From d4cf45e3f1bc366b6888594711966c1e679f551f Mon Sep 17 00:00:00 2001 From: Krzysztof Foltman Date: Tue, 15 Mar 2005 15:40:52 +0000 Subject: [PATCH] - WM_COPY (and WM_CUT) can now put both Unicode and RTF format (thanks to Phil Krylov's RTF generator code). - New message implemented - WM_PASTE. - RTF reader: rtfPlain implemented (kind of). - RTF writer: rewritten main loop (the old one crashed in some circumstances when SFF_SELECTION was used). --- dlls/riched20/editor.c | 121 ++++++++++++++++++++++++++++++++++++++--- dlls/riched20/writer.c | 67 ++++++++++++----------- 2 files changed, 149 insertions(+), 39 deletions(-) diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index f40819a4122..5980fad9066 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -107,12 +107,12 @@ - EM_UNDO + WM_CHAR + WM_CLEAR - - WM_COPY (lame implementation, no RTF support) - - WM_CUT (lame implementation, no RTF support) + + WM_COPY + + WM_CUT + WM_GETDLGCODE (the current implementation is incomplete) + WM_GETTEXT (ANSI&Unicode) + WM_GETTEXTLENGTH (ANSI version sucks) - - WM_PASTE + + WM_PASTE - WM_SETFONT + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode - WM_STYLECHANGING @@ -270,7 +270,8 @@ static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM if (nDataSizertfMinor) { + case rtfPlain: + FIXME("rtfPlain: how plain should it be ?\n"); + fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR; + fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; + break; case rtfBold: fmt.dwMask = CFM_BOLD; fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; @@ -449,7 +455,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre editor->nUndoMode = nUndoMode; pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL); - FIXME("from %d to %d\n", from, to); + TRACE("from %d to %d\n", from, to); if (pUI && from < to) { pUI->nStart = from; @@ -530,6 +536,70 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { return ed; } +typedef struct tagME_GlobalDestStruct +{ + HGLOBAL hData; + int nLength; +} ME_GlobalDestStruct; + +static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int nMaxSize; + BYTE *pDest; + + nMaxSize = GlobalSize(pData->hData); + if (pData->nLength+cb+1 >= cb) + { + /* round up to 2^17 */ + int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000; + pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0); + } + pDest = (BYTE *)GlobalLock(pData->hData); + memcpy(pDest + pData->nLength, lpBuff, cb); + pData->nLength += cb; + pDest[pData->nLength] = '\0'; + GlobalUnlock(pData->hData); + *pcb = cb; + + return 0; +} + +static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int i; + WORD *pSrc, *pDest; + + cb = cb >> 1; + pDest = (WORD *)lpBuff; + pSrc = (WORD *)GlobalLock(pData->hData); + for (i = 0; inLength+i]; i++) { + pDest[i] = pSrc[pData->nLength+i]; + } + pData->nLength += i; + *pcb = 2*i; + GlobalUnlock(pData->hData); + return 0; +} + +static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) +{ + ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; + int i; + BYTE *pSrc, *pDest; + + pDest = lpBuff; + pSrc = (BYTE *)GlobalLock(pData->hData); + for (i = 0; inLength+i]; i++) { + pDest[i] = pSrc[pData->nLength+i]; + } + pData->nLength += i; + *pcb = i; + GlobalUnlock(pData->hData); + return 0; +} + void ME_DestroyEditor(ME_TextEditor *editor) { ME_DisplayItem *pFirst = editor->pBuffer->pFirst; @@ -618,7 +688,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_SETWORDBREAKPROC) UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX) UNSUPPORTED_MSG(WM_SETFONT) - UNSUPPORTED_MSG(WM_PASTE) UNSUPPORTED_MSG(WM_STYLECHANGING) UNSUPPORTED_MSG(WM_STYLECHANGED) /* UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */ @@ -805,12 +874,40 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP ME_UpdateRepaint(editor); return 0; } + case WM_PASTE: + { + DWORD dwFormat = 0; + EDITSTREAM es; + ME_GlobalDestStruct gds; + UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format"); + UINT cf = 0; + + if (!OpenClipboard(hWnd)) + return 0; + if (IsClipboardFormatAvailable(nRTFFormat)) + cf = nRTFFormat, dwFormat = SF_RTF; + else if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE; + else + return 0; + + gds.hData = GetClipboardData(cf); + gds.nLength = 0; + es.dwCookie = (DWORD)&gds; + es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode; + SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es); + + CloseClipboard(); + return 0; + } case WM_CUT: case WM_COPY: { int from, to, pars; WCHAR *data; HANDLE hData; + EDITSTREAM es; + ME_GlobalDestStruct gds; if (!OpenClipboard(hWnd)) return 0; @@ -822,7 +919,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP data = (WCHAR *)GlobalLock(hData); ME_GetTextW(editor, data, from, to-from, TRUE); GlobalUnlock(hData); - SetClipboardData(CF_UNICODETEXT, hData); + + gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0); + gds.nLength = 0; + es.dwCookie = (DWORD)&gds; + es.pfnCallback = ME_AppendToHGLOBAL; + SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es); + GlobalReAlloc(gds.hData, gds.nLength+1, 0); + + SetClipboardData(CF_UNICODETEXT, hData); + SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData); + CloseClipboard(); if (msg == WM_CUT) { diff --git a/dlls/riched20/writer.c b/dlls/riched20/writer.c index 0881992aa9e..4a972c63ec2 100644 --- a/dlls/riched20/writer.c +++ b/dlls/riched20/writer.c @@ -107,7 +107,7 @@ ME_StreamOutPrint(ME_TextEditor *editor, char *format, ...) static BOOL ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat) { - char *cCharSet; + char *cCharSet = NULL; UINT nCodePage; LANGID language; BOOL success; @@ -171,10 +171,9 @@ ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat) static BOOL -ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, LONG to) +ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun) { ME_DisplayItem *item = pFirstRun; - ME_DisplayItem *pLastRun = ME_FindItemAtOffset(editor, diRun, to, NULL); ME_FontTableItem *table = editor->pStream->fonttbl; int i; @@ -485,15 +484,15 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars) static BOOL ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat) { - int nTo; - ME_DisplayItem *para = ME_FindItemAtOffset(editor, diParagraph, nStart, NULL); - ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); - ME_DisplayItem *last_item = ME_FindItemAtOffset(editor, diRun, nStart + nChars, &nTo); - + ME_DisplayItem *p, *pEnd; + int nOffset, nEndLen; + ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset); + ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen); + if (!ME_StreamOutRTFHeader(editor, dwFormat)) return FALSE; - if (!ME_StreamOutRTFFontAndColorTbl(editor, item, nStart + nChars)) + if (!ME_StreamOutRTFFontAndColorTbl(editor, p, pEnd)) return FALSE; /* TODO: stylesheet table */ @@ -510,48 +509,51 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat) /* TODO: section formatting properties */ - while (para) { - ME_DisplayItem *p; - int nLen; - - if (!ME_StreamOutRTFParaProps(editor, para)) - return FALSE; - - if (!item) { - item = ME_FindItemFwd(para, diRun); - nStart = 0; - } - for (p = item; p && p != para->member.para.next_para; p = p->next) { - TRACE("type %d\n", p->type); - if (p->type == diRun) { + if (!ME_StreamOutRTFParaProps(editor, ME_GetParagraph(p))) + return FALSE; + + while(1) + { + switch(p->type) + { + case diParagraph: + if (!ME_StreamOutRTFParaProps(editor, p)) + return FALSE; + break; + case diRun: + if (p == pEnd && !nEndLen) + break; TRACE("flags %xh\n", p->member.run.nFlags); + /* TODO: emit embedded objects */ + if (p->member.run.nFlags & MERF_GRAPHICS) + FIXME("embedded objects are not handled\n"); if (p->member.run.nFlags & MERF_ENDPARA) { if (!ME_StreamOutPrint(editor, "\r\n\\par")) return FALSE; nChars--; } else { + int nEnd; + if (!ME_StreamOutPrint(editor, "{")) return FALSE; TRACE("style %p\n", p->member.run.style); if (!ME_StreamOutRTFCharProps(editor, &p->member.run.style->fmt)) return FALSE; - /* TODO: emit embedded objects as well as text */ - nLen = ME_StrLen(p->member.run.strText) - nStart; - if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nStart, - (p == last_item ? nTo - nStart : nLen))) + nEnd = (p == pEnd) ? nEndLen : ME_StrLen(p->member.run.strText); + if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nOffset, nEnd - nOffset)) return FALSE; + nOffset = 0; if (!ME_StreamOutPrint(editor, "}")) return FALSE; } - } - if (p == last_item) break; + default: /* we missed the last item */ + assert(0); } - para = para->member.para.next_para; - item = NULL; - if (p == last_item) + if (p == pEnd) break; + p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); } if (!ME_StreamOutPrint(editor, "}")) return FALSE; @@ -562,6 +564,7 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat) static BOOL ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat) { + /* FIXME: use ME_RunOfsFromCharOfs */ ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); int nLen; UINT nCodePage = CP_ACP;