From 174476f7726be1a24e58290ace97347c9dc89959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Wed, 2 Nov 2005 20:03:07 +0000 Subject: [PATCH] Sync to Wine-0_9: Phil Krylov - Fixed encoding of non-ASCII chars. Krzysztof Foltman - Bugfix in EM_GETTEXTEX - Additional traces helpful in diagnosing similar (text retrieval-related) bugs. - Fix unnecessary (and harmful) repeated statement. - Removed buffer overrun error (incrementing output pointer one time too much in non-CRLF mode) making KeyNote fail to install. - Style trace information is written to different debug channel (it's not very useful anymore, reference counting looks correct for now). - The document dump contains the character position of the end-of-text mark. - The previous implementation was a workaround for off-by-one bug in ME_RunOfsFromCharOfs, this one relies on correct behavior of that function introduced by the previous patch. - Send verbose info to different debug channels (richedit_check for output from offset checker, richedit_lists for the document list dumps). - Fix a bug in 1.0 emulation mode in EM_LINELENGTH (which broke PTE installer). - Fixed EOL detection in ME_RunOfsFromCharOfs in 1.0 emulation mode (necessary for a non-workaround version of EM_POSFROMCHAR). - Fix 1.0 emulation mode in ME_GetTextW. - Remove another potential sources of infinite loops caused by EOF in the middle of the font and color tables. - Closing brace on text level is treated as EOF (effectively protecting the control from trash after the end of RTF). - Removed misleading comment about incomplete buffers (I was definitely wrong). - Implemented EM_GETFIRSTVISIBLELINE and EM_POSFROMCHAR (basic suboptimal implementation, can be optimized to skip whole paragraphs later if it's useful at all). - Fixed another case of misunderstanding MSDN wrt StreamInProc, causing license text to be truncated in Picasa installer (as well as some other programs, especially those that display long texts with NSIS). svn path=/trunk/; revision=18955 --- reactos/lib/riched20/editor.c | 100 ++++++++++++++++++++++++++++------ reactos/lib/riched20/list.c | 4 +- reactos/lib/riched20/reader.c | 25 ++++++--- reactos/lib/riched20/run.c | 18 ++++-- reactos/lib/riched20/style.c | 13 +++-- reactos/lib/riched20/writer.c | 2 +- 6 files changed, 123 insertions(+), 39 deletions(-) diff --git a/reactos/lib/riched20/editor.c b/reactos/lib/riched20/editor.c index d0667201202..07a1ee03579 100644 --- a/reactos/lib/riched20/editor.c +++ b/reactos/lib/riched20/editor.c @@ -43,7 +43,7 @@ - EM_GETCHARFORMAT (partly done) - EM_GETEDITSTYLE + EM_GETEVENTMASK - - EM_GETFIRSTVISIBLELINE + + EM_GETFIRSTVISIBLELINE (can be optimized if needed) - EM_GETIMECOLOR 1.0asian - EM_GETIMECOMPMODE 2.0 - EM_GETIMEOPTIONS 1.0asian @@ -81,7 +81,7 @@ + EM_LINELENGTH + EM_LINESCROLL - EM_PASTESPECIAL - - EM_POSFROMCHARS + + EM_POSFROMCHAR + EM_REDO 2.0 - EM_REQUESTRESIZE + EM_REPLACESEL (proper style?) ANSI&Unicode @@ -290,7 +290,7 @@ static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStrea } ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style); - if (stream->dwSize < STREAMIN_BUFFER_SIZE) + if (stream->dwSize == 0) break; stream->dwSize = 0; } while(1); @@ -483,7 +483,12 @@ static void ME_RTFReadHook(RTF_Info *info) { { ME_Style *s; RTFFlushOutputBuffer(info); + if (info->stackTop<=1) { + info->rtfClass = rtfEOF; + return; + } info->stackTop--; + assert(info->stackTop >= 0); if (info->styleChanged) { /* FIXME too slow ? how come ? */ @@ -1111,7 +1116,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_GETAUTOURLDETECT) UNSUPPORTED_MSG(EM_GETBIDIOPTIONS) UNSUPPORTED_MSG(EM_GETEDITSTYLE) - UNSUPPORTED_MSG(EM_GETFIRSTVISIBLELINE) UNSUPPORTED_MSG(EM_GETIMECOMPMODE) /* UNSUPPORTED_MSG(EM_GETIMESTATUS) missing in Wine headers */ UNSUPPORTED_MSG(EM_GETLANGOPTIONS) @@ -1130,7 +1134,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_HIDESELECTION) UNSUPPORTED_MSG(EM_LIMITTEXT) /* also known as EM_SETLIMITTEXT */ UNSUPPORTED_MSG(EM_PASTESPECIAL) -/* UNSUPPORTED_MSG(EM_POSFROMCHARS) missing in Wine headers */ UNSUPPORTED_MSG(EM_REQUESTRESIZE) UNSUPPORTED_MSG(EM_SCROLL) UNSUPPORTED_MSG(EM_SCROLLCARET) @@ -1350,6 +1353,30 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP case EM_GETPARAFORMAT: ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); return 0; + case EM_GETFIRSTVISIBLELINE: + { + ME_DisplayItem *p = editor->pBuffer->pFirst; + int y = editor->nScrollPosY; + int ypara = 0; + int count = 0; + int ystart, yend; + while(p) { + p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd); + if (p->type == diTextEnd) + break; + if (p->type == diParagraph) { + ypara = p->member.para.nYPos; + continue; + } + ystart = ypara + p->member.row.nYPos; + yend = ystart + p->member.row.nHeight; + if (y < yend) { + break; + } + count++; + } + return count; + } case EM_LINESCROLL: { int nPos = editor->nScrollPosY, nEnd= editor->nTotalLength - editor->sizeWindow.cy; @@ -1538,16 +1565,19 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP } else { - LPWSTR buffer = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(WCHAR)); - DWORD buflen = ex->cb; - LRESULT rc; - DWORD flags = 0; + /* potentially each char may be a CR, why calculate the exact value with O(N) when + we can just take a bigger buffer? :) */ + int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1; + LPWSTR buffer = HeapAlloc(GetProcessHeap(), 0, (crlfmul*nCount + 1) * sizeof(WCHAR)); + DWORD buflen = ex->cb; + LRESULT rc; + DWORD flags = 0; - buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF); - rc = WideCharToMultiByte(ex->codepage, flags, buffer, buflen, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar); + buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF); + rc = WideCharToMultiByte(ex->codepage, flags, buffer, buflen, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar); - HeapFree(GetProcessHeap(),0,buffer); - return rc; + HeapFree(GetProcessHeap(),0,buffer); + return rc; } } case EM_GETSELTEXT: @@ -1563,6 +1593,9 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP case EM_GETTEXTRANGE: { TEXTRANGEW *rng = (TEXTRANGEW *)lParam; + TRACE("EM_GETTEXTRANGE min=%ld max=%ld unicode=%d emul1.0=%d length=%d\n", + rng->chrg.cpMin, rng->chrg.cpMax, IsWindowUnicode(hWnd), + editor->bEmulateVersion10, ME_GetTextLength(editor)); if (IsWindowUnicode(hWnd)) return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10); else @@ -1639,7 +1672,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP if (item_end) nNextLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item_end, diRun), 0); else - nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs-1; + nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs + - (editor->bEmulateVersion10?2:1); nChars = nNextLineOfs - nThisLineOfs; TRACE("EM_LINELENGTH(%d)==%d\n",wParam, nChars); return nChars; @@ -1684,6 +1718,33 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return ME_SetZoom(editor, wParam, lParam); case EM_CHARFROMPOS: return ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y); + case EM_POSFROMCHAR: + { + ME_DisplayItem *pRun; + int nCharOfs, nOffset, nLength; + POINTL pt = {0,0}; + + nCharOfs = wParam; + /* detect which API version we're dealing with */ + if (wParam >= 0x40000) + nCharOfs = lParam; + nLength = ME_GetTextLength(editor); + + if (nCharOfs < nLength) { + ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset); + assert(pRun->type == diRun); + pt.y = pRun->member.run.pt.y; + pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset); + pt.y += ME_GetParagraph(pRun)->member.para.nYPos; + } else { + pt.x = 0; + pt.y = editor->pBuffer->pLast->member.para.nYPos; + } + if (wParam >= 0x40000) { + *(POINTL *)wParam = pt; + } + return MAKELONG( pt.x, pt.y ); + } case WM_CREATE: ME_CommitUndo(editor); ME_WrapMarkedParagraphs(editor); @@ -1982,12 +2043,12 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in { ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); int nWritten = 0; + WCHAR *pStart = buffer; if (!item) { *buffer = L'\0'; return 0; } - assert(item); if (nStart) { @@ -2012,13 +2073,16 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in if (item->member.run.nFlags & MERF_ENDPARA) { - *buffer++ = '\r'; + *buffer = '\r'; if (bCRLF) { - *buffer = '\n'; + *(++buffer) = '\n'; nWritten++; } assert(nLen == 1); + /* our end paragraph consists of 2 characters now */ + if (editor->bEmulateVersion10) + nChars--; } else CopyMemory(buffer, item->member.run.strText->szData, sizeof(WCHAR)*nLen); @@ -2028,12 +2092,14 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in if (!nChars) { + TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart); *buffer = L'\0'; return nWritten; } item = ME_FindItemFwd(item, diRun); } *buffer = L'\0'; + TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart); return nWritten; } diff --git a/reactos/lib/riched20/list.c b/reactos/lib/riched20/list.c index e4e1f403862..857fcf3edfa 100644 --- a/reactos/lib/riched20/list.c +++ b/reactos/lib/riched20/list.c @@ -21,7 +21,7 @@ #include "editor.h" -WINE_DEFAULT_DEBUG_CHANNEL(riched20); +WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists); void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) { @@ -181,7 +181,7 @@ void ME_DumpDocument(ME_TextBuffer *buffer) pItem->member.run.nCharOfs); break; case diTextEnd: - TRACE("\nEnd\n"); + TRACE("\nEnd(ofs=%d)\n", pItem->member.para.nCharOfs); break; default: break; diff --git a/reactos/lib/riched20/reader.c b/reactos/lib/riched20/reader.c index 5c104e1c90c..c16911552b1 100644 --- a/reactos/lib/riched20/reader.c +++ b/reactos/lib/riched20/reader.c @@ -127,13 +127,6 @@ int _RTFGetChar(RTF_Info *info) TRACE("\n"); - /* Doc says, that if the last buffer wasn't full, it's EOF. - Actually, that's not true. */ -/* - if (stream->dwSize > 0 && stream->dwSize == stream->dwUsed - && stream->dwSize < sizeof(stream->buffer)) - return EOF; -*/ if (stream->dwSize <= stream->dwUsed) { ME_StreamInFill(stream); @@ -455,6 +448,10 @@ int RTFGetToken(RTF_Info *info) RTFFuncPtr p; TRACE("\n"); + /* don't try to return anything once EOF is reached */ + if (info->rtfClass == rtfEOF) { + return rtfEOF; + } for (;;) { @@ -885,6 +882,8 @@ static void ReadFontTbl(RTF_Info *info) for (;;) { RTFGetToken (info); + if (info->rtfClass == rtfEOF) + break; if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; if (old < 0) /* first entry - determine tbl type */ @@ -901,6 +900,8 @@ static void ReadFontTbl(RTF_Info *info) if (!RTFCheckCM (info, rtfGroup, rtfBeginGroup)) RTFPanic (info, "%s: missing \"{\"", fn); RTFGetToken (info); /* yes, skip to next token */ + if (info->rtfClass == rtfEOF) + break; } fp = New (RTFFont); if (fp == NULL) @@ -1002,12 +1003,18 @@ static void ReadFontTbl(RTF_Info *info) fn,info->rtfTextBuf); } RTFGetToken (info); + if (info->rtfClass == rtfEOF) + break; } + if (info->rtfClass == rtfEOF) + break; if (old == 0) /* need to see "}" here */ { RTFGetToken (info); if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) RTFPanic (info, "%s: missing \"}\"", fn); + if (info->rtfClass == rtfEOF) + break; } /* Apply the real properties of the default font */ @@ -1055,6 +1062,8 @@ static void ReadColorTbl(RTF_Info *info) for (;;) { RTFGetToken (info); + if (info->rtfClass == rtfEOF) + break; if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; cp = New (RTFColor); @@ -1074,6 +1083,8 @@ static void ReadColorTbl(RTF_Info *info) } RTFGetToken (info); } + if (info->rtfClass == rtfEOF) + break; if (!RTFCheckCM (info, rtfText, ';')) RTFPanic (info,"%s: malformed entry", fn); } diff --git a/reactos/lib/riched20/run.c b/reactos/lib/riched20/run.c index eab74012fe1..568472c62f2 100644 --- a/reactos/lib/riched20/run.c +++ b/reactos/lib/riched20/run.c @@ -23,6 +23,8 @@ #include "editor.h" WINE_DEFAULT_DEBUG_CHANNEL(richedit); +WINE_DECLARE_DEBUG_CHANNEL(richedit_check); +WINE_DECLARE_DEBUG_CHANNEL(richedit_lists); int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2) { @@ -72,26 +74,26 @@ void ME_CheckCharOffsets(ME_TextEditor *editor) { ME_DisplayItem *p = editor->pBuffer->pFirst; int ofs = 0, ofsp = 0; - if(TRACE_ON(richedit)) + if(TRACE_ON(richedit_lists)) { - TRACE("---\n"); + TRACE_(richedit_lists)("---\n"); ME_DumpDocument(editor->pBuffer); } do { p = ME_FindItemFwd(p, diRunOrParagraphOrEnd); switch(p->type) { case diTextEnd: - TRACE("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); + TRACE_(richedit_check)("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); assert(ofsp+ofs == p->member.para.nCharOfs); return; case diParagraph: - TRACE("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); + TRACE_(richedit_check)("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs); assert(ofsp+ofs == p->member.para.nCharOfs); ofsp = p->member.para.nCharOfs; ofs = 0; break; case diRun: - TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n", + TRACE_(richedit_check)("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n", p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs, p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData), p->member.run.nFlags, @@ -143,6 +145,7 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ** if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs) { + int eollen = 1; *ppRun = ME_FindItemFwd(pPara, diRun); assert(*ppRun); while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA)) @@ -157,7 +160,10 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem ** } *ppRun = pNext; } - if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) { + /* the handling of bEmulateVersion10 may be a source of many bugs, I'm afraid */ + eollen = (editor->bEmulateVersion10 ? 2 : 1); + if (nCharOfs >= nParaOfs + (*ppRun)->member.run.nCharOfs && + nCharOfs < nParaOfs + (*ppRun)->member.run.nCharOfs + eollen) { *pOfs = 0; return; } diff --git a/reactos/lib/riched20/style.c b/reactos/lib/riched20/style.c index 1d06154adfc..11fd56b02c8 100644 --- a/reactos/lib/riched20/style.c +++ b/reactos/lib/riched20/style.c @@ -21,6 +21,7 @@ #include "editor.h" WINE_DEFAULT_DEBUG_CHANNEL(richedit); +WINE_DECLARE_DEBUG_CHANNEL(richedit_style); static int all_refs = 0; @@ -197,7 +198,7 @@ void ME_DumpStyle(ME_Style *s) { char buf[2048]; ME_DumpStyleToBuf(&s->fmt, buf); - TRACE("%s\n", buf); + TRACE_(richedit_style)("%s\n", buf); } void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]) @@ -321,7 +322,7 @@ HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s) if (i < HFONT_CACHE_SIZE) /* found */ { item = &editor->pFontCache[i]; - TRACE("font reused %d\n", i); + TRACE_(richedit_style)("font reused %d\n", i); s->hFont = item->hFont; item->nRefs++; @@ -332,13 +333,13 @@ HFONT ME_SelectStyleFont(ME_TextEditor *editor, HDC hDC, ME_Style *s) assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/ if (item->hFont) { - TRACE("font deleted %d\n", nEmpty); + TRACE_(richedit_style)("font deleted %d\n", nEmpty); DeleteObject(item->hFont); item->hFont = NULL; } s->hFont = CreateFontIndirectW(&lf); assert(s->hFont); - TRACE("font created %d\n", nEmpty); + TRACE_(richedit_style)("font created %d\n", nEmpty); item->hFont = s->hFont; item->nRefs = 1; memcpy(&item->lfSpecs, &lf, sizeof(LOGFONTW)); @@ -391,9 +392,9 @@ void ME_ReleaseStyle(ME_Style *s) s->nRefs--; all_refs--; if (s->nRefs==0) - TRACE("destroy style %p, total refs=%d\n", s, all_refs); + TRACE_(richedit_style)("destroy style %p, total refs=%d\n", s, all_refs); else - TRACE("release style %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs); + TRACE_(richedit_style)("release style %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs); if (!all_refs) TRACE("all style references freed (good!)\n"); assert(s->nRefs>=0); if (!s->nRefs) diff --git a/reactos/lib/riched20/writer.c b/reactos/lib/riched20/writer.c index 629cce2e439..c8d1226c894 100644 --- a/reactos/lib/riched20/writer.c +++ b/reactos/lib/riched20/writer.c @@ -616,7 +616,7 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars) buffer[pos++] = *letter; } else { for (i = 0; i < nBytes; i++) - pos += sprintf(buffer + pos, "\\'%02x", letter[i]); + pos += sprintf(buffer + pos, "\\'%02x", (BYTE)letter[i]); } text++; nChars--;