From 4e74b68be8b1d8701ada946d6a5615d04a2e67b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?G=C3=A9=20van=20Geldorp?= Date: Mon, 5 Sep 2005 22:07:52 +0000 Subject: [PATCH] Sync to Wine-20050830: Phil Krylov - Added support for backward search to RichEdit EM_FINDTEXT[AW], EM_FINDTEXTEX[AW] message handler. - Fixed EM_SETEVENTMASK RichEdit message handler to return old event mask. - Added handling of deff RTF control word. - Added common keyboard shortcuts for Select All, Undo, Redo, Cut, Copy and Paste to RichEdit. - Automatically set default font after parsing a font table in RichEdit RTF reader. - Fixed EM_EXLINEFROMCHAR to work for last row of a paragraph. - Fixed UTF-8 RTF parsing. - Fixed a bug in EM_STREAMOUT RichEdit message handler which truncated some streamed text. - Generate ending \par in RTF output of RichEdit when streaming out a whole document. - Fixed a RichEdit RTF reader bug which resulted in loss of text. Eliminated unneeded recursion in ME_InsertTextFromCursor(). - Implemented EM_CHARFROMPOS RichEdit message. - Added EM_SETRECT, EM_SETRECTNP, and WM_SETREDRAW message handling. Added support for GT_SELECTION flag in EM_GETTEXTEX handler. Mike McCormack - gcc 4.0 warning fixes for Interlocked* functions. svn path=/trunk/; revision=17681 --- reactos/lib/riched20/caret.c | 155 +++++++------ reactos/lib/riched20/context.c | 2 +- reactos/lib/riched20/editor.c | 362 ++++++++++++++++++++++-------- reactos/lib/riched20/editor.h | 1 + reactos/lib/riched20/editstr.h | 2 + reactos/lib/riched20/paint.c | 40 ++-- reactos/lib/riched20/reader.c | 42 +++- reactos/lib/riched20/richole.c | 2 +- reactos/lib/riched20/row.c | 4 + reactos/lib/riched20/rtf.h | 2 + reactos/lib/riched20/writer.c | 9 +- reactos/w32api/include/richedit.h | 1 + 12 files changed, 442 insertions(+), 180 deletions(-) diff --git a/reactos/lib/riched20/caret.c b/reactos/lib/riched20/caret.c index f1c87db24d0..9c30e5c9a10 100644 --- a/reactos/lib/riched20/caret.c +++ b/reactos/lib/riched20/caret.c @@ -325,6 +325,28 @@ void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor) ME_SendSelChange(editor); } + +static void +ME_InternalInsertTextFromCursor(ME_TextEditor *editor, int nCursor, + const WCHAR *str, int len, ME_Style *style, + int flags) +{ + ME_DisplayItem *pNewRun = NULL; + ME_Cursor *p = &editor->pCursors[nCursor]; + + editor->bCaretAtEnd = FALSE; + + assert(p->pRun->type == diRun); + + ME_AddRefStyle(style); + + pNewRun = ME_MakeRun(style, ME_MakeStringN(str, len), flags); /* addrefs style */ + ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun); + ME_DestroyDisplayItem(pNewRun); + ME_ReleaseStyle(style); +} + + void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, const WCHAR *str, int len, ME_Style *style) { @@ -332,10 +354,7 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, ME_Cursor *p = NULL; assert(style); - editor->bCaretAtEnd = FALSE; - ME_AddRefStyle(style); - /* FIXME really HERE ? */ if (ME_IsSelection(editor)) ME_DeleteSelection(editor); @@ -343,75 +362,61 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, assert(nCursor>=0 && nCursornCursors); if (len == -1) len = lstrlenW(str); - pos = str; - /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */ - while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t') - pos++; - if (pos-str < len && *pos == '\t') { /* handle tabs */ - ME_DisplayItem *pNewRun = NULL; - WCHAR tab = '\t'; + while (len) + { + pos = str; + /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */ + while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t') + pos++; + if (pos-str < len && *pos == '\t') { /* handle tabs */ + WCHAR tab = '\t'; - if (pos!=str) - ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style); + if (pos!=str) + ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); - p = &editor->pCursors[nCursor]; - assert(style); - assert(p->pRun->type == diRun); - pNewRun = ME_MakeRun(style, ME_MakeStringN(&tab, 1), MERF_TAB); /* addrefs style */ - ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun); - ME_DestroyDisplayItem(pNewRun); - ME_ReleaseStyle(style); - - pos++; - if(pos-str < len) { - ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style); + ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB); + + pos++; + if(pos-str <= len) { + len -= pos - str; + str = pos; + continue; + } } - return; - } - if (pos-str < len) { /* handle EOLs */ - ME_DisplayItem *tp, *end_run; - ME_Paragraph *para; - ME_Style *tmp_style; - if (pos!=str) - ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style); - p = &editor->pCursors[nCursor]; - tp = ME_FindItemBack(p->pRun, diParagraph); - para = &tp->member.para; - assert(tp); - if (p->nOffset) { - ME_SplitRunSimple(editor, p->pRun, p->nOffset); + if (pos-str < len) { /* handle EOLs */ + ME_DisplayItem *tp, *end_run; + ME_Paragraph *para; + ME_Style *tmp_style; + if (pos!=str) + ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); p = &editor->pCursors[nCursor]; + tp = ME_FindItemBack(p->pRun, diParagraph); + para = &tp->member.para; + assert(tp); + if (p->nOffset) { + ME_SplitRunSimple(editor, p->pRun, p->nOffset); + p = &editor->pCursors[nCursor]; + } + tmp_style = ME_GetInsertStyle(editor, nCursor); + /* ME_SplitParagraph increases style refcount */ + tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style); + p->pRun = ME_FindItemFwd(tp, diRun); + end_run = ME_FindItemBack(tp, diRun); + ME_ReleaseStyle(end_run->member.run.style); + end_run->member.run.style = tmp_style; + p->nOffset = 0; + if(pos-str < len && *pos =='\r') + pos++; + if(pos-str < len && *pos =='\n') + pos++; + if(pos-str <= len) { + len -= pos - str; + str = pos; + continue; + } } - tmp_style = ME_GetInsertStyle(editor, nCursor); - /* ME_SplitParagraph increases style refcount */ - tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style); - p->pRun = ME_FindItemFwd(tp, diRun); - end_run = ME_FindItemBack(tp, diRun); - ME_ReleaseStyle(end_run->member.run.style); - end_run->member.run.style = tmp_style; - p->nOffset = 0; - if(pos-str < len && *pos =='\r') - pos++; - if(pos-str < len && *pos =='\n') - pos++; - if(pos-str < len) { - ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style); - } - ME_ReleaseStyle(style); - return; - } - p = &editor->pCursors[nCursor]; - if (style) { - ME_DisplayItem *pNewRun = NULL; - - assert(p->pRun->type == diRun); - pNewRun = ME_MakeRun(style, ME_MakeStringN(str, len), 0); /* addrefs style */ - ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun); - ME_DestroyDisplayItem(pNewRun); - ME_ReleaseStyle(style); - return; - } else { - assert(0); + ME_InternalInsertTextFromCursor(editor, nCursor, str, len, style, 0); + len = 0; } } @@ -584,6 +589,22 @@ int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL return 0; } + +int +ME_CharFromPos(ME_TextEditor *editor, int x, int y) +{ + ME_Cursor cursor; + RECT rc; + + GetClientRect(editor->hWnd, &rc); + if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom) + return -1; + ME_FindPixelPos(editor, x, y, &cursor, NULL); + return (ME_GetParagraph(cursor.pRun)->member.para.nCharOfs + + cursor.pRun->member.run.nCharOfs + cursor.nOffset); +} + + void ME_LButtonDown(ME_TextEditor *editor, int x, int y) { ME_Cursor tmp_cursor; diff --git a/reactos/lib/riched20/context.c b/reactos/lib/riched20/context.c index 62b02590608..0c851e6fabc 100644 --- a/reactos/lib/riched20/context.c +++ b/reactos/lib/riched20/context.c @@ -28,7 +28,7 @@ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC) c->pt.x = 0; c->pt.y = 0; c->hbrMargin = CreateSolidBrush(RGB(224,224,224)); - GetClientRect(editor->hWnd, &c->rcView); + c->rcView = editor->rcFormat; } void ME_DestroyContext(ME_Context *c) diff --git a/reactos/lib/riched20/editor.c b/reactos/lib/riched20/editor.c index 8339b12e9c4..a074d5545de 100644 --- a/reactos/lib/riched20/editor.c +++ b/reactos/lib/riched20/editor.c @@ -26,7 +26,7 @@ + EM_CANPASTE + EM_CANREDO 2.0 + EM_CANUNDO - - EM_CHARFROMPOS + + EM_CHARFROMPOS - EM_DISPLAYBAND + EM_EMPTYUNDOBUFFER + EM_EXGETSEL @@ -58,7 +58,7 @@ + EM_GETPARAFORMAT - EM_GETPASSWORDCHAR 2.0 - EM_GETPUNCTUATION 1.0asian - - EM_GETRECT + + EM_GETRECT - EM_GETREDONAME 2.0 + EM_GETSEL + EM_GETSELTEXT (ANSI&Unicode) @@ -106,8 +106,8 @@ - EM_SETPASSWORDCHAR 2.0 - EM_SETPUNCTUATION 1.0asian + EM_SETREADONLY no beep on modification attempt - - EM_SETRECT - - EM_SETRECTNP (EM_SETRECT without repainting) - not supported in RICHEDIT + + EM_SETRECT + + EM_SETRECTNP (EM_SETRECT without repainting) + EM_SETSEL - EM_SETSCROLLPOS 3.0 - EM_SETTABSTOPS 3.0 @@ -393,6 +393,7 @@ static void ME_RTFCharAttrHook(RTF_Info *info) style2 = ME_ApplyStyle(info->style, &fmt); ME_ReleaseStyle(info->style); info->style = style2; + info->styleChanged = TRUE; } } @@ -476,18 +477,22 @@ static void ME_RTFReadHook(RTF_Info *info) { info->stack[info->stackTop].unicodeLength = info->unicodeLength; } info->stackTop++; + info->styleChanged = FALSE; break; case rtfEndGroup: { ME_Style *s; RTFFlushOutputBuffer(info); info->stackTop--; - /* FIXME too slow ? how come ? */ - s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt); - ME_ReleaseStyle(info->style); - info->style = s; - info->codePage = info->stack[info->stackTop].codePage; - info->unicodeLength = info->stack[info->stackTop].unicodeLength; + if (info->styleChanged) + { + /* FIXME too slow ? how come ? */ + s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt); + ME_ReleaseStyle(info->style); + info->style = s; + info->codePage = info->stack[info->stackTop].codePage; + info->unicodeLength = info->stack[info->stackTop].unicodeLength; + } break; } } @@ -613,8 +618,11 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre ME_CommitUndo(editor); ME_ReleaseStyle(style); editor->nEventMask = nEventMask; - InvalidateRect(editor->hWnd, NULL, TRUE); - ME_UpdateRepaint(editor); + if (editor->bRedraw) + { + InvalidateRect(editor->hWnd, NULL, TRUE); + ME_UpdateRepaint(editor); + } if (!(format & SFF_SELECTION)) { ME_ClearTempStyle(editor); } @@ -658,62 +666,130 @@ ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int static int ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, WCHAR *text, CHARRANGE *chrgText) { - int nStart = chrg->cpMin; + int nStart, nEnd; int nLen = lstrlenW(text); - ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + int nMin, nMax; + ME_DisplayItem *item; ME_DisplayItem *para; + + TRACE("flags==0x%08lx, chrg->cpMin==%ld, chrg->cpMax==%ld text==%s\n", + flags, chrg->cpMin, chrg->cpMax, debugstr_w(text)); - if (!item) - return -1; + if (!(flags & FR_MATCHCASE)) + FIXME("Case-insensitive search not implemented\n"); + if (flags & ~(FR_DOWN | FR_MATCHCASE)) + FIXME("Flags 0x%08lx not implemented\n", flags & ~(FR_DOWN | FR_MATCHCASE)); + if (chrg->cpMax == -1) + { + nMin = chrg->cpMin; + nMax = ME_GetTextLength(editor); + } + else + { + nMin = min(chrg->cpMin, chrg->cpMax); + nMax = max(chrg->cpMin, chrg->cpMax); + } + if (!nLen) { if (chrgText) - chrgText->cpMin = chrgText->cpMax = chrg->cpMin; - return chrg->cpMin; + chrgText->cpMin = chrgText->cpMax = ((flags & FR_DOWN) ? nMin : nMax); + return chrgText->cpMin; } - if (!(flags & FR_DOWN)) - FIXME("Backward search not implemented\n"); - if (!(flags & FR_MATCHCASE)) - FIXME("Case-insensitive search not implemented\n"); - if (flags & ~(FR_DOWN | FR_MATCHCASE)) - FIXME("Flags 0x%08lx not implemented\n", flags & ~(FR_DOWN | FR_MATCHCASE)); - - para = ME_GetParagraph(item); - while (item && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen < chrg->cpMax) + if (flags & FR_DOWN) /* Forward search */ { - ME_DisplayItem *pCurItem = item; - int nCurStart = nStart; - int nMatched = 0; - - while (pCurItem->member.run.strText->szData[nCurStart + nMatched] == text[nMatched]) + nStart = nMin; + item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + if (!item) + return -1; + + para = ME_GetParagraph(item); + while (item + && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen < nMax) { - nMatched++; - if (nMatched == nLen) + ME_DisplayItem *pCurItem = item; + int nCurStart = nStart; + int nMatched = 0; + + while (pCurItem && pCurItem->member.run.strText->szData[nCurStart + nMatched] == text[nMatched]) { - nStart += para->member.para.nCharOfs + item->member.run.nCharOfs; - if (chrgText) + nMatched++; + if (nMatched == nLen) + { + nStart += para->member.para.nCharOfs + item->member.run.nCharOfs; + if (chrgText) + { + chrgText->cpMin = nStart; + chrgText->cpMax = nStart + nLen; + } + TRACE("found at %d-%d\n", nStart, nStart + nLen); + return nStart; + } + if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText)) { - chrgText->cpMin = nStart; - chrgText->cpMax = nStart + nLen; + pCurItem = ME_FindItemFwd(pCurItem, diRun); + para = ME_GetParagraph(pCurItem); + nCurStart = -nMatched; } - return nStart; } - if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText)) + nStart++; + if (nStart == ME_StrLen(item->member.run.strText)) { - pCurItem = ME_FindItemFwd(pCurItem, diRun); - nCurStart = -nMatched; + item = ME_FindItemFwd(item, diRun); + para = ME_GetParagraph(item); + nStart = 0; } } - nStart++; - if (nStart == ME_StrLen(item->member.run.strText)) + } + else /* Backward search */ + { + nEnd = nMax; + item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd); + if (!item) + return -1; + + para = ME_GetParagraph(item); + + while (item + && para->member.para.nCharOfs + item->member.run.nCharOfs + nEnd - nLen >= nMin) { - item = ME_FindItemFwd(item, diRun); - para = ME_GetParagraph(item); - nStart = 0; + ME_DisplayItem *pCurItem = item; + int nCurEnd = nEnd; + int nMatched = 0; + + while (pCurItem && pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1] == text[nLen - nMatched - 1]) + { + nMatched++; + if (nMatched == nLen) + { + nStart = para->member.para.nCharOfs + item->member.run.nCharOfs + nCurEnd - nMatched; + if (chrgText) + { + chrgText->cpMin = nStart; + chrgText->cpMax = nStart + nLen; + } + TRACE("found at %d-%d\n", nStart, nStart + nLen); + return nStart; + } + if (nCurEnd - nMatched == 0) + { + pCurItem = ME_FindItemBack(pCurItem, diRun); + para = ME_GetParagraph(pCurItem); + nCurEnd = ME_StrLen(pCurItem->member.run.strText) + nMatched; + } + } + nEnd--; + if (nEnd < 0) + { + item = ME_FindItemBack(item, diRun); + para = ME_GetParagraph(item); + nEnd = ME_StrLen(item->member.run.strText); + } } } + TRACE("not found\n"); return -1; } @@ -748,6 +824,8 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { ed->nLastSelStart = ed->nLastSelEnd = 0; ed->nScrollPosY = 0; ed->nZoomNumerator = ed->nZoomDenominator = 0; + ed->bRedraw = TRUE; + GetClientRect(hWnd, &ed->rcFormat); for (i=0; ipFontCache[i].nRefs = 0; @@ -1016,17 +1094,15 @@ get_msg_name(UINT msg) * RichEditANSIWndProc (RICHED20.10) */ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - HDC hDC; - PAINTSTRUCT ps; SCROLLINFO si; ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongW(hWnd, 0); - TRACE("msg %d (%s) %08x %08lx\n", msg, get_msg_name(msg), wParam, lParam); + TRACE("hWnd %p msg %d (%s) %08x %08lx\n", + hWnd, msg, get_msg_name(msg), wParam, lParam); switch(msg) { UNSUPPORTED_MSG(EM_AUTOURLDETECT) - UNSUPPORTED_MSG(EM_CHARFROMPOS) UNSUPPORTED_MSG(EM_DISPLAYBAND) UNSUPPORTED_MSG(EM_EXLIMITTEXT) UNSUPPORTED_MSG(EM_FINDWORDBREAK) @@ -1044,7 +1120,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */ UNSUPPORTED_MSG(EM_GETOPTIONS) UNSUPPORTED_MSG(EM_GETPASSWORDCHAR) - UNSUPPORTED_MSG(EM_GETRECT) UNSUPPORTED_MSG(EM_GETREDONAME) UNSUPPORTED_MSG(EM_GETSCROLLPOS) UNSUPPORTED_MSG(EM_GETTEXTMODE) @@ -1068,8 +1143,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_SETOPTIONS) UNSUPPORTED_MSG(EM_SETPALETTE) UNSUPPORTED_MSG(EM_SETPASSWORDCHAR) - UNSUPPORTED_MSG(EM_SETRECT) - UNSUPPORTED_MSG(EM_SETRECTNP) UNSUPPORTED_MSG(EM_SETSCROLLPOS) UNSUPPORTED_MSG(EM_SETTABSTOPS) UNSUPPORTED_MSG(EM_SETTARGETDEVICE) @@ -1131,6 +1204,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return editor->pUndoStack != NULL; case EM_CANREDO: return editor->pRedoStack != NULL; + case WM_UNDO: /* FIXME: actually not the same */ case EM_UNDO: ME_Undo(editor); return 0; @@ -1191,9 +1265,12 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP if (wParam) editor->rgbBackColor = -1; else - editor->rgbBackColor = lParam; - InvalidateRect(hWnd, NULL, TRUE); - UpdateWindow(hWnd); + editor->rgbBackColor = lParam; + if (editor->bRedraw) + { + InvalidateRect(hWnd, NULL, TRUE); + UpdateWindow(hWnd); + } return lColor; } case EM_GETMODIFY: @@ -1219,8 +1296,12 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return 0; } case EM_SETEVENTMASK: + { + DWORD nOldMask = editor->nEventMask; + editor->nEventMask = lParam; - return 0; + return nOldMask; + } case EM_GETEVENTMASK: return editor->nEventMask; case EM_SETCHARFORMAT: @@ -1278,10 +1359,13 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP if (nPos<0) nPos = 0; if (nPos != editor->nScrollPosY) { - ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + if (editor->bRedraw) + { + ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + SetScrollPos(hWnd, SB_VERT, nPos, TRUE); + UpdateWindow(hWnd); + } editor->nScrollPosY = nPos; - SetScrollPos(hWnd, SB_VERT, nPos, TRUE); - UpdateWindow(hWnd); } return TRUE; /* Should return false if a single line richedit control */ } @@ -1430,20 +1514,35 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP case EM_GETTEXTEX: { GETTEXTEX *ex = (GETTEXTEX*)wParam; + int nStart, nCount; - if (ex->flags != 0) - FIXME("Unhandled EM_GETTEXTEX flags 0x%lx\n",ex->flags); + if (ex->flags & ~(GT_SELECTION | GT_USECRLF)) + FIXME("GETTEXTEX flags 0x%08lx not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF)); - if (IsWindowUnicode(hWnd)) - return ME_GetTextW(editor, (LPWSTR)lParam, 0, ex->cb, FALSE); + if (ex->flags & GT_SELECTION) + { + ME_GetSelection(editor, &nStart, &nCount); + nCount -= nStart; + nCount = min(nCount, ex->cb - 1); + } + else + { + nStart = 0; + nCount = ex->cb - 1; + } + if (ex->codepage == 1200 || IsWindowUnicode(hWnd)) + { + nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1); + return ME_GetTextW(editor, (LPWSTR)lParam, nStart, nCount, ex->flags & GT_USECRLF); + } else { - LPWSTR buffer = HeapAlloc(GetProcessHeap(),0,ex->cb*sizeof(WCHAR)); + LPWSTR buffer = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(WCHAR)); DWORD buflen = ex->cb; LRESULT rc; DWORD flags = 0; - buflen = ME_GetTextW(editor, buffer, 0, buflen, FALSE); + 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); @@ -1464,12 +1563,12 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP { TEXTRANGEW *rng = (TEXTRANGEW *)lParam; if (IsWindowUnicode(hWnd)) - return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE); + return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10); else { int nLen = rng->chrg.cpMax-rng->chrg.cpMin; WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1); - int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, FALSE); + int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, editor->bEmulateVersion10); /* FIXME this is a potential security hole (buffer overrun) if you know more about wchar->mbyte conversion please explain */ @@ -1477,7 +1576,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP FREE_OBJ(p); return nChars; } - return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE); } case EM_GETLINECOUNT: { @@ -1587,6 +1685,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return TRUE; case EM_SETZOOM: return ME_SetZoom(editor, wParam, lParam); + case EM_CHARFROMPOS: + return ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y); case WM_CREATE: ME_CommitUndo(editor); ME_WrapMarkedParagraphs(editor); @@ -1610,9 +1710,15 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP ReleaseCapture(); break; case WM_PAINT: - hDC = BeginPaint(hWnd, &ps); - ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint); - EndPaint(hWnd, &ps); + if (editor->bRedraw) + { + HDC hDC; + PAINTSTRUCT ps; + + hDC = BeginPaint(hWnd, &ps); + ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint); + EndPaint(hWnd, &ps); + } break; case WM_SETFOCUS: ME_ShowCaret(editor); @@ -1624,14 +1730,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP return 0; case WM_ERASEBKGND: { - HDC hDC = (HDC)wParam; - RECT rc; - COLORREF rgbBG = ME_GetBackColor(editor); - if (GetUpdateRect(hWnd,&rc,TRUE)) + if (editor->bRedraw) { - HBRUSH hbr = CreateSolidBrush(rgbBG); - FillRect(hDC, &rc, hbr); - DeleteObject(hbr); + HDC hDC = (HDC)wParam; + RECT rc; + COLORREF rgbBG = ME_GetBackColor(editor); + if (GetUpdateRect(hWnd,&rc,TRUE)) + { + HBRUSH hbr = CreateSolidBrush(rgbBG); + FillRect(hDC, &rc, hbr); + DeleteObject(hbr); + } } return 1; } @@ -1665,12 +1774,38 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP goto do_default; case WM_CHAR: { - WCHAR wstr; + WCHAR wstr = LOWORD(wParam); + + switch (wstr) + { + case 3: /* Ctrl-C */ + SendMessageW(editor->hWnd, WM_COPY, 0, 0); + return 0; + } + if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) { MessageBeep(MB_ICONERROR); return 0; /* FIXME really 0 ? */ } - wstr = LOWORD(wParam); + + switch (wstr) + { + case 1: /* Ctrl-A */ + ME_SetSelection(editor, 0, -1); + return 0; + case 22: /* Ctrl-V */ + SendMessageW(editor->hWnd, WM_PASTE, 0, 0); + return 0; + case 24: /* Ctrl-X */ + SendMessageW(editor->hWnd, WM_CUT, 0, 0); + return 0; + case 25: /* Ctrl-Y */ + SendMessageW(editor->hWnd, EM_REDO, 0, 0); + return 0; + case 26: /* Ctrl-Z */ + SendMessageW(editor->hWnd, EM_UNDO, 0, 0); + return 0; + } if (((unsigned)wstr)>=' ' || wstr=='\r' || wstr=='\t') { /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */ ME_Style *style = ME_GetInsertStyle(editor, 0); @@ -1714,10 +1849,13 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP break; } if (nPos != editor->nScrollPosY) { - ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + if (editor->bRedraw) + { + ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + SetScrollPos(hWnd, SB_VERT, nPos, TRUE); + UpdateWindow(hWnd); + } editor->nScrollPosY = nPos; - SetScrollPos(hWnd, SB_VERT, nPos, TRUE); - UpdateWindow(hWnd); } break; } @@ -1734,15 +1872,54 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP if (nPos<0) nPos = 0; if (nPos != editor->nScrollPosY) { - ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + if (editor->bRedraw) + { + ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL); + SetScrollPos(hWnd, SB_VERT, nPos, TRUE); + UpdateWindow(hWnd); + } editor->nScrollPosY = nPos; - SetScrollPos(hWnd, SB_VERT, nPos, TRUE); - UpdateWindow(hWnd); } break; } + case EM_GETRECT: + { + *((RECT *)lParam) = editor->rcFormat; + return 0; + } + case EM_SETRECT: + case EM_SETRECTNP: + { + if (lParam) + { + RECT *rc = (RECT *)lParam; + + if (wParam) + { + editor->rcFormat.left += rc->left; + editor->rcFormat.top += rc->top; + editor->rcFormat.right += rc->right; + editor->rcFormat.bottom += rc->bottom; + } + else + { + editor->rcFormat = *rc; + } + } + else + { + GetClientRect(hWnd, &editor->rcFormat); + } + if (msg != EM_SETRECTNP) + ME_RewrapRepaint(editor); + return 0; + } + case WM_SETREDRAW: + editor->bRedraw = wParam; + return 0; case WM_SIZE: { + GetClientRect(hWnd, &editor->rcFormat); ME_RewrapRepaint(editor); return DefWindowProcW(hWnd, msg, wParam, lParam); } @@ -1836,11 +2013,12 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in if (item->member.run.nFlags & MERF_ENDPARA) { - if (bCRLF) { - *buffer++ = '\r'; + *buffer++ = '\r'; + if (bCRLF) + { + *buffer = '\n'; nWritten++; - } - *buffer = '\n'; + } assert(nLen == 1); } else diff --git a/reactos/lib/riched20/editor.h b/reactos/lib/riched20/editor.h index 9f5f6bdd0ab..b168d01481d 100644 --- a/reactos/lib/riched20/editor.h +++ b/reactos/lib/riched20/editor.h @@ -141,6 +141,7 @@ void ME_HideCaret(ME_TextEditor *ed); void ME_ShowCaret(ME_TextEditor *ed); void ME_MoveCaret(ME_TextEditor *ed); int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol); +int ME_CharFromPos(ME_TextEditor *editor, int x, int y); void ME_LButtonDown(ME_TextEditor *editor, int x, int y); void ME_MouseMove(ME_TextEditor *editor, int x, int y); void ME_DeleteTextAtCursor(ME_TextEditor *editor, int nCursor, int nChars); diff --git a/reactos/lib/riched20/editstr.h b/reactos/lib/riched20/editstr.h index b6df58774cd..39de7e1282b 100644 --- a/reactos/lib/riched20/editstr.h +++ b/reactos/lib/riched20/editstr.h @@ -270,6 +270,8 @@ typedef struct tagME_TextEditor BOOL bScrollX, bScrollY; int nScrollPosY; int nZoomNumerator, nZoomDenominator; + RECT rcFormat; + BOOL bRedraw; } ME_TextEditor; typedef struct tagME_Context diff --git a/reactos/lib/riched20/paint.c b/reactos/lib/riched20/paint.c index 7b734af1ef3..c60b50d2f1e 100644 --- a/reactos/lib/riched20/paint.c +++ b/reactos/lib/riched20/paint.c @@ -154,12 +154,15 @@ void ME_Repaint(ME_TextEditor *editor) if (ME_WrapMarkedParagraphs(editor)) { ME_UpdateScrollBar(editor); } - hDC = GetDC(editor->hWnd); - ME_HideCaret(editor); - ME_PaintContent(editor, hDC, TRUE, NULL); - ReleaseDC(editor->hWnd, hDC); - ME_ShowCaret(editor); - ME_EnsureVisible(editor, pCursor->pRun); + if (editor->bRedraw) + { + hDC = GetDC(editor->hWnd); + ME_HideCaret(editor); + ME_PaintContent(editor, hDC, TRUE, NULL); + ReleaseDC(editor->hWnd, hDC); + ME_ShowCaret(editor); + ME_EnsureVisible(editor, pCursor->pRun); + } } void ME_UpdateRepaint(ME_TextEditor *editor) @@ -415,10 +418,13 @@ void ME_Scroll(ME_TextEditor *editor, int cx, int cy) GetScrollInfo(hWnd, SB_VERT, &si); si.nPos = editor->nScrollPosY -= cy; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); - if (abs(cy) > editor->sizeWindow.cy) - InvalidateRect(editor->hWnd, NULL, TRUE); - else - ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE); + if (editor->bRedraw) + { + if (abs(cy) > editor->sizeWindow.cy) + InvalidateRect(editor->hWnd, NULL, TRUE); + else + ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE); + } } void ME_UpdateScrollBar(ME_TextEditor *editor) @@ -495,14 +501,20 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun) if (yrel < 0) { editor->nScrollPosY = y; SetScrollPos(hWnd, SB_VERT, y, TRUE); - ScrollWindow(hWnd, 0, -yrel, NULL, NULL); - UpdateWindow(hWnd); + if (editor->bRedraw) + { + ScrollWindow(hWnd, 0, -yrel, NULL, NULL); + UpdateWindow(hWnd); + } } else if (yrel + yheight > editor->sizeWindow.cy) { int newy = y+yheight-editor->sizeWindow.cy; editor->nScrollPosY = newy; SetScrollPos(hWnd, SB_VERT, newy, TRUE); - ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL); - UpdateWindow(hWnd); + if (editor->bRedraw) + { + ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL); + UpdateWindow(hWnd); + } } } diff --git a/reactos/lib/riched20/reader.c b/reactos/lib/riched20/reader.c index caecb52f8d3..25805c21111 100644 --- a/reactos/lib/riched20/reader.c +++ b/reactos/lib/riched20/reader.c @@ -257,6 +257,7 @@ void RTFInit(RTF_Info *info) info->ansiCodePage = 1252; /* Latin-1; actually unused */ info->unicodeLength = 1; /* \uc1 is the default */ info->codePage = info->ansiCodePage; + info->defFont = 0; info->rtfClass = -1; info->pushedClass = -1; @@ -1005,6 +1006,14 @@ static void ReadFontTbl(RTF_Info *info) if (!RTFCheckCM (info, rtfGroup, rtfEndGroup)) RTFPanic (info, "%s: missing \"}\"", fn); } + + /* Apply the real properties of the default font */ + if (fp->rtfFNum == info->defFont) + { + if (info->ansiCodePage != CP_UTF8) + info->codePage = fp->rtfFCodePage; + TRACE("default font codepage %d\n", info->codePage); + } } if (fp->rtfFNum == -1) RTFPanic (info,"%s: missing font number", fn); @@ -1012,6 +1021,14 @@ static void ReadFontTbl(RTF_Info *info) * Could check other pieces of structure here, too, I suppose. */ RTFRouteToken (info); /* feed "}" back to router */ + + /* Set default font */ + info->rtfClass = rtfControl; + info->rtfMajor = rtfCharAttr; + info->rtfMinor = rtfFontNum; + info->rtfParam = info->defFont; + lstrcpyA(info->rtfTextBuf, "f"); + RTFUngetToken(info); } @@ -2467,6 +2484,7 @@ void RTFPanic(RTF_Info *info, const char *fmt, ...) static void TextClass (RTF_Info *info); static void ControlClass (RTF_Info *info); +static void DefFont(RTF_Info *info); static void Destination (RTF_Info *info); static void SpecialChar (RTF_Info *info); static void RTFPutUnicodeChar (RTF_Info *info, int c); @@ -2516,6 +2534,9 @@ ControlClass (RTF_Info *info) case rtfCharSet: CharSet(info); break; + case rtfDefFont: + DefFont(info); + break; case rtfDestination: Destination (info); break; @@ -2542,6 +2563,7 @@ CharAttr(RTF_Info *info) { if (info->ansiCodePage != CP_UTF8) info->codePage = font->rtfFCodePage; + TRACE("font %d codepage %d\n", info->rtfParam, info->codePage); } else RTFMsg(info, "unknown font %d\n", info->rtfParam); @@ -2556,6 +2578,9 @@ CharAttr(RTF_Info *info) static void CharSet(RTF_Info *info) { + if (info->ansiCodePage == CP_UTF8) + return; + switch (info->rtfMinor) { case rtfAnsiCharSet: @@ -2588,16 +2613,26 @@ Destination (RTF_Info *info) } +static void +DefFont(RTF_Info *info) +{ + TRACE("%d\n", info->rtfParam); + info->defFont = info->rtfParam; +} + + static void DocAttr(RTF_Info *info) { + TRACE("minor %d, param %d\n", info->rtfMinor, info->rtfParam); + switch (info->rtfMinor) { case rtfAnsiCodePage: - info->ansiCodePage = info->rtfParam; + info->codePage = info->ansiCodePage = info->rtfParam; break; case rtfUTF8RTF: - info->ansiCodePage = CP_UTF8; + info->codePage = info->ansiCodePage = CP_UTF8; break; } } @@ -2704,10 +2739,9 @@ RTFPutUnicodeString(RTF_Info *info, WCHAR *string, int length) int fit = min(length, sizeof(info->OutputBuffer) / sizeof(WCHAR) - info->dwOutputCount); memmove(info->OutputBuffer + info->dwOutputCount, string, fit * sizeof(WCHAR)); + info->dwOutputCount += fit; if (fit == sizeof(info->OutputBuffer) / sizeof(WCHAR) - info->dwOutputCount) RTFFlushUnicodeOutputBuffer(info); - else - info->dwOutputCount += fit; length -= fit; string += fit; } diff --git a/reactos/lib/riched20/richole.c b/reactos/lib/riched20/richole.c index 4f399a2067a..d45741477d6 100644 --- a/reactos/lib/riched20/richole.c +++ b/reactos/lib/riched20/richole.c @@ -37,7 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); typedef struct IRichEditOleImpl { const IRichEditOleVtbl *lpVtbl; - DWORD ref; + LONG ref; } IRichEditOleImpl; /* there is no way to be consistent across different sets of headers - mingw, Wine, Win32 SDK*/ diff --git a/reactos/lib/riched20/row.c b/reactos/lib/riched20/row.c index b803ed21302..d7a6bd158e2 100644 --- a/reactos/lib/riched20/row.c +++ b/reactos/lib/riched20/row.c @@ -116,10 +116,14 @@ ME_RowNumberFromCharOfs(ME_TextEditor *editor, int nOfs) } if (item) { + ME_DisplayItem *next_para = item->member.para.next_para; + nOfs -= item->member.para.nCharOfs; item = ME_FindItemFwd(item, diRun); while ((item = ME_FindItemFwd(item, diStartRowOrParagraph)) != NULL) { + if (item == next_para) + break; item = ME_FindItemFwd(item, diRun); if (item->member.run.nCharOfs > nOfs) break; diff --git a/reactos/lib/riched20/rtf.h b/reactos/lib/riched20/rtf.h index 53ec6eeac21..d3720be01d5 100644 --- a/reactos/lib/riched20/rtf.h +++ b/reactos/lib/riched20/rtf.h @@ -1070,6 +1070,7 @@ struct _RTF_Info { RTFColor *colorList; /* initialized to NULL */ RTFStyle *styleList; int ansiCodePage; /* ANSI codepage used in conversion to Unicode */ + int defFont; /* Character attributes */ int unicodeLength; /* The length of ANSI representation of Unicode characters */ @@ -1103,6 +1104,7 @@ struct _RTF_Info { RTFState stack[maxStack]; int stackTop; + BOOL styleChanged; }; diff --git a/reactos/lib/riched20/writer.c b/reactos/lib/riched20/writer.c index a6aba952472..11d55a8917f 100644 --- a/reactos/lib/riched20/writer.c +++ b/reactos/lib/riched20/writer.c @@ -588,7 +588,7 @@ ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars) return FALSE; pos = i; } - if (!pos) + if (pos < nBytes) if (!ME_StreamOutMove(editor, buffer + pos, nBytes - pos)) return FALSE; pos = 0; @@ -681,6 +681,8 @@ ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat) if (!ME_StreamOutPrint(editor, "\r\n\\par")) return FALSE; nChars--; + if (editor->bEmulateVersion10 && nChars) + nChars--; } else { int nEnd; @@ -790,7 +792,12 @@ ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream) nTo = -1; } if (nTo == -1) + { nTo = ME_GetTextLength(editor); + /* Generate an end-of-paragraph at the end of SCF_ALL RTF output */ + if (dwFormat & SF_RTF) + nTo++; + } TRACE("from %d to %d\n", nStart, nTo); if (dwFormat & SF_RTF) diff --git a/reactos/w32api/include/richedit.h b/reactos/w32api/include/richedit.h index 5a1a5fe046c..c8ca83f67f0 100644 --- a/reactos/w32api/include/richedit.h +++ b/reactos/w32api/include/richedit.h @@ -296,6 +296,7 @@ extern "C" { #define TM_MULTICODEPAGE 32 #define GT_DEFAULT 0 #define GT_USECRLF 1 +#define GT_SELECTION 2 #define yHeightCharPtsMost 1638 #define lDefaultTab 720 -- 2.17.1