From 5bb24c753a6772aeca03bb7a0ede642d390670e6 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Sat, 31 Jan 2009 12:10:24 +0000 Subject: [PATCH] sync riched20 with wine 1.1.14 svn path=/trunk/; revision=39224 --- reactos/dll/win32/riched20/caret.c | 175 ++--- reactos/dll/win32/riched20/clipboard.c | 4 +- reactos/dll/win32/riched20/context.c | 12 +- reactos/dll/win32/riched20/editor.c | 676 ++++++++++--------- reactos/dll/win32/riched20/editor.h | 59 +- reactos/dll/win32/riched20/editstr.h | 12 +- reactos/dll/win32/riched20/list.c | 6 +- reactos/dll/win32/riched20/paint.c | 138 ++-- reactos/dll/win32/riched20/para.c | 36 +- reactos/dll/win32/riched20/reader.c | 114 ++-- reactos/dll/win32/riched20/riched20.rbuild | 2 + reactos/dll/win32/riched20/richole.c | 4 +- reactos/dll/win32/riched20/rtf.h | 7 - reactos/dll/win32/riched20/run.c | 103 ++- reactos/dll/win32/riched20/string.c | 9 +- reactos/dll/win32/riched20/style.c | 4 +- reactos/dll/win32/riched20/table.c | 23 +- reactos/dll/win32/riched20/txthost.c | 727 +++++++++++++++++++++ reactos/dll/win32/riched20/txtsrv.c | 59 +- reactos/dll/win32/riched20/undo.c | 8 +- reactos/dll/win32/riched20/wrap.c | 19 +- reactos/dll/win32/riched20/writer.c | 61 +- reactos/include/psdk/textserv.h | 40 -- 23 files changed, 1492 insertions(+), 806 deletions(-) create mode 100644 reactos/dll/win32/riched20/txthost.c diff --git a/reactos/dll/win32/riched20/caret.c b/reactos/dll/win32/riched20/caret.c index 461ad005cc7..cdd8f798415 100644 --- a/reactos/dll/win32/riched20/caret.c +++ b/reactos/dll/win32/riched20/caret.c @@ -151,8 +151,13 @@ int ME_SetSelection(ME_TextEditor *editor, int from, int to) return len; } - ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset); - ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset); + ME_CursorFromCharOfs(editor, from, &editor->pCursors[1]); + ME_CursorFromCharOfs(editor, to, &editor->pCursors[0]); + /* Selection is not allowed in the middle of an end paragraph run. */ + if (editor->pCursors[1].pRun->member.run.nFlags & MERF_ENDPARA) + editor->pCursors[1].nOffset = 0; + if (editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA) + editor->pCursors[0].nOffset = 0; return to; } @@ -173,7 +178,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor, ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph); if (row) { - HDC hDC = GetDC(editor->hWnd); + HDC hDC = ITextHost_TxGetDC(editor->texthost); ME_Context c; ME_DisplayItem *run = pCursorRun; ME_DisplayItem *para = NULL; @@ -217,7 +222,7 @@ ME_GetCursorCoordinates(ME_TextEditor *editor, ME_Cursor *pCursor, *x = c.rcView.left + run->member.run.pt.x + sz.cx - editor->horz_si.nPos; *y = c.rcView.top + para->member.para.pt.y + row->member.row.nBaseline + run->member.run.pt.y - pSizeRun->member.run.nAscent - editor->vert_si.nPos; - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); return; } } @@ -238,8 +243,8 @@ ME_MoveCaret(ME_TextEditor *editor) if(editor->bHaveFocus && !ME_IsSelection(editor)) { x = min(x, editor->rcFormat.right-1); - CreateCaret(editor->hWnd, NULL, 0, height); - SetCaretPos(x, y); + ITextHost_TxCreateCaret(editor->texthost, NULL, 0, height); + ITextHost_TxSetCaretPos(editor->texthost, x, y); } } @@ -248,14 +253,14 @@ void ME_ShowCaret(ME_TextEditor *ed) { ME_MoveCaret(ed); if(ed->bHaveFocus && !ME_IsSelection(ed)) - ShowCaret(ed->hWnd); + ITextHost_TxShowCaret(ed->texthost, TRUE); } void ME_HideCaret(ME_TextEditor *ed) { if(!ed->bHaveFocus || ME_IsSelection(ed)) { - HideCaret(ed->hWnd); + ITextHost_TxShowCaret(ed->texthost, FALSE); DestroyCaret(); } } @@ -298,14 +303,11 @@ BOOL ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars, /* We aren't deleting anything in this run, so we will go back to the * last run we are deleting text in. */ c.pRun = ME_FindItemBack(c.pRun, diRun); - if (c.pRun->member.run.nFlags & MERF_ENDPARA) - c.nOffset = c.pRun->member.run.nCR + c.pRun->member.run.nLF; - else - c.nOffset = c.pRun->member.run.strText->nLen; + c.nOffset = c.pRun->member.run.strText->nLen; } run = &c.pRun->member.run; if (run->nFlags & MERF_ENDPARA) { - int eollen = run->nCR + run->nLF; + int eollen = c.pRun->member.run.strText->nLen; BOOL keepFirstParaFormat; if (!ME_FindItemFwd(c.pRun, diParagraph)) @@ -517,107 +519,72 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, if(editor->nTextLimit < oldLen +len) editor->nTextLimit = oldLen + len; + pos = str; + 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') + while(pos - str < len && *pos != '\r' && *pos != '\n' && *pos != '\t') pos++; - if (pos-str < len && *pos == '\t') { /* handle tabs */ + + if (pos != str) { /* handle text */ + ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); + } else if (*pos == '\t') { /* handle tabs */ WCHAR tab = '\t'; - - if (pos!=str) - ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); - ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB); - pos++; - if(pos-str <= len) { - len -= pos - str; - str = pos; - continue; - } - } - /* handle special \r\r\n sequence (richedit 2.x and higher only) */ - if (!editor->bEmulateVersion10 && pos-str < len-2 && pos[0] == '\r' && pos[1] == '\r' && pos[2] == '\n') { - WCHAR space = ' '; - - if (pos!=str) - ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); - - ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0); - - pos+=3; - if(pos-str <= len) { - len -= pos - str; - str = pos; - continue; - } - } - if (pos-str < len) { /* handle EOLs */ + } else { /* handle EOLs */ ME_DisplayItem *tp, *end_run; ME_Style *tmp_style; - int numCR, numLF; + int eol_len = 0; - if (pos!=str) - ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0); - p = &editor->pCursors[nCursor]; - 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 */ - - /* Encode and fill number of CR and LF according to emulation mode */ - if (editor->bEmulateVersion10) { - const WCHAR * tpos; - - /* We have to find out how many consecutive \r are there, and if there - is a \n terminating the run of \r's. */ - numCR = 0; numLF = 0; - tpos = pos; - while (tpos-str < len && *tpos == '\r') { - tpos++; - numCR++; - } - if (tpos-str >= len) { - /* Reached end of text without finding anything but '\r' */ - if (tpos != pos) { - pos++; - } - numCR = 1; numLF = 0; - } else if (*tpos == '\n') { - /* The entire run of \r's plus the one \n is one single line break */ - pos = tpos + 1; - numLF = 1; - } else { - /* Found some other content past the run of \r's */ - pos++; - numCR = 1; numLF = 0; - } + /* Find number of CR and LF in end of paragraph run */ + if (*pos =='\r') + { + if (len > 1 && pos[1] == '\n') + eol_len = 2; + else if (len > 2 && pos[1] == '\r' && pos[2] == '\n') + eol_len = 3; + else + eol_len = 1; } else { - if(pos-str < len && *pos =='\r') - pos++; - if(pos-str < len && *pos =='\n') - pos++; - numCR = 1; numLF = 0; + assert(*pos == '\n'); + eol_len = 1; } - tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, numCR, numLF, 0); - 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; + pos += eol_len; - if(pos-str <= len) { - len -= pos - str; - str = pos; - continue; + if (!editor->bEmulateVersion10 && eol_len == 3) + { + /* handle special \r\r\n sequence (richedit 2.x and higher only) */ + WCHAR space = ' '; + ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0); + } else { + ME_String *eol_str; + + if (!editor->bEmulateVersion10) { + WCHAR cr = '\r'; + eol_str = ME_MakeStringN(&cr, 1); + } else { + eol_str = ME_MakeStringN(str, eol_len); + } + + p = &editor->pCursors[nCursor]; + 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, eol_str, 0); + 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; } } - ME_InternalInsertTextFromCursor(editor, nCursor, str, len, style, 0); - len = 0; + len -= pos - str; + str = pos; } } @@ -1020,7 +987,7 @@ int ME_CharFromPos(ME_TextEditor *editor, int x, int y, BOOL *isExact) RECT rc; BOOL bResult; - GetClientRect(editor->hWnd, &rc); + ITextHost_TxGetClientRect(editor->texthost, &rc); if (x < 0 || y < 0 || x >= rc.right || y >= rc.bottom) { if (isExact) *isExact = FALSE; return -1; @@ -1154,7 +1121,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum) } } ME_InvalidateSelection(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_ShowCaret(editor); ME_ClearTempStyle(editor); ME_SendSelChange(editor); @@ -1188,7 +1155,7 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y) } ME_InvalidateSelection(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_ShowCaret(editor); ME_SendSelChange(editor); } @@ -1574,7 +1541,7 @@ void ME_SendSelChange(ME_TextEditor *editor) ME_ClearTempStyle(editor); editor->notified_cr = sc.chrg; - SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc); + ITextHost_TxNotify(editor->texthost, sc.nmhdr.code, &sc); } } @@ -1636,7 +1603,7 @@ ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl) ME_InvalidateSelection(editor); ME_Repaint(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_EnsureVisible(editor, &tmp_curs); ME_ShowCaret(editor); ME_SendSelChange(editor); diff --git a/reactos/dll/win32/riched20/clipboard.c b/reactos/dll/win32/riched20/clipboard.c index b26222d85c9..648f0c5a12b 100644 --- a/reactos/dll/win32/riched20/clipboard.c +++ b/reactos/dll/win32/riched20/clipboard.c @@ -54,7 +54,7 @@ static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFII if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) { IEnumFORMATETC_AddRef(iface); - *ppvObj = (LPVOID)This; + *ppvObj = This; return S_OK; } *ppvObj = NULL; @@ -170,7 +170,7 @@ static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID r if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) { IDataObject_AddRef(iface); - *ppvObj = (LPVOID)This; + *ppvObj = This; return S_OK; } *ppvObj = NULL; diff --git a/reactos/dll/win32/riched20/context.c b/reactos/dll/win32/riched20/context.c index 161a64a4ebd..6d4a2a93580 100644 --- a/reactos/dll/win32/riched20/context.c +++ b/reactos/dll/win32/riched20/context.c @@ -29,12 +29,16 @@ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC) c->pt.y = 0; c->hbrMargin = CreateSolidBrush(RGB(224,224,224)); c->rcView = editor->rcFormat; - c->dpi.cx = GetDeviceCaps(hDC, LOGPIXELSX); - c->dpi.cy = GetDeviceCaps(hDC, LOGPIXELSY); + if (hDC) { + c->dpi.cx = GetDeviceCaps(hDC, LOGPIXELSX); + c->dpi.cy = GetDeviceCaps(hDC, LOGPIXELSY); + } else { + c->dpi.cx = c->dpi.cy = 96; + } } -void ME_DestroyContext(ME_Context *c, HWND hWnd) +void ME_DestroyContext(ME_Context *c) { - if (hWnd) ReleaseDC(hWnd, c->hDC); + if (c->hDC) ITextHost_TxReleaseDC(c->editor->texthost, c->hDC); DeleteObject(c->hbrMargin); } diff --git a/reactos/dll/win32/riched20/editor.c b/reactos/dll/win32/riched20/editor.c index b67ca6045dd..574118aede4 100644 --- a/reactos/dll/win32/riched20/editor.c +++ b/reactos/dll/win32/riched20/editor.c @@ -56,7 +56,7 @@ + EM_GETLINE + EM_GETLINECOUNT returns number of rows, not of paragraphs + EM_GETMODIFY - - EM_GETOLEINTERFACE + + EM_GETOLEINTERFACE + EM_GETOPTIONS + EM_GETPARAFORMAT + EM_GETPASSWORDCHAR 2.0 @@ -1393,7 +1393,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre ME_InStream inStream; BOOL invalidRTF = FALSE; - TRACE("stream==%p hWnd==%p format==0x%X\n", stream, editor->hWnd, format); + TRACE("stream==%p editor==%p format==0x%X\n", stream, editor, format); editor->nEventMask = 0; ME_GetSelection(editor, &from, &to); @@ -1580,9 +1580,9 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre if (!(format & SFF_SELECTION)) { ME_ClearTempStyle(editor); } - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_MoveCaret(editor); - ShowCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, TRUE); ME_SendSelChange(editor); ME_SendRequestResize(editor, FALSE); @@ -1624,55 +1624,6 @@ ME_StreamInRTFString(ME_TextEditor *editor, BOOL selection, char *string) } -ME_DisplayItem * -ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset) -{ - ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph); - int runLength; - - while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset) - item = ME_FindItemFwd(item, diParagraph); - - if (!item) - return item; - - nOffset -= item->member.para.nCharOfs; - if (nItemType == diParagraph) { - if (nItemOffset) - *nItemOffset = nOffset; - return item; - } - - do { - item = ME_FindItemFwd(item, diRun); - runLength = ME_StrLen(item->member.run.strText); - if (item->member.run.nFlags & MERF_ENDPARA) - runLength = item->member.run.nCR + item->member.run.nLF; - } while (item && (item->member.run.nCharOfs + runLength <= nOffset)); - if (item) { - nOffset -= item->member.run.nCharOfs; - - /* Special case: nOffset may not point exactly at the division between the - \r and the \n in 1.0 emulation. If such a case happens, it is sent - into the next run, if one exists - */ - if ( item->member.run.nFlags & MERF_ENDPARA - && nOffset == item->member.run.nCR - && item->member.run.nLF > 0) { - ME_DisplayItem *nextItem; - nextItem = ME_FindItemFwd(item, diRun); - if (nextItem) { - nOffset = 0; - item = nextItem; - } - } - if (nItemOffset) - *nItemOffset = nOffset; - } - return item; -} - - static int ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCHAR *text, CHARRANGE *chrgText) { @@ -1743,7 +1694,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH if ((flags & FR_WHOLEWORD) && nMin) { nStart = nMin - 1; - item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + ME_RunOfsFromCharOfs(editor, nStart, &item, &nStart); if (!item) { if (chrgText) @@ -1754,7 +1705,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH } nStart = nMin; - item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + ME_RunOfsFromCharOfs(editor, nStart, &item, &nStart); if (!item) { if (chrgText) @@ -1836,7 +1787,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH if ((flags & FR_WHOLEWORD) && nMax < nTextLen - 1) { nEnd = nMax + 1; - item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd); + ME_RunOfsFromCharOfs(editor, nEnd, &item, &nEnd); if (!item) { if (chrgText) @@ -1847,7 +1798,7 @@ ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCH } nEnd = nMax; - item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd); + ME_RunOfsFromCharOfs(editor, nEnd, &item, &nEnd); if (!item) { if (chrgText) @@ -2100,14 +2051,11 @@ ME_FilterEvent(ME_TextEditor *editor, UINT msg, WPARAM* wParam, LPARAM* lParam) { MSGFILTER msgf; - msgf.nmhdr.hwndFrom = editor->hWnd; - msgf.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID); msgf.nmhdr.code = EN_MSGFILTER; msgf.msg = msg; - msgf.wParam = *wParam; msgf.lParam = *lParam; - if (SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, msgf.nmhdr.idFrom, (LPARAM)&msgf)) + if (ITextHost_TxNotify(editor->texthost, msgf.nmhdr.code, &msgf) == S_OK) return FALSE; *wParam = msgf.wParam; *lParam = msgf.lParam; @@ -2120,7 +2068,7 @@ static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor) { ME_DisplayItem * startPara, * endPara; ME_DisplayItem * item; - int dummy; + ME_Cursor cursor; int from, to; ME_GetSelection(editor, &from, &to); @@ -2128,15 +2076,17 @@ static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor) startPara = NULL; endPara = NULL; /* Find paragraph previous to the one that contains start cursor */ - item = ME_FindItemAtOffset(editor, diRun, from, &dummy); + ME_CursorFromCharOfs(editor, from, &cursor); + item = cursor.pRun; if (item) { startPara = ME_FindItemBack(item, diParagraph); - item = ME_FindItemBack(startPara, diParagraph); - if (item) startPara = item; + item = startPara->member.para.prev_para; + if (item && item->type == diParagraph) startPara = item; } /* Find paragraph that contains end cursor */ - item = ME_FindItemAtOffset(editor, diRun, to, &dummy); + ME_CursorFromCharOfs(editor, to, &cursor); + item = cursor.pRun; if (item) { endPara = ME_FindItemFwd(item, diParagraph); } @@ -2158,6 +2108,8 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000; BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000; + if (editor->bMouseCaptured) + return FALSE; if (nKey != VK_SHIFT && nKey != VK_CONTROL && nKey != VK_MENU) editor->nSelectionType = stPosition; @@ -2403,6 +2355,9 @@ static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode, { WCHAR wstr; + if (editor->bMouseCaptured) + return 0; + if (unicode) wstr = (WCHAR)charCode; else @@ -2476,7 +2431,7 @@ static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode, ME_InsertTextFromCursor(editor, 0, &wstr, 1, style); ME_ReleaseStyle(style); ME_CommitCoalescingUndo(editor); - SetCursor(NULL); + ITextHost_TxSetCursor(editor->texthost, NULL, FALSE); } if (editor->AutoURLDetect_bEnable) ME_UpdateSelectionLinkAttribute(editor); @@ -2549,46 +2504,53 @@ static BOOL ME_SetCursor(ME_TextEditor *editor) pt.x = (short)LOWORD(messagePos); pt.y = (short)HIWORD(messagePos); - sbi.cbSize = sizeof(sbi); - GetScrollBarInfo(editor->hWnd, OBJID_HSCROLL, &sbi); - if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && - PtInRect(&sbi.rcScrollBar, pt)) + if (editor->hWnd) { - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); - return TRUE; + sbi.cbSize = sizeof(sbi); + GetScrollBarInfo(editor->hWnd, OBJID_HSCROLL, &sbi); + if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && + PtInRect(&sbi.rcScrollBar, pt)) + { + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); + return TRUE; + } + sbi.cbSize = sizeof(sbi); + GetScrollBarInfo(editor->hWnd, OBJID_VSCROLL, &sbi); + if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && + PtInRect(&sbi.rcScrollBar, pt)) + { + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); + return TRUE; + } } - sbi.cbSize = sizeof(sbi); - GetScrollBarInfo(editor->hWnd, OBJID_VSCROLL, &sbi); - if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && - PtInRect(&sbi.rcScrollBar, pt)) - { - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); - return TRUE; - } - ScreenToClient(editor->hWnd, &pt); + ITextHost_TxScreenToClient(editor->texthost, &pt); if (editor->nSelectionType == stLine && editor->bMouseCaptured) { - SetCursor(hLeft); + ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); return TRUE; } if (!editor->bEmulateVersion10 /* v4.1 */ && pt.y < editor->rcFormat.top && pt.x < editor->rcFormat.left) { - SetCursor(hLeft); + ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); return TRUE; } if (pt.y < editor->rcFormat.top || pt.y > editor->rcFormat.bottom) { if (editor->bEmulateVersion10) /* v1.0 - 3.0 */ - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); else /* v4.1 */ - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_IBEAM)); + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_IBEAM), TRUE); return TRUE; } if (pt.x < editor->rcFormat.left) { - SetCursor(hLeft); + ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); return TRUE; } offset = ME_CharFromPos(editor, pt.x, pt.y, &isExact); @@ -2604,7 +2566,9 @@ static BOOL ME_SetCursor(ME_TextEditor *editor) run->style->fmt.dwMask & CFM_LINK && run->style->fmt.dwEffects & CFE_LINK) { - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_HAND)); + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_HAND), + FALSE); return TRUE; } } @@ -2613,21 +2577,22 @@ static BOOL ME_SetCursor(ME_TextEditor *editor) int selStart, selEnd; ME_GetSelection(editor, &selStart, &selEnd); if (selStart <= offset && selEnd >= offset) { - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_ARROW)); + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_ARROW), + FALSE); return TRUE; } } } - SetCursor(LoadCursorW(NULL, (WCHAR*)IDC_IBEAM)); + ITextHost_TxSetCursor(editor->texthost, + LoadCursorW(NULL, (WCHAR*)IDC_IBEAM), TRUE); return TRUE; } static void ME_SetDefaultFormatRect(ME_TextEditor *editor) { - DWORD exstyle = GetWindowLongW(editor->hWnd, GWL_EXSTYLE); - - GetClientRect(editor->hWnd, &editor->rcFormat); - editor->rcFormat.top += (exstyle & WS_EX_CLIENTEDGE ? 1 : 0); + ITextHost_TxGetClientRect(editor->texthost, &editor->rcFormat); + editor->rcFormat.top += editor->exStyleFlags & WS_EX_CLIENTEDGE ? 1 : 0; editor->rcFormat.left += 1 + editor->selofs; editor->rcFormat.right -= 1; } @@ -2637,7 +2602,7 @@ static BOOL ME_ShowContextMenu(ME_TextEditor *editor, int x, int y) CHARRANGE selrange; HMENU menu; int seltype = 0; - if(!editor->lpOleCallback) + if(!editor->lpOleCallback || !editor->hWnd) return FALSE; ME_GetSelection(editor, &selrange.cpMin, &selrange.cpMax); if(selrange.cpMin == selrange.cpMax) @@ -2657,17 +2622,26 @@ static BOOL ME_ShowContextMenu(ME_TextEditor *editor, int x, int y) return TRUE; } -static ME_TextEditor *ME_MakeEditor(HWND hWnd, BOOL bEmulateVersion10) +ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10) { ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor); int i; - ed->hWnd = hWnd; + DWORD props; + LONG selbarwidth; + + ed->hWnd = NULL; + ed->texthost = texthost; ed->bEmulateVersion10 = bEmulateVersion10; - ed->styleFlags = GetWindowLongW(hWnd, GWL_STYLE); - if (ed->styleFlags & WS_VSCROLL) - ed->styleFlags |= ES_AUTOVSCROLL; - if (!ed->bEmulateVersion10 && (ed->styleFlags & WS_HSCROLL)) - ed->styleFlags |= ES_AUTOHSCROLL; + ITextHost_TxGetPropertyBits(texthost, + (TXTBIT_RICHTEXT|TXTBIT_MULTILINE| + TXTBIT_READONLY|TXTBIT_USEPASSWORD| + TXTBIT_HIDESELECTION|TXTBIT_SAVESELECTION| + TXTBIT_AUTOWORDSEL|TXTBIT_VERTICAL| + TXTBIT_WORDWRAP|TXTBIT_DISABLEDRAG), + &props); + ITextHost_TxGetScrollBars(texthost, &ed->styleFlags); + ed->styleFlags &= (WS_VSCROLL|WS_HSCROLL|ES_AUTOVSCROLL| + ES_AUTOHSCROLL|ES_DISABLENOSCROLL); ed->pBuffer = ME_MakeText(); ed->nZoomNumerator = ed->nZoomDenominator = 0; ME_MakeFirstParagraph(ed); @@ -2702,12 +2676,12 @@ static ME_TextEditor *ME_MakeEditor(HWND hWnd, BOOL bEmulateVersion10) ed->nParagraphs = 1; ed->nLastSelStart = ed->nLastSelEnd = 0; ed->pLastSelStartPara = ed->pLastSelEndPara = ME_FindItemFwd(ed->pBuffer->pFirst, diParagraph); - ed->bWordWrap = !(ed->styleFlags & ES_AUTOHSCROLL); + ed->bWordWrap = (props & TXTBIT_WORDWRAP) != 0; ed->bHideSelection = FALSE; - ed->nInvalidOfs = -1; ed->pfnWordBreak = NULL; ed->lpOleCallback = NULL; ed->mode = TM_RICHTEXT | TM_MULTILEVELUNDO | TM_MULTICODEPAGE; + ed->mode |= (props & TXTBIT_RICHTEXT) ? TM_RICHTEXT : TM_PLAINTEXT; ed->AutoURLDetect_bEnable = FALSE; ed->bHaveFocus = FALSE; ed->bMouseCaptured = FALSE; @@ -2719,17 +2693,30 @@ static ME_TextEditor *ME_MakeEditor(HWND hWnd, BOOL bEmulateVersion10) } ME_CheckCharOffsets(ed); - if (ed->styleFlags & ES_SELECTIONBAR) - ed->selofs = SELECTIONBAR_WIDTH; - else - ed->selofs = 0; ed->bDefaultFormatRect = TRUE; + ITextHost_TxGetSelectionBarWidth(ed->texthost, &selbarwidth); + /* FIXME: Convert selbarwidth from HIMETRIC to pixels */ + ed->selofs = selbarwidth ? SELECTIONBAR_WIDTH : 0; ed->nSelectionType = stPosition; - if (ed->styleFlags & ES_PASSWORD) - ed->cPasswordMask = '*'; - else - ed->cPasswordMask = 0; + ed->cPasswordMask = 0; + if (props & TXTBIT_USEPASSWORD) + ITextHost_TxGetPasswordChar(texthost, &ed->cPasswordMask); + + if (props & TXTBIT_AUTOWORDSEL) + ed->styleFlags |= ECO_AUTOWORDSELECTION; + if (props & TXTBIT_MULTILINE) + ed->styleFlags |= ES_MULTILINE; + if (props & TXTBIT_READONLY) + ed->styleFlags |= ES_READONLY; + if (!(props & TXTBIT_HIDESELECTION)) + ed->styleFlags |= ES_NOHIDESEL; + if (props & TXTBIT_SAVESELECTION) + ed->styleFlags |= ES_SAVESEL; + if (props & TXTBIT_VERTICAL) + ed->styleFlags |= ES_VERTICAL; + if (props & TXTBIT_DISABLEDRAG) + ed->styleFlags |= ES_NOOLEDRAGDROP; ed->notified_cr.cpMin = ed->notified_cr.cpMax = 0; @@ -2774,7 +2761,7 @@ static void ME_DestroyEditor(ME_TextEditor *editor) DeleteObject(editor->hbrBackground); if(editor->lpOleCallback) IUnknown_Release(editor->lpOleCallback); - SetWindowLongPtrW(editor->hWnd, 0, 0); + IUnknown_Release(editor->texthost); OleUninitialize(); FREE_OBJ(editor->pBuffer); @@ -2994,7 +2981,7 @@ void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam * The LRESULT that is returned is a return value for window procs, * and the phresult parameter is the COM return code needed by the * text services interface. */ -static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, +LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode, HRESULT* phresult) { *phresult = S_OK; @@ -3011,7 +2998,6 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, UNSUPPORTED_MSG(EM_GETIMESTATUS) UNSUPPORTED_MSG(EM_SETIMESTATUS) UNSUPPORTED_MSG(EM_GETLANGOPTIONS) - /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */ UNSUPPORTED_MSG(EM_GETREDONAME) UNSUPPORTED_MSG(EM_GETTEXTMODE) UNSUPPORTED_MSG(EM_GETTYPOGRAPHYOPTIONS) @@ -3096,12 +3082,12 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, } case EM_SETOPTIONS: { - /* these flags are equivalent to ES_* counterparts - * ECO_READONLY is already implemented in the code, only requires - * setting the bit to work - */ - DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | - ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | ECO_SELECTIONBAR; + /* these flags are equivalent to ES_* counterparts, except for + * ECO_AUTOWORDSELECTION that doesn't have an ES_* counterpart, + * but is still stored in editor->styleFlags. */ + const DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | + ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | + ECO_SELECTIONBAR | ECO_AUTOWORDSELECTION; DWORD settings = mask & editor->styleFlags; DWORD oldSettings = settings; DWORD changedSettings; @@ -3122,14 +3108,8 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, } changedSettings = oldSettings ^ settings; - if (settings & ECO_AUTOWORDSELECTION) - FIXME("ECO_AUTOWORDSELECTION not implemented yet!\n"); - if (oldSettings ^ settings) { - DWORD dwStyle = GetWindowLongW(editor->hWnd, GWL_STYLE); - editor->styleFlags = (editor->styleFlags & ~mask) | (settings & mask); - SetWindowLongW(editor->hWnd, GWL_STYLE, (dwStyle & ~mask) | (settings & mask)); if (settings & ECO_SELECTIONBAR) { editor->selofs = SELECTIONBAR_WIDTH; @@ -3151,6 +3131,8 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, FIXME("ECO_NOHIDESEL not implemented yet!\n"); if (settings & ECO_WANTRETURN) FIXME("ECO_WANTRETURN not implemented yet!\n"); + if (settings & ECO_AUTOWORDSELECTION) + FIXME("ECO_AUTOWORDSELECTION not implemented yet!\n"); return settings; } @@ -3159,7 +3141,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, ME_InvalidateSelection(editor); ME_SetSelection(editor, wParam, lParam); ME_InvalidateSelection(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_ShowCaret(editor); ME_SendSelChange(editor); return 0; @@ -3193,7 +3175,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, ME_InvalidateSelection(editor); end = ME_SetSelection(editor, range.cpMin, range.cpMax); ME_InvalidateSelection(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_ShowCaret(editor); ME_SendSelChange(editor); @@ -3201,49 +3183,85 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, } case EM_SHOWSCROLLBAR: { - ShowScrollBar(editor->hWnd, wParam, lParam); + DWORD flags; + + switch (wParam) + { + case SB_HORZ: + flags = WS_HSCROLL; + break; + case SB_VERT: + flags = WS_VSCROLL; + break; + case SB_BOTH: + flags = WS_HSCROLL|WS_VSCROLL; + break; + default: + return 0; + } + + if (lParam) + editor->styleFlags |= flags; + else + editor->styleFlags &= flags; + + ITextHost_TxShowScrollBar(editor->texthost, wParam, lParam); return 0; } case EM_SETTEXTEX: { LPWSTR wszText; SETTEXTEX *pStruct = (SETTEXTEX *)wParam; - size_t len; + size_t len = 0; int from, to; ME_Style *style; + BOOL bRtf, bUnicode, bSelection; int oldModify = editor->nModifyStep; if (!pStruct) return 0; + /* If we detect ascii rtf at the start of the string, + * we know it isn't unicode. */ + bRtf = (lParam && (!strncmp((char *)lParam, "{\\rtf", 5) || + !strncmp((char *)lParam, "{\\urtf}", 6))); + bUnicode = !bRtf && pStruct->codepage == 1200; + TRACE("EM_SETTEXTEX - %s, flags %d, cp %d\n", - pStruct->codepage == 1200 ? debugstr_w((LPCWSTR)lParam) : debugstr_a((LPCSTR)lParam), + bUnicode ? debugstr_w((LPCWSTR)lParam) : debugstr_a((LPCSTR)lParam), pStruct->flags, pStruct->codepage); - /* FIXME: make use of pStruct->codepage in the to unicode translation */ - wszText = lParam ? ME_ToUnicode(pStruct->codepage == 1200, (void *)lParam) : NULL; - len = wszText ? lstrlenW(wszText) : 0; - - if (pStruct->flags & ST_SELECTION) { + bSelection = (pStruct->flags & ST_SELECTION) != 0; + if (bSelection) { ME_GetSelection(editor, &from, &to); style = ME_GetSelectionInsertStyle(editor); ME_InternalDeleteText(editor, from, to - from, FALSE); - if (pStruct->codepage != 1200 && lParam && - (!strncmp((char *)lParam, "{\\rtf", 5) || !strncmp((char *)lParam, "{\\urtf}", 6))) - ME_StreamInRTFString(editor, 1, (char *)lParam); - else ME_InsertTextFromCursor(editor, 0, wszText, len, style); - ME_ReleaseStyle(style); - - if (editor->AutoURLDetect_bEnable) ME_UpdateSelectionLinkAttribute(editor); - } - else { + } else { ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor), FALSE); - if (pStruct->codepage != 1200 && lParam && - (!strncmp((char *)lParam, "{\\rtf", 5) || !strncmp((char *)lParam, "{\\urtf}", 6))) - ME_StreamInRTFString(editor, 0, (char *)lParam); - else ME_InsertTextFromCursor(editor, 0, wszText, len, editor->pBuffer->pDefaultStyle); - len = 1; + style = editor->pBuffer->pDefaultStyle; + } - if (editor->AutoURLDetect_bEnable) ME_UpdateLinkAttribute(editor, 0, -1); + if (bRtf) { + ME_StreamInRTFString(editor, bSelection, (char *)lParam); + if (bSelection) { + /* FIXME: The length returned is doesn't include the rtf control + * characters, only the actual text. */ + len = lParam ? strlen((char *)lParam) : 0; + } + } else { + /* FIXME: make use of pStruct->codepage in the to unicode translation */ + wszText = lParam ? ME_ToUnicode(bUnicode, (void *)lParam) : NULL; + len = wszText ? lstrlenW(wszText) : 0; + ME_InsertTextFromCursor(editor, 0, wszText, len, style); + } + + if (bSelection) { + ME_ReleaseStyle(style); + if (editor->AutoURLDetect_bEnable) + ME_UpdateSelectionLinkAttribute(editor); + } else { + len = 1; + if (editor->AutoURLDetect_bEnable) + ME_UpdateLinkAttribute(editor, 0, -1); } ME_CommitUndo(editor); if (!(pStruct->flags & ST_KEEPUNDO)) @@ -3261,7 +3279,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, DeleteObject(editor->hbrBackground); lColor = editor->rgbBackColor; } - else lColor = GetSysColor(COLOR_WINDOW); + else lColor = ITextHost_TxGetSysColor(editor->texthost, COLOR_WINDOW); if (wParam) { @@ -3273,8 +3291,8 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, editor->rgbBackColor = lParam; editor->hbrBackground = CreateSolidBrush(editor->rgbBackColor); } - InvalidateRect(editor->hWnd, NULL, TRUE); - UpdateWindow(editor->hWnd); + ITextHost_TxInvalidateRect(editor->texthost, NULL, TRUE); + ITextHost_TxViewChange(editor->texthost, TRUE); return lColor; } case EM_GETMODIFY: @@ -3290,15 +3308,10 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, } case EM_SETREADONLY: { - LONG winStyle = GetWindowLongW(editor->hWnd, GWL_STYLE); - if (wParam) { + if (wParam) editor->styleFlags |= ES_READONLY; - winStyle |= ES_READONLY; - } else { + else editor->styleFlags &= ~ES_READONLY; - winStyle &= ~ES_READONLY; - } - SetWindowLongW(editor->hWnd, GWL_STYLE, winStyle); return 0; } case EM_SETEVENTMASK: @@ -3459,9 +3472,9 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, if (!wParam) wParam = (WPARAM)GetStockObject(SYSTEM_FONT); GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf); - hDC = GetDC(editor->hWnd); + hDC = ITextHost_TxGetDC(editor->texthost); ME_CharFormatFromLogFont(hDC, &lf, &fmt); - ReleaseDC(editor->hWnd, hDC); + ITextHost_TxReleaseDC(editor->texthost, hDC); ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), &fmt); ME_SetDefaultCharFormat(editor, &fmt); @@ -3630,12 +3643,11 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, return 0; while (nCharsLeft && (run = ME_FindItemFwd(run, diRunOrStartRow)) - && !(run->member.run.nFlags & MERF_ENDPARA)) + && run->type == diRun) { unsigned int nCopy; ME_String *strText; - if (run->type != diRun) - break; + strText = run->member.run.strText; nCopy = min(nCharsLeft, strText->nLen); @@ -3651,31 +3663,12 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, /* append line termination, space allowing */ if (nCharsLeft > 0) { - if (run && (run->member.run.nFlags & MERF_ENDPARA)) - { - int i; - /* Write as many \r as encoded in end-of-paragraph, space allowing */ - for (i = 0; i < run->member.run.nCR && nCharsLeft > 0; i++, nCharsLeft--) - { - *((WCHAR *)dest) = '\r'; - dest += unicode ? sizeof(WCHAR) : 1; - } - /* Write as many \n as encoded in end-of-paragraph, space allowing */ - for (i = 0; i < run->member.run.nLF && nCharsLeft > 0; i++, nCharsLeft--) - { - *((WCHAR *)dest) = '\n'; - dest += unicode ? sizeof(WCHAR) : 1; - } - } - if (nCharsLeft > 0) - { - if (unicode) - *((WCHAR *)dest) = '\0'; - else - *dest = '\0'; - nCharsLeft--; - wroteNull = TRUE; - } + if (unicode) + *((WCHAR *)dest) = '\0'; + else + *dest = '\0'; + nCharsLeft--; + wroteNull = TRUE; } TRACE("EM_GETLINE: got %u characters\n", nMaxChars - nCharsLeft); @@ -3701,8 +3694,10 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, last_para = ME_FindItemBack(item, diRun); assert(last_para); assert(last_para->member.run.nFlags & MERF_ENDPARA); - if (editor->bEmulateVersion10 && prev_para && last_para->member.run.nCharOfs == 0 - && prev_para->member.run.nCR == 1 && prev_para->member.run.nLF == 0) + if (editor->bEmulateVersion10 && prev_para && + last_para->member.run.nCharOfs == 0 && + prev_para->member.run.strText->nLen == 1 && + prev_para->member.run.strText->szData[0] == '\r') { /* In 1.0 emulation, the last solitary \r at the very end of the text (if one exists) is NOT a line break. @@ -3748,7 +3743,8 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, { ME_DisplayItem *item, *item_end; int nChars = 0, nThisLineOfs = 0, nNextLineOfs = 0; - + ME_Cursor cursor; + if (wParam > ME_GetTextLength(editor)) return 0; if (wParam == -1) @@ -3756,8 +3752,8 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, FIXME("EM_LINELENGTH: returning number of unselected characters on lines with selection unsupported.\n"); return 0; } - item = ME_FindItemAtOffset(editor, diRun, wParam, NULL); - item = ME_RowStart(item); + ME_CursorFromCharOfs(editor, wParam, &cursor); + item = ME_RowStart(cursor.pRun); nThisLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item, diRun), 0); item_end = ME_FindItemFwd(item, diStartRowOrParagraphOrEnd); if (item_end->type == diStartRow) @@ -3772,7 +3768,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, assert(endPara); assert(endPara->type == diRun); assert(endPara->member.run.nFlags & MERF_ENDPARA); - nNextLineOfs -= endPara->member.run.nCR + endPara->member.run.nLF; + nNextLineOfs -= endPara->member.run.strText->nLen; } nChars = nNextLineOfs - nThisLineOfs; TRACE("EM_LINELENGTH(%ld)==%d\n",wParam, nChars); @@ -3888,8 +3884,13 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, si.nMax = (si.fMask & SIF_DISABLENOSCROLL) ? 1 : 0; si.nMin = 0; si.nPage = 0; - SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE); - SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE); + if (editor->hWnd) { + SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE); + SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE); + } else { + ITextHost_TxSetScrollRange(editor->texthost, SB_VERT, si.nMin, si.nMax, TRUE); + ITextHost_TxSetScrollRange(editor->texthost, SB_HORZ, si.nMin, si.nMax, TRUE); + } ME_CommitUndo(editor); ME_WrapMarkedParagraphs(editor); @@ -3910,10 +3911,10 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, if ((editor->nEventMask & ENM_MOUSEEVENTS) && !ME_FilterEvent(editor, msg, &wParam, &lParam)) return 0; - SetFocus(editor->hWnd); + ITextHost_TxSetFocus(editor->texthost); ME_LButtonDown(editor, (short)LOWORD(lParam), (short)HIWORD(lParam), ME_CalculateClickCount(editor, msg, wParam, lParam)); - SetCapture(editor->hWnd); + ITextHost_TxSetCapture(editor->texthost, TRUE); editor->bMouseCaptured = TRUE; ME_LinkNotify(editor,msg,wParam,lParam); if (!ME_SetCursor(editor)) goto do_default; @@ -3932,7 +3933,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, break; case WM_LBUTTONUP: if (editor->bMouseCaptured) { - ReleaseCapture(); + ITextHost_TxSetCapture(editor->texthost, FALSE); editor->bMouseCaptured = FALSE; } if (editor->nSelectionType == stDocument) @@ -3957,44 +3958,6 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, if (!ME_ShowContextMenu(editor, (short)LOWORD(lParam), (short)HIWORD(lParam))) goto do_default; break; - case WM_PAINT: - { - HDC hDC; - RECT rc; - PAINTSTRUCT ps; - - hDC = BeginPaint(editor->hWnd, &ps); - /* Erase area outside of the formatting rectangle */ - if (ps.rcPaint.top < editor->rcFormat.top) - { - rc = ps.rcPaint; - rc.bottom = editor->rcFormat.top; - FillRect(hDC, &rc, editor->hbrBackground); - ps.rcPaint.top = editor->rcFormat.top; - } - if (ps.rcPaint.bottom > editor->rcFormat.bottom) { - rc = ps.rcPaint; - rc.top = editor->rcFormat.bottom; - FillRect(hDC, &rc, editor->hbrBackground); - ps.rcPaint.bottom = editor->rcFormat.bottom; - } - if (ps.rcPaint.left < editor->rcFormat.left) { - rc = ps.rcPaint; - rc.right = editor->rcFormat.left; - FillRect(hDC, &rc, editor->hbrBackground); - ps.rcPaint.left = editor->rcFormat.left; - } - if (ps.rcPaint.right > editor->rcFormat.right) { - rc = ps.rcPaint; - rc.left = editor->rcFormat.right; - FillRect(hDC, &rc, editor->hbrBackground); - ps.rcPaint.right = editor->rcFormat.right; - } - - ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint); - EndPaint(editor->hWnd, &ps); - } - break; case WM_SETFOCUS: editor->bHaveFocus = TRUE; ME_ShowCaret(editor); @@ -4006,16 +3969,6 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, ME_HideCaret(editor); ME_SendOldNotify(editor, EN_KILLFOCUS); return 0; - case WM_ERASEBKGND: - { - HDC hDC = (HDC)wParam; - RECT rc; - if (GetUpdateRect(editor->hWnd,&rc,TRUE)) - { - FillRect(hDC, &rc, editor->hbrBackground); - } - return 1; - } case WM_COMMAND: TRACE("editor wnd command = %d\n", LOWORD(wParam)); return 0; @@ -4106,7 +4059,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, origNPos = editor->vert_si.nPos; lineHeight = 24; - if (editor && editor->pBuffer && editor->pBuffer->pDefaultStyle) + if (editor->pBuffer && editor->pBuffer->pDefaultStyle) lineHeight = editor->pBuffer->pDefaultStyle->tm.tmHeight; if (lineHeight <= 0) lineHeight = 24; @@ -4199,12 +4152,12 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, { if (lParam) { - DWORD exstyle = GetWindowLongW(editor->hWnd, GWL_EXSTYLE); - int border = (exstyle & WS_EX_CLIENTEDGE) ? 1 : 0; + int border = 0; RECT clientRect; RECT *rc = (RECT *)lParam; - GetClientRect(editor->hWnd, &clientRect); + border = editor->exStyleFlags & WS_EX_CLIENTEDGE ? 1 : 0; + ITextHost_TxGetClientRect(editor->texthost, &clientRect); if (wParam == 0) { editor->rcFormat.top = max(0, rc->top - border); @@ -4243,7 +4196,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, { RECT clientRect; - GetClientRect(editor->hWnd, &clientRect); + ITextHost_TxGetClientRect(editor->texthost, &clientRect); if (editor->bDefaultFormatRect) { ME_SetDefaultFormatRect(editor); } else { @@ -4273,7 +4226,7 @@ static LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, HIMC hIMC; ME_Style *style = ME_GetInsertStyle(editor, 0); - hIMC = ImmGetContext(editor->hWnd); + hIMC = ITextHost_TxImmGetContext(editor->texthost); ME_DeleteSelection(editor); ME_CommitUndo(editor); ME_SaveTempStyle(editor); @@ -4400,7 +4353,7 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, { ME_TextEditor *editor; HRESULT hresult; - LRESULT lresult; + LRESULT lresult = 0; TRACE("enter hwnd %p msg %04x (%s) %lx %lx, unicode %d\n", hWnd, msg, get_msg_name(msg), wParam, lParam, unicode); @@ -4411,10 +4364,11 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, if (msg == WM_NCCREATE) { CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam; + ITextHost *texthost; + TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style); - editor = ME_MakeEditor(hWnd, FALSE); - SetWindowLongPtrW(hWnd, 0, (LONG_PTR)editor); - return TRUE; + texthost = ME_CreateTextHost(hWnd, FALSE); + return texthost != NULL; } else if (msg != WM_NCDESTROY) { @@ -4423,7 +4377,81 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, } } - lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); + switch (msg) + { + case WM_PAINT: + { + HDC hDC; + RECT rc; + PAINTSTRUCT ps; + + hDC = BeginPaint(editor->hWnd, &ps); + /* Erase area outside of the formatting rectangle */ + if (ps.rcPaint.top < editor->rcFormat.top) + { + rc = ps.rcPaint; + rc.bottom = editor->rcFormat.top; + FillRect(hDC, &rc, editor->hbrBackground); + ps.rcPaint.top = editor->rcFormat.top; + } + if (ps.rcPaint.bottom > editor->rcFormat.bottom) { + rc = ps.rcPaint; + rc.top = editor->rcFormat.bottom; + FillRect(hDC, &rc, editor->hbrBackground); + ps.rcPaint.bottom = editor->rcFormat.bottom; + } + if (ps.rcPaint.left < editor->rcFormat.left) { + rc = ps.rcPaint; + rc.right = editor->rcFormat.left; + FillRect(hDC, &rc, editor->hbrBackground); + ps.rcPaint.left = editor->rcFormat.left; + } + if (ps.rcPaint.right > editor->rcFormat.right) { + rc = ps.rcPaint; + rc.left = editor->rcFormat.right; + FillRect(hDC, &rc, editor->hbrBackground); + ps.rcPaint.right = editor->rcFormat.right; + } + + ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint); + EndPaint(editor->hWnd, &ps); + return 0; + } + case WM_ERASEBKGND: + { + HDC hDC = (HDC)wParam; + RECT rc; + + if (GetUpdateRect(editor->hWnd, &rc, TRUE)) + FillRect(hDC, &rc, editor->hbrBackground); + return 1; + } + case EM_SETOPTIONS: + { + DWORD dwStyle; + const DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | + ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | + ECO_SELECTIONBAR; + lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); + dwStyle = GetWindowLongW(hWnd, GWL_STYLE); + dwStyle = (dwStyle & ~mask) | (lresult & mask); + SetWindowLongW(hWnd, GWL_STYLE, dwStyle); + return lresult; + } + case EM_SETREADONLY: + { + DWORD dwStyle; + lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); + dwStyle = GetWindowLongW(hWnd, GWL_STYLE); + dwStyle &= ~ES_READONLY; + if (wParam) + dwStyle |= ES_READONLY; + SetWindowLongW(hWnd, GWL_STYLE, dwStyle); + return lresult; + } + default: + lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); + } if (hresult == S_FALSE) lresult = DefWindowProcW(hWnd, msg, wParam, lParam); @@ -4465,21 +4493,19 @@ LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM { if (msg == WM_NCCREATE && !GetWindowLongPtrW(hWnd, 0)) { - ME_TextEditor *editor; + ITextHost *texthost; CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam; TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style); - editor = ME_MakeEditor(hWnd, TRUE); - SetWindowLongPtrW(hWnd, 0, (LONG_PTR)editor); - return TRUE; + texthost = ME_CreateTextHost(hWnd, TRUE); + return texthost != NULL; } return RichEditANSIWndProc(hWnd, msg, wParam, lParam); } void ME_SendOldNotify(ME_TextEditor *editor, int nCode) { - HWND hWnd = editor->hWnd; - SendMessageA(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetWindowLongW(hWnd, GWLP_ID), nCode), (LPARAM)hWnd); + ITextHost_TxNotify(editor->texthost, nCode, NULL); } int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to) @@ -4499,108 +4525,64 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to) } -int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF) +int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, + int nChars, int bCRLF) { - ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); - int nWritten = 0; + ME_DisplayItem *pRun; + int nOffset, nWritten = 0; WCHAR *pStart = buffer; - - if (!item) { - *buffer = 0; - return 0; - } - + + ME_RunOfsFromCharOfs(editor, nStart, &pRun, &nOffset); + /* bCRLF flag is only honored in 2.0 and up. 1.0 must always return text verbatim */ if (editor->bEmulateVersion10) bCRLF = 0; - if (nStart) + while (nChars && pRun) { - int nLen = ME_StrLen(item->member.run.strText) - nStart; - if (nLen > nChars) - nLen = nChars; - CopyMemory(buffer, item->member.run.strText->szData + nStart, sizeof(WCHAR)*nLen); - nChars -= nLen; - nWritten += nLen; - buffer += nLen; - if (!nChars) { - *buffer = 0; - return nWritten; - } - nStart = 0; - item = ME_FindItemFwd(item, diRun); - } - - while(nChars && item) - { - int nLen = ME_StrLen(item->member.run.strText); - if (item->member.run.nFlags & MERF_ENDPARA) - nLen = item->member.run.nCR + item->member.run.nLF; - if (nLen > nChars) - nLen = nChars; + int nLen; - if (item->member.run.nFlags & MERF_ENDCELL && - item->member.run.nFlags & MERF_ENDPARA) + if (pRun->member.run.nFlags & MERF_ENDCELL && + pRun->member.run.nFlags & MERF_ENDPARA) { *buffer = '\t'; - } - else if (item->member.run.nFlags & MERF_ENDPARA) - { - if (!ME_FindItemFwd(item, diRun)) + nLen = 1; + } else if (pRun->member.run.nFlags & MERF_ENDPARA) { + if (!ME_FindItemFwd(pRun, diRun)) { /* No '\r' is appended to the last paragraph. */ nLen = 0; - else if (bCRLF && nChars == 1) { + } else if (bCRLF && nChars == 1) { nLen = 0; nChars = 0; } else { + WCHAR cr_lf[] = {'\r', '\n', 0}; + WCHAR *szData; + if (bCRLF) { - /* richedit 2.0 case - actual line-break is \r but should report \r\n */ - if (ME_GetParagraph(item)->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND)) - assert(nLen == 2); - else - assert(nLen == 1); - *buffer++ = '\r'; - *buffer = '\n'; /* Later updated by nLen==1 at the end of the loop */ - if (nLen == 1) - nWritten++; - else - buffer--; - } - else - { - int i, j; - - /* richedit 2.0 verbatim has only \r. richedit 1.0 should honor encodings */ - i = 0; - while (nChars - i > 0 && i < item->member.run.nCR) - { - buffer[i] = '\r'; i++; - } - j = 0; - while (nChars - i - j > 0 && j < item->member.run.nLF) - { - buffer[i+j] = '\n'; j++; - } + nLen = 2; + szData = cr_lf; + } else { + nLen = pRun->member.run.strText->nLen; + szData = pRun->member.run.strText->szData; } + nLen = min(nChars, nLen - nOffset); + CopyMemory(buffer, szData + nOffset, sizeof(WCHAR) * nLen); } + } else { + nLen = min(nChars, pRun->member.run.strText->nLen - nOffset); + CopyMemory(buffer, pRun->member.run.strText->szData + nOffset, + sizeof(WCHAR) * nLen); } - else - CopyMemory(buffer, item->member.run.strText->szData, sizeof(WCHAR)*nLen); nChars -= nLen; nWritten += nLen; - buffer += nLen; - - if (!nChars) - { - TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart); - *buffer = 0; - return nWritten; - } - item = ME_FindItemFwd(item, diRun); + buffer += nLen; + nOffset = 0; + + pRun = ME_FindItemFwd(pRun, diRun); } *buffer = 0; TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart); - return nWritten; + return nWritten; } static BOOL ME_RegisterEditorClass(HINSTANCE hInstance) @@ -4738,7 +4720,7 @@ static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor, int sel_min, int sel_ TRACE("sel_min = %d sel_max = %d\n", sel_min, sel_max); *candidate_min = *candidate_max = -1; - item = ME_FindItemAtOffset(editor, diRun, sel_min, &nStart); + ME_RunOfsFromCharOfs(editor, sel_min, &item, &nStart); if (!item) return FALSE; TRACE("nStart = %d\n", nStart); para = ME_GetParagraph(item); diff --git a/reactos/dll/win32/riched20/editor.h b/reactos/dll/win32/riched20/editor.h index d052d5d37fb..a412389a369 100644 --- a/reactos/dll/win32/riched20/editor.h +++ b/reactos/dll/win32/riched20/editor.h @@ -71,7 +71,6 @@ void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048]); void ME_DumpStyle(ME_Style *s); CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from); void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from); -CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from); void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from); void ME_CopyCharFormat(CHARFORMAT2W *pDest, const CHARFORMAT2W *pSrc); /* only works with 2W structs */ void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt); /* ditto */ @@ -89,7 +88,6 @@ void ME_DumpDocument(ME_TextBuffer *buffer); const char *ME_GetDITypeName(ME_DIType type); /* string.c */ -int ME_GetOptimalBuffer(int nLen); ME_String *ME_MakeString(LPCWSTR szText); ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars); ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars); @@ -205,7 +203,7 @@ ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor); /* context.c */ void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC); -void ME_DestroyContext(ME_Context *c, HWND release); +void ME_DestroyContext(ME_Context *c); /* wrap.c */ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor); @@ -216,7 +214,7 @@ void ME_SendRequestResize(ME_TextEditor *editor, BOOL force); ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run); void ME_GetSelectionParas(ME_TextEditor *editor, ME_DisplayItem **para, ME_DisplayItem **para_end); void ME_MakeFirstParagraph(ME_TextEditor *editor); -ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, int numCR, int numLF, int paraFlags); +ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, ME_String *eol_str, int paraFlags); ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, BOOL keepFirstParaFormat); void ME_DumpParaStyle(ME_Paragraph *s); @@ -235,7 +233,6 @@ void ME_RewrapRepaint(ME_TextEditor *editor); void ME_UpdateRepaint(ME_TextEditor *editor); void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor); void ME_InvalidateSelection(ME_TextEditor *editor); -void ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor); BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator); int ME_twips2pointsX(ME_Context *c, int x); int ME_twips2pointsY(ME_Context *c, int y); @@ -263,9 +260,11 @@ void ME_CopyReObject(REOBJECT* dst, const REOBJECT* src); void ME_DeleteReObject(REOBJECT* reo); /* editor.c */ +ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10); +LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, + LPARAM lParam, BOOL unicode, HRESULT* phresult); void ME_SendOldNotify(ME_TextEditor *editor, int nCode); int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF); -ME_DisplayItem *ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset); void ME_RTFCharAttrHook(struct _RTF_Info *info); void ME_RTFParAttrHook(struct _RTF_Info *info); void ME_RTFTblAttrHook(struct _RTF_Info *info); @@ -291,6 +290,54 @@ void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor); struct RTFTable *ME_MakeTableDef(ME_TextEditor *editor); void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef); +/* txthost.c */ +ITextHost *ME_CreateTextHost(HWND hwnd, BOOL bEmulateVersion10); +#ifdef __i386__ /* Use wrappers to perform thiscall on i386 */ +#define TXTHOST_VTABLE(This) (&itextHostStdcallVtbl) +#else /* __i386__ */ +#define TXTHOST_VTABLE(This) (This)->lpVtbl +#endif /* __i386__ */ + /*** ITextHost methods ***/ +#define ITextHost_TxGetDC(This) TXTHOST_VTABLE(This)->TxGetDC(This) +#define ITextHost_TxReleaseDC(This,a) TXTHOST_VTABLE(This)->TxReleaseDC(This,a) +#define ITextHost_TxShowScrollBar(This,a,b) TXTHOST_VTABLE(This)->TxShowScrollBar(This,a,b) +#define ITextHost_TxEnableScrollBar(This,a,b) TXTHOST_VTABLE(This)->TxEnableScrollBar(This,a,b) +#define ITextHost_TxSetScrollRange(This,a,b,c,d) TXTHOST_VTABLE(This)->TxSetScrollRange(This,a,b,c,d) +#define ITextHost_TxSetScrollPos(This,a,b,c) TXTHOST_VTABLE(This)->TxSetScrollPos(This,a,b,c) +#define ITextHost_TxInvalidateRect(This,a,b) TXTHOST_VTABLE(This)->TxInvalidateRect(This,a,b) +#define ITextHost_TxViewChange(This,a) TXTHOST_VTABLE(This)->TxViewChange(This,a) +#define ITextHost_TxCreateCaret(This,a,b,c) TXTHOST_VTABLE(This)->TxCreateCaret(This,a,b,c) +#define ITextHost_TxShowCaret(This,a) TXTHOST_VTABLE(This)->TxShowCaret(This,a) +#define ITextHost_TxSetCaretPos(This,a,b) TXTHOST_VTABLE(This)->TxSetCaretPos(This,a,b) +#define ITextHost_TxSetTimer(This,a,b) TXTHOST_VTABLE(This)->TxSetTimer(This,a,b) +#define ITextHost_TxKillTimer(This,a) TXTHOST_VTABLE(This)->TxKillTimer(This,a) +#define ITextHost_TxScrollWindowEx(This,a,b,c,d,e,f,g) TXTHOST_VTABLE(This)->TxScrollWindowEx(This,a,b,c,d,e,f,g) +#define ITextHost_TxSetCapture(This,a) TXTHOST_VTABLE(This)->TxSetCapture(This,a) +#define ITextHost_TxSetFocus(This) TXTHOST_VTABLE(This)->TxSetFocus(This) +#define ITextHost_TxSetCursor(This,a,b) TXTHOST_VTABLE(This)->TxSetCursor(This,a,b) +#define ITextHost_TxScreenToClient(This,a) TXTHOST_VTABLE(This)->TxScreenToClient(This,a) +#define ITextHost_TxClientToScreen(This,a) TXTHOST_VTABLE(This)->TxClientToScreen(This,a) +#define ITextHost_TxActivate(This,a) TXTHOST_VTABLE(This)->TxActivate(This,a) +#define ITextHost_TxDeactivate(This,a) TXTHOST_VTABLE(This)->TxDeactivate(This,a) +#define ITextHost_TxGetClientRect(This,a) TXTHOST_VTABLE(This)->TxGetClientRect(This,a) +#define ITextHost_TxGetViewInset(This,a) TXTHOST_VTABLE(This)->TxGetViewInset(This,a) +#define ITextHost_TxGetCharFormat(This,a) TXTHOST_VTABLE(This)->TxGetCharFormat(This,a) +#define ITextHost_TxGetParaFormat(This,a) TXTHOST_VTABLE(This)->TxGetParaFormat(This,a) +#define ITextHost_TxGetSysColor(This,a) TXTHOST_VTABLE(This)->TxGetSysColor(This,a) +#define ITextHost_TxGetBackStyle(This,a) TXTHOST_VTABLE(This)->TxGetBackStyle(This,a) +#define ITextHost_TxGetMaxLength(This,a) TXTHOST_VTABLE(This)->TxGetMaxLength(This,a) +#define ITextHost_TxGetScrollBars(This,a) TXTHOST_VTABLE(This)->TxGetScrollBars(This,a) +#define ITextHost_TxGetPasswordChar(This,a) TXTHOST_VTABLE(This)->TxGetPasswordChar(This,a) +#define ITextHost_TxGetAcceleratorPos(This,a) TXTHOST_VTABLE(This)->TxGetAcceleratorPos(This,a) +#define ITextHost_TxGetExtent(This,a) TXTHOST_VTABLE(This)->TxGetExtent(This,a) +#define ITextHost_OnTxCharFormatChange(This,a) TXTHOST_VTABLE(This)->OnTxCharFormatChange(This,a) +#define ITextHost_OnTxParaFormatChange(This,a) TXTHOST_VTABLE(This)->OnTxParaFormatChange(This,a) +#define ITextHost_TxGetPropertyBits(This,a,b) TXTHOST_VTABLE(This)->TxGetPropertyBits(This,a,b) +#define ITextHost_TxNotify(This,a,b) TXTHOST_VTABLE(This)->TxNotify(This,a,b) +#define ITextHost_TxImmGetContext(This) TXTHOST_VTABLE(This)->TxImmGetContext(This) +#define ITextHost_TxImmReleaseContext(This,a) TXTHOST_VTABLE(This)->TxImmReleaseContext(This,a) +#define ITextHost_TxGetSelectionBarWidth(This,a) TXTHOST_VTABLE(This)->TxGetSelectionBarWidth(This,a) + /* undo.c */ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi); void ME_CommitUndo(ME_TextEditor *editor); diff --git a/reactos/dll/win32/riched20/editstr.h b/reactos/dll/win32/riched20/editstr.h index d289509454b..a6450753712 100644 --- a/reactos/dll/win32/riched20/editstr.h +++ b/reactos/dll/win32/riched20/editstr.h @@ -44,9 +44,15 @@ #include #include #include +#include "imm.h" +#include #include "wine/debug.h" +#ifdef __i386__ +extern struct ITextHostVtbl itextHostStdcallVtbl; +#endif /* __i386__ */ + typedef struct tagME_String { WCHAR *szData; @@ -156,7 +162,6 @@ typedef struct tagME_Run int nAscent, nDescent; /* pixels above/below baseline */ POINT pt; /* relative to para's position */ REOBJECT *ole_obj; /* FIXME: should be a union with strText (at least) */ - int nCR; int nLF; /* for MERF_ENDPARA: number of \r and \n characters encoded by run */ } ME_Run; typedef struct tagME_Document { @@ -246,7 +251,7 @@ typedef struct tagME_UndoItem { ME_DisplayItem di; int nStart, nLen; - int nCR, nLF; /* used by diUndoSplitParagraph */ + ME_String *eol_str; /* used by diUndoSplitParagraph */ } ME_UndoItem; typedef struct tagME_TextBuffer @@ -327,10 +332,12 @@ typedef struct tagME_FontCacheItem typedef struct tagME_TextEditor { HWND hWnd; + ITextHost *texthost; BOOL bEmulateVersion10; ME_TextBuffer *pBuffer; ME_Cursor *pCursors; DWORD styleFlags; + DWORD exStyleFlags; int nCursors; SIZE sizeWindow; int nTotalLength, nLastTotalLength; @@ -355,7 +362,6 @@ typedef struct tagME_TextEditor RECT rcFormat; BOOL bDefaultFormatRect; BOOL bWordWrap; - int nInvalidOfs; int nTextLimit; EDITWORDBREAKPROCW pfnWordBreak; LPRICHEDITOLECALLBACK lpOleCallback; diff --git a/reactos/dll/win32/riched20/list.c b/reactos/dll/win32/riched20/list.c index 804fd608bc0..f9a903205b9 100644 --- a/reactos/dll/win32/riched20/list.c +++ b/reactos/dll/win32/riched20/list.c @@ -191,10 +191,8 @@ void ME_DumpDocument(ME_TextBuffer *buffer) TRACE(" - StartRow\n"); break; case diRun: - TRACE(" - Run(\"%s\", %d)\n", debugstr_w(pItem->member.run.strText->szData), - pItem->member.run.nCharOfs); - if (pItem->member.run.nFlags & MERF_ENDPARA) - TRACE(" - Paragraph end: %d CR, %d LF\n", pItem->member.run.nCR, pItem->member.run.nLF); + TRACE(" - Run(\"%s\", %d, flags=%x)\n", debugstr_w(pItem->member.run.strText->szData), + pItem->member.run.nCharOfs, pItem->member.run.nFlags); break; case diTextEnd: TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs); diff --git a/reactos/dll/win32/riched20/paint.c b/reactos/dll/win32/riched20/paint.c index bc0441bcdd8..30548feaabb 100644 --- a/reactos/dll/win32/riched20/paint.c +++ b/reactos/dll/win32/riched20/paint.c @@ -74,15 +74,12 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT * if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT)) { /* Draw the pargraph if any of the paragraph is in the update region. */ - BOOL bPaint = (rcUpdate == NULL); - if (rcUpdate) - bPaint = ys < rcUpdate->bottom && ye > rcUpdate->top; - if (bPaint) + if (ys < rcUpdate->bottom && ye > rcUpdate->top) { ME_DrawParagraph(&c, item); /* Clear the repaint flag if the whole paragraph is in the * update region. */ - if (!rcUpdate || (rcUpdate->top <= ys && rcUpdate->bottom >= ye)) + if (rcUpdate->top <= ys && rcUpdate->bottom >= ye) item->member.para.nFlags &= ~MEPF_REPAINT; } } @@ -116,11 +113,13 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, const RECT * ME_SendRequestResize(editor, FALSE); editor->nLastTotalLength = editor->nTotalLength; editor->nLastTotalWidth = editor->nTotalWidth; - ME_DestroyContext(&c, NULL); SelectClipRgn(hDC, oldRgn); if (oldRgn) DeleteObject(oldRgn); + + c.hDC = NULL; + ME_DestroyContext(&c); } void ME_Repaint(ME_TextEditor *editor) @@ -130,11 +129,9 @@ void ME_Repaint(ME_TextEditor *editor) ME_UpdateScrollBar(editor); FIXME("ME_Repaint had to call ME_WrapMarkedParagraphs\n"); } - if (!IsWindowVisible(editor->hWnd)) - return; if (!editor->bEmulateVersion10 || (editor->nEventMask & ENM_UPDATE)) ME_SendOldNotify(editor, EN_UPDATE); - UpdateWindow(editor->hWnd); + ITextHost_TxViewChange(editor->texthost, TRUE); } void ME_UpdateRepaint(ME_TextEditor *editor) @@ -232,7 +229,8 @@ static void ME_HighlightSpace(ME_Context *c, int x, int y, LPCWSTR szText, rect.top = ymin; rect.right = x + selWidth; rect.bottom = ymin + cy; - hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); + hBrush = CreateSolidBrush(ITextHost_TxGetSysColor(c->editor->texthost, + COLOR_HIGHLIGHT)); FillRect(hDC, &rect, hBrush); DeleteObject(hBrush); } @@ -274,7 +272,7 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, if ((s->fmt.dwMask & CFM_LINK) && (s->fmt.dwEffects & CFE_LINK)) rgb = RGB(0,0,255); else if ((s->fmt.dwMask & CFM_COLOR) && (s->fmt.dwEffects & CFE_AUTOCOLOR)) - rgb = GetSysColor(COLOR_WINDOWTEXT); + rgb = ITextHost_TxGetSysColor(c->editor->texthost, COLOR_WINDOWTEXT); else rgb = s->fmt.crTextColor; @@ -351,8 +349,10 @@ static void ME_DrawTextWithStyle(ME_Context *c, int x, int y, LPCWSTR szText, dim.bottom = ymin + cy; dim.left = xSelStart; dim.right = xSelEnd; - SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - rgbBackOld = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); + SetTextColor(hDC, ITextHost_TxGetSysColor(c->editor->texthost, + COLOR_HIGHLIGHTTEXT)); + rgbBackOld = SetBkColor(hDC, ITextHost_TxGetSysColor(c->editor->texthost, + COLOR_HIGHLIGHT)); ExtTextOutW(hDC, xSelStart, y-yOffset, ETO_OPAQUE, &dim, szText+nSelFrom, nSelTo-nSelFrom, lpDx); if (hPen) @@ -418,7 +418,6 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa ME_GetSelection(c->editor, &nSelFrom, &nSelTo); /* Draw selected end-of-paragraph mark */ - /* you can always comment it out if you need visible paragraph marks */ if (run->nFlags & MERF_ENDPARA) { if (runofs >= nSelFrom && runofs < nSelTo) @@ -625,7 +624,8 @@ static void ME_DrawParaDecoration(ME_Context* c, ME_Paragraph* para, int y, RECT POINT pt; if (para->pFmt->wBorders & 64) /* autocolor */ - pencr = GetSysColor(COLOR_WINDOWTEXT); + pencr = ITextHost_TxGetSysColor(c->editor->texthost, + COLOR_WINDOWTEXT); else pencr = pen_colors[(para->pFmt->wBorders >> 12) & 0xF]; @@ -1032,14 +1032,13 @@ static void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) void ME_ScrollAbs(ME_TextEditor *editor, int x, int y) { - LONG winStyle; BOOL bScrollBarIsVisible, bScrollBarWillBeVisible; int scrollX = 0, scrollY = 0; if (editor->horz_si.nPos != x) { x = min(x, editor->horz_si.nMax); x = max(x, editor->horz_si.nMin); - SetScrollPos(editor->hWnd, SB_HORZ, x, TRUE); + ITextHost_TxSetScrollPos(editor->texthost, SB_HORZ, x, TRUE); scrollX = editor->horz_si.nPos - x; editor->horz_si.nPos = x; } @@ -1047,32 +1046,39 @@ void ME_ScrollAbs(ME_TextEditor *editor, int x, int y) if (editor->vert_si.nPos != y) { y = min(y, editor->vert_si.nMax - (int)editor->vert_si.nPage); y = max(y, editor->vert_si.nMin); - SetScrollPos(editor->hWnd, SB_VERT, y, TRUE); + ITextHost_TxSetScrollPos(editor->texthost, SB_VERT, y, TRUE); scrollY = editor->vert_si.nPos - y; editor->vert_si.nPos = y; } if (abs(scrollX) > editor->sizeWindow.cx || abs(scrollY) > editor->sizeWindow.cy) - InvalidateRect(editor->hWnd, NULL, TRUE); + ITextHost_TxInvalidateRect(editor->texthost, NULL, TRUE); else - ScrollWindowEx(editor->hWnd, scrollX, scrollY, &editor->rcFormat, - &editor->rcFormat, NULL, NULL, SW_INVALIDATE); + ITextHost_TxScrollWindowEx(editor->texthost, scrollX, scrollY, + &editor->rcFormat, &editor->rcFormat, + NULL, NULL, SW_INVALIDATE); ME_Repaint(editor); - winStyle = GetWindowLongW(editor->hWnd, GWL_STYLE); - bScrollBarIsVisible = (winStyle & WS_HSCROLL) != 0; - bScrollBarWillBeVisible = (editor->nTotalWidth > editor->sizeWindow.cx) - || (editor->styleFlags & ES_DISABLENOSCROLL); - if (bScrollBarIsVisible != bScrollBarWillBeVisible) - ShowScrollBar(editor->hWnd, SB_HORZ, bScrollBarWillBeVisible); - - bScrollBarIsVisible = (winStyle & WS_VSCROLL) != 0; - bScrollBarWillBeVisible = (editor->nTotalLength > editor->sizeWindow.cy) - || (editor->styleFlags & ES_DISABLENOSCROLL); - if (bScrollBarIsVisible != bScrollBarWillBeVisible) - ShowScrollBar(editor->hWnd, SB_VERT, bScrollBarWillBeVisible); + if (editor->hWnd) + { + LONG winStyle = GetWindowLongW(editor->hWnd, GWL_STYLE); + bScrollBarIsVisible = (winStyle & WS_HSCROLL) != 0; + bScrollBarWillBeVisible = (editor->nTotalWidth > editor->sizeWindow.cx + && (editor->styleFlags & WS_HSCROLL)) + || (editor->styleFlags & ES_DISABLENOSCROLL); + if (bScrollBarIsVisible != bScrollBarWillBeVisible) + ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, + bScrollBarWillBeVisible); + bScrollBarIsVisible = (winStyle & WS_VSCROLL) != 0; + bScrollBarWillBeVisible = (editor->nTotalLength > editor->sizeWindow.cy + && (editor->styleFlags & WS_VSCROLL)) + || (editor->styleFlags & ES_DISABLENOSCROLL); + if (bScrollBarIsVisible != bScrollBarWillBeVisible) + ITextHost_TxShowScrollBar(editor->texthost, SB_VERT, + bScrollBarWillBeVisible); + } ME_UpdateScrollBar(editor); } @@ -1146,15 +1152,27 @@ void ME_UpdateScrollBar(ME_TextEditor *editor) editor->horz_si.nMin = si.nMin; editor->horz_si.nMax = si.nMax; editor->horz_si.nPage = si.nPage; - if (bScrollBarWillBeVisible || bScrollBarWasVisible) - SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE); + if (bScrollBarWillBeVisible || bScrollBarWasVisible) { + if (editor->hWnd) { + SetScrollInfo(editor->hWnd, SB_HORZ, &si, TRUE); + } else { + ITextHost_TxSetScrollRange(editor->texthost, SB_HORZ, si.nMin, si.nMax, FALSE); + ITextHost_TxSetScrollPos(editor->texthost, SB_HORZ, si.nPos, TRUE); + } + } } - if (si.fMask & SIF_DISABLENOSCROLL) + if (si.fMask & SIF_DISABLENOSCROLL) { bScrollBarWillBeVisible = TRUE; + } else if (!(editor->styleFlags & WS_HSCROLL)) { + /* SetScrollInfo or SetScrollRange may cause the scrollbar to be + * shown, so hide the scrollbar if necessary. */ + bScrollBarWasVisible = bScrollBarWillBeVisible; + bScrollBarWillBeVisible = FALSE; + } if (bScrollBarWasVisible != bScrollBarWillBeVisible) - ShowScrollBar(editor->hWnd, SB_HORZ, bScrollBarWillBeVisible); + ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, bScrollBarWillBeVisible); /* Update vertical scrollbar */ bScrollBarWasVisible = editor->vert_si.nMax > editor->vert_si.nPage; @@ -1180,15 +1198,28 @@ void ME_UpdateScrollBar(ME_TextEditor *editor) editor->vert_si.nMin = si.nMin; editor->vert_si.nMax = si.nMax; editor->vert_si.nPage = si.nPage; - if (bScrollBarWillBeVisible || bScrollBarWasVisible) - SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE); + if (bScrollBarWillBeVisible || bScrollBarWasVisible) { + if (editor->hWnd) { + SetScrollInfo(editor->hWnd, SB_VERT, &si, TRUE); + } else { + ITextHost_TxSetScrollRange(editor->texthost, SB_VERT, si.nMin, si.nMax, FALSE); + ITextHost_TxSetScrollPos(editor->texthost, SB_VERT, si.nPos, TRUE); + } + } } - if (si.fMask & SIF_DISABLENOSCROLL) + if (si.fMask & SIF_DISABLENOSCROLL) { bScrollBarWillBeVisible = TRUE; + } else if (!(editor->styleFlags & WS_VSCROLL)) { + /* SetScrollInfo or SetScrollRange may cause the scrollbar to be + * shown, so hide the scrollbar if necessary. */ + bScrollBarWasVisible = bScrollBarWillBeVisible; + bScrollBarWillBeVisible = FALSE; + } if (bScrollBarWasVisible != bScrollBarWillBeVisible) - ShowScrollBar(editor->hWnd, SB_VERT, bScrollBarWillBeVisible); + ITextHost_TxShowScrollBar(editor->texthost, SB_VERT, + bScrollBarWillBeVisible); } void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor) @@ -1219,24 +1250,6 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_Cursor *pCursor) } -void -ME_InvalidateFromOfs(ME_TextEditor *editor, int nCharOfs) -{ - RECT rc; - int x, y, height; - ME_Cursor tmp; - - ME_RunOfsFromCharOfs(editor, nCharOfs, &tmp.pRun, &tmp.nOffset); - ME_GetCursorCoordinates(editor, &tmp, &x, &y, &height); - - rc.left = 0; - rc.top = y; - rc.bottom = y + height; - rc.right = editor->rcFormat.right; - InvalidateRect(editor->hWnd, &rc, FALSE); -} - - void ME_InvalidateSelection(ME_TextEditor *editor) { @@ -1285,13 +1298,6 @@ ME_InvalidateSelection(ME_TextEditor *editor) assert(editor->pLastSelEndPara->type == diParagraph); } -void -ME_QueueInvalidateFromCursor(ME_TextEditor *editor, int nCursor) -{ - editor->nInvalidOfs = ME_GetCursorOfs(editor, nCursor); -} - - BOOL ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator) { diff --git a/reactos/dll/win32/riched20/para.c b/reactos/dll/win32/riched20/para.c index 00d81a261b9..a4a9adb1b29 100644 --- a/reactos/dll/win32/riched20/para.c +++ b/reactos/dll/win32/riched20/para.c @@ -23,8 +23,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); -static const WCHAR wszParagraphSign[] = {0xB6, 0}; - void ME_MakeFirstParagraph(ME_TextEditor *editor) { ME_Context c; @@ -35,8 +33,10 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) ME_DisplayItem *para = ME_MakeDI(diParagraph); ME_DisplayItem *run; ME_Style *style; + ME_String *eol_str; + WCHAR cr_lf[] = {'\r','\n',0}; - ME_InitContext(&c, editor, GetDC(editor->hWnd)); + ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); hf = GetStockObject(SYSTEM_FONT); assert(hf); @@ -63,11 +63,10 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) style = ME_MakeStyle(&cf); text->pDefaultStyle = style; - - run = ME_MakeRun(style, ME_MakeString(wszParagraphSign), MERF_ENDPARA); + + eol_str = ME_MakeStringN(cr_lf, editor->bEmulateVersion10 ? 2 : 1); + run = ME_MakeRun(style, eol_str, MERF_ENDPARA); run->member.run.nCharOfs = 0; - run->member.run.nCR = 1; - run->member.run.nLF = editor->bEmulateVersion10 ? 1 : 0; ME_InsertBefore(text->pLast, para); ME_InsertBefore(text->pLast, run); @@ -78,7 +77,7 @@ void ME_MakeFirstParagraph(ME_TextEditor *editor) text->pLast->member.para.nCharOfs = editor->bEmulateVersion10 ? 2 : 1; - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); } static void ME_MarkForWrapping(ME_TextEditor *editor, ME_DisplayItem *first, const ME_DisplayItem *last) @@ -201,7 +200,7 @@ static BOOL ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, const /* split paragraph at the beginning of the run */ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, - ME_Style *style, int numCR, int numLF, + ME_Style *style, ME_String *eol_str, int paraFlags) { ME_DisplayItem *next_para = NULL; @@ -211,8 +210,8 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, ME_UndoItem *undo = NULL; int ofs; ME_DisplayItem *pp; - int end_len = numCR + numLF; int run_flags = MERF_ENDPARA; + if (!editor->bEmulateVersion10) { /* v4.1 */ /* At most 1 of MEPF_CELL, MEPF_ROWSTART, or MEPF_ROWEND should be set. */ assert(!(paraFlags & ~(MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); @@ -224,12 +223,9 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, } else { /* v1.0 - v3.0 */ assert(!(paraFlags & (MEPF_CELL|MEPF_ROWSTART|MEPF_ROWEND))); } - end_run = ME_MakeRun(style,ME_MakeString(wszParagraphSign), run_flags); - - assert(run->type == diRun); + end_run = ME_MakeRun(style, eol_str, run_flags); - end_run->member.run.nCR = numCR; - end_run->member.run.nLF = numLF; + assert(run->type == diRun); run_para = ME_GetParagraph(run); assert(run_para->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); @@ -248,7 +244,7 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, pp = ME_FindItemFwd(pp, diRunOrParagraphOrEnd); } new_para->member.para.nCharOfs = ME_GetParagraph(run)->member.para.nCharOfs+ofs; - new_para->member.para.nCharOfs += end_len; + new_para->member.para.nCharOfs += eol_str->nLen; new_para->member.para.nFlags = MEPF_REWRAP; /* FIXME initialize format style and call ME_SetParaFormat blah blah */ @@ -315,7 +311,7 @@ ME_DisplayItem *ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *run, new_para->member.para.prev_para->member.para.nFlags |= MEPF_REWRAP; /* we've added the end run, so we need to modify nCharOfs in the next paragraphs */ - ME_PropagateCharOffset(next_para, end_len); + ME_PropagateCharOffset(next_para, eol_str->nLen); editor->nParagraphs++; return new_para; @@ -344,7 +340,7 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, assert(pRun->type == diRun); assert(pRun->member.run.nFlags & MERF_ENDPARA); - end_len = pRun->member.run.nCR + pRun->member.run.nLF; + end_len = pRun->member.run.strText->nLen; { /* null char format operation to store the original char format for the ENDPARA run */ @@ -356,8 +352,8 @@ ME_DisplayItem *ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, if (undo) { undo->nStart = pNext->member.para.nCharOfs - end_len; - undo->nCR = pRun->member.run.nCR; - undo->nLF = pRun->member.run.nLF; + undo->eol_str = pRun->member.run.strText; + pRun->member.run.strText = NULL; /* Avoid freeing the string */ } if (!keepFirstParaFormat) { diff --git a/reactos/dll/win32/riched20/reader.c b/reactos/dll/win32/riched20/reader.c index 0e0d9a00533..3df7109a0f9 100644 --- a/reactos/dll/win32/riched20/reader.c +++ b/reactos/dll/win32/riched20/reader.c @@ -178,6 +178,33 @@ RTFDestroy(RTF_Info *info) } + +/* ---------------------------------------------------------------------- */ + +/* + * Callback table manipulation routines + */ + + +/* + * Install or return a writer callback for a token class + */ + +static void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback) +{ + if (class >= 0 && class < rtfMaxClass) + info->ccb[class] = callback; +} + + +static RTFFuncPtr RTFGetClassCallback(const RTF_Info *info, int class) +{ + if (class >= 0 && class < rtfMaxClass) + return info->ccb[class]; + return NULL; +} + + /* * Initialize the reader. This may be called multiple times, * to read multiple files. The only thing not reset is the input @@ -192,8 +219,10 @@ void RTFInit(RTF_Info *info) { info->rtfTextBuf = heap_alloc (rtfBufSiz); info->pushedTextBuf = heap_alloc (rtfBufSiz); - if (info->rtfTextBuf == NULL || info->pushedTextBuf == NULL) + if (info->rtfTextBuf == NULL || info->pushedTextBuf == NULL) { ERR ("Cannot allocate text buffers.\n"); + return; + } info->rtfTextBuf[0] = info->pushedTextBuf[0] = '\0'; } @@ -281,33 +310,6 @@ char *RTFGetOutputName(const RTF_Info *info) } - -/* ---------------------------------------------------------------------- */ - -/* - * Callback table manipulation routines - */ - - -/* - * Install or return a writer callback for a token class - */ - -void RTFSetClassCallback(RTF_Info *info, int class, RTFFuncPtr callback) -{ - if (class >= 0 && class < rtfMaxClass) - info->ccb[class] = callback; -} - - -RTFFuncPtr RTFGetClassCallback(const RTF_Info *info, int class) -{ - if (class >= 0 && class < rtfMaxClass) - return info->ccb[class]; - return NULL; -} - - /* * Install or return a writer callback for a destination type */ @@ -319,7 +321,7 @@ void RTFSetDestinationCallback(RTF_Info *info, int dest, RTFFuncPtr callback) } -RTFFuncPtr RTFGetDestinationCallback(const RTF_Info *info, int dest) +static RTFFuncPtr RTFGetDestinationCallback(const RTF_Info *info, int dest) { if (dest >= 0 && dest < rtfMaxDestination) return info->dcb[dest]; @@ -415,6 +417,22 @@ void RTFReadGroup (RTF_Info *info) } +/* + * Install or return a token reader hook. + */ + +void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f) +{ + info->readHook = f; +} + + +static RTFFuncPtr RTFGetReadHook(const RTF_Info *info) +{ + return (info->readHook); +} + + /* * Read one token. Call the read hook if there is one. The * token class is the return value. Returns rtfEOF when there @@ -446,23 +464,7 @@ int RTFGetToken(RTF_Info *info) } -/* - * Install or return a token reader hook. - */ - -void RTFSetReadHook(RTF_Info *info, RTFFuncPtr f) -{ - info->readHook = f; -} - - -RTFFuncPtr RTFGetReadHook(const RTF_Info *info) -{ - return (info->readHook); -} - - -void RTFUngetToken(RTF_Info *info) +static void RTFUngetToken(RTF_Info *info) { if (info->pushedClass >= 0) /* there's already an ungotten token */ ERR ("cannot unget two tokens\n"); @@ -797,7 +799,7 @@ static int GetChar(RTF_Info *info) * part of the token text. */ -void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text) +static void RTFSetToken(RTF_Info *info, int class, int major, int minor, int param, const char *text) { info->rtfClass = class; info->rtfMajor = major; @@ -871,8 +873,10 @@ static void ReadFontTbl(RTF_Info *info) break; } fp = New (RTFFont); - if (fp == NULL) + if (fp == NULL) { ERR ( "%s: cannot allocate font entry\n", fn); + break; + } fp->rtfNextFont = info->fontList; info->fontList = fp; @@ -992,7 +996,7 @@ static void ReadFontTbl(RTF_Info *info) TRACE("default font codepage %d\n", info->codePage); } } - if (fp->rtfFNum == -1) + if (!fp || (fp->rtfFNum == -1)) ERR( "%s: missing font number\n", fn); /* * Could check other pieces of structure here, too, I suppose. @@ -1044,8 +1048,10 @@ static void ReadColorTbl(RTF_Info *info) } cp = New (RTFColor); - if (cp == NULL) + if (cp == NULL) { ERR ( "%s: cannot allocate color entry\n", fn); + break; + } cp->rtfCNum = cnum++; cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1; cp->rtfNextColor = info->colorList; @@ -1090,8 +1096,10 @@ static void ReadStyleSheet(RTF_Info *info) if (RTFCheckCM (info, rtfGroup, rtfEndGroup)) break; sp = New (RTFStyle); - if (sp == NULL) + if (sp == NULL) { ERR ( "%s: cannot allocate stylesheet entry\n", fn); + break; + } sp->rtfSName = NULL; sp->rtfSNum = -1; sp->rtfSType = rtfParStyle; @@ -1269,7 +1277,7 @@ static void ReadObjGroup(RTF_Info *info) */ -RTFStyle *RTFGetStyle(const RTF_Info *info, int num) +static RTFStyle *RTFGetStyle(const RTF_Info *info, int num) { RTFStyle *s; @@ -2719,7 +2727,7 @@ RTFFlushCPOutputBuffer(RTF_Info *info) info->dwCPOutputCount = 0; RTFPutUnicodeString(info, buffer, length); - heap_free((char *)buffer); + heap_free(buffer); } void diff --git a/reactos/dll/win32/riched20/riched20.rbuild b/reactos/dll/win32/riched20/riched20.rbuild index 5b10d49effe..ed098add847 100644 --- a/reactos/dll/win32/riched20/riched20.rbuild +++ b/reactos/dll/win32/riched20/riched20.rbuild @@ -22,6 +22,7 @@ string.c style.c table.c + txthost.c txtsrv.c undo.c wrap.c @@ -30,6 +31,7 @@ wine uuid ole32 + oleaut32 imm32 user32 gdi32 diff --git a/reactos/dll/win32/riched20/richole.c b/reactos/dll/win32/riched20/richole.c index a5f79c7af0c..ee8ea600a68 100644 --- a/reactos/dll/win32/riched20/richole.c +++ b/reactos/dll/win32/riched20/richole.c @@ -348,7 +348,7 @@ IRichEditOle_fnGetObjectCount(IRichEditOle *me) { IRichEditOleImpl *This = impl_from_IRichEditOle(me); FIXME("stub %p\n",This); - return E_NOTIMPL; + return 0; } static HRESULT WINAPI @@ -1694,7 +1694,7 @@ LRESULT CreateIRichEditOle(ME_TextEditor *editor, LPVOID *ppObj) return 0; } TRACE("Created %p\n",reo); - *ppObj = (LPVOID) reo; + *ppObj = reo; return 1; } diff --git a/reactos/dll/win32/riched20/rtf.h b/reactos/dll/win32/riched20/rtf.h index a276b7c2e92..6de440fe547 100644 --- a/reactos/dll/win32/riched20/rtf.h +++ b/reactos/dll/win32/riched20/rtf.h @@ -1195,17 +1195,11 @@ void RTFSetInputName (RTF_Info *, const char *); char *RTFGetInputName (const RTF_Info *); void RTFSetOutputName (RTF_Info *, const char *); char *RTFGetOutputName (const RTF_Info *); -void RTFSetClassCallback (RTF_Info *, int, RTFFuncPtr); -RTFFuncPtr RTFGetClassCallback (const RTF_Info *, int); void RTFSetDestinationCallback (RTF_Info *, int, RTFFuncPtr); -RTFFuncPtr RTFGetDestinationCallback (const RTF_Info *, int); void RTFRead (RTF_Info *); int RTFGetToken (RTF_Info *); /* writer should rarely need this */ -void RTFUngetToken (RTF_Info *); int RTFPeekToken (RTF_Info *); -void RTFSetToken (RTF_Info *, int, int, int, int, const char *); void RTFSetReadHook (RTF_Info *, RTFFuncPtr); -RTFFuncPtr RTFGetReadHook (const RTF_Info *); void RTFRouteToken (RTF_Info *); void RTFSkipGroup (RTF_Info *); void RTFReadGroup (RTF_Info *); @@ -1215,7 +1209,6 @@ int RTFCheckCMM (const RTF_Info *, int, int, int); int RTFCheckMM (const RTF_Info *, int, int); RTFFont *RTFGetFont (const RTF_Info *, int); RTFColor *RTFGetColor (const RTF_Info *, int); -RTFStyle *RTFGetStyle (const RTF_Info *, int); int RTFCharToHex ( char); int RTFHexToChar ( int ); diff --git a/reactos/dll/win32/riched20/run.c b/reactos/dll/win32/riched20/run.c index 28239057011..1f8cc1837c4 100644 --- a/reactos/dll/win32/riched20/run.c +++ b/reactos/dll/win32/riched20/run.c @@ -127,12 +127,8 @@ void ME_CheckCharOffsets(ME_TextEditor *editor) p->member.run.nFlags, p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects); assert(ofs == p->member.run.nCharOfs); - if (p->member.run.nFlags & MERF_ENDPARA) { - assert(p->member.run.nCR + p->member.run.nLF > 0); - ofs += p->member.run.nCR + p->member.run.nLF; - } - else - ofs += ME_StrLen(p->member.run.strText); + assert(p->member.run.strText->nLen); + ofs += p->member.run.strText->nLen; break; case diCell: TRACE_(richedit_check)("cell\n"); @@ -166,11 +162,11 @@ int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs) /****************************************************************************** * ME_CursorFromCharOfs - * + * * Converts a character offset (relative to the start of the document) to * a cursor structure (which contains a run and a position relative to that - * run). - */ + * run). + */ void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor) { ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pRun, &pCursor->nOffset); @@ -178,57 +174,42 @@ void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCurso /****************************************************************************** * ME_RunOfsFromCharOfs - * + * * Find a run and relative character offset given an absolute character offset * (absolute offset being an offset relative to the start of the document). - * Kind of a "global to local" offset conversion. - */ + * Kind of a "global to local" offset conversion. + */ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs) { - ME_DisplayItem *pPara; - int nParaOfs; + ME_DisplayItem *item, *next_item; - pPara = editor->pBuffer->pFirst->member.para.next_para; - assert(pPara); assert(ppRun); assert(pOfs); - while (pPara->type == diParagraph) - { - nParaOfs = pPara->member.para.nCharOfs; - assert(nCharOfs >= nParaOfs); - 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)) - { - ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun); - assert(pNext); - assert(pNext->type == diRun); - if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) { - *pOfs = ME_PosToVPos((*ppRun)->member.run.strText, - nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs); - return; - } - *ppRun = pNext; - } - /* Recover proper character length of this line break */ - eollen = (*ppRun)->member.run.nCR + (*ppRun)->member.run.nLF; - if (nCharOfs >= nParaOfs + (*ppRun)->member.run.nCharOfs && - nCharOfs < nParaOfs + (*ppRun)->member.run.nCharOfs + eollen) { - /* FIXME: Might cause problems when actually requiring an offset in the - middle of a run that is considered a single line break */ - *pOfs = 0; - return; - } - } - pPara = pPara->member.para.next_para; - } - *ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); - *pOfs = 0; - assert((*ppRun)->member.run.nFlags & MERF_ENDPARA); + nCharOfs = max(nCharOfs, 0); + nCharOfs = min(nCharOfs, ME_GetTextLength(editor)); + + /* Find the paragraph at the offset. */ + next_item = editor->pBuffer->pFirst->member.para.next_para; + do { + item = next_item; + next_item = item->member.para.next_para; + } while (next_item->member.para.nCharOfs <= nCharOfs); + assert(item->type == diParagraph); + nCharOfs -= item->member.para.nCharOfs; + + /* Find the run at the offset. */ + next_item = ME_FindItemFwd(item, diRun); + do { + item = next_item; + next_item = ME_FindItemFwd(item, diRunOrParagraphOrEnd); + } while (next_item->type == diRun && + next_item->member.run.nCharOfs <= nCharOfs); + assert(item->type == diRun); + nCharOfs -= item->member.run.nCharOfs; + + *ppRun = item; + *pOfs = nCharOfs; } /****************************************************************************** @@ -550,12 +531,12 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) return 0; return 1; } - ME_InitContext(&c, editor, GetDC(editor->hWnd)); + ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); if (run->nFlags & MERF_GRAPHICS) { SIZE sz; ME_GetOLEObjectSize(&c, run, &sz); - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); if (cx < sz.cx/2) return 0; return 1; @@ -584,7 +565,7 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) ME_DestroyString(strRunText); ME_UnselectStyleFont(&c, run->style, hOldFont); - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); return fit; } @@ -614,22 +595,24 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) ME_String *strRunText; /* This could point to either the run's real text, or it's masked form in a password control */ - ME_InitContext(&c, editor, GetDC(editor->hWnd)); + ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); if (pRun->nFlags & MERF_GRAPHICS) { if (nOffset) ME_GetOLEObjectSize(&c, pRun, &size); - ReleaseDC(editor->hWnd, c.hDC); + ITextHost_TxReleaseDC(editor->texthost, c.hDC); return nOffset != 0; + } else if (pRun->nFlags & MERF_ENDPARA) { + nOffset = 0; } - - if (editor->cPasswordMask) + + if (editor->cPasswordMask) strRunText = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(pRun->strText)); else strRunText = pRun->strText; ME_GetTextExtent(&c, strRunText->szData, nOffset, pRun->style, &size); - ReleaseDC(editor->hWnd, c.hDC); + ITextHost_TxReleaseDC(editor->texthost, c.hDC); if (editor->cPasswordMask) ME_DestroyString(strRunText); return size.cx; diff --git a/reactos/dll/win32/riched20/string.c b/reactos/dll/win32/riched20/string.c index 4a5d59084b2..0bd751ce66f 100644 --- a/reactos/dll/win32/riched20/string.c +++ b/reactos/dll/win32/riched20/string.c @@ -22,7 +22,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit); -int ME_GetOptimalBuffer(int nLen) +static int ME_GetOptimalBuffer(int nLen) { return ((2*nLen+1)+128)&~63; } @@ -83,6 +83,7 @@ ME_String *ME_StrDup(const ME_String *s) void ME_DestroyString(ME_String *s) { + if (!s) return; FREE_OBJ(s->szData); FREE_OBJ(s); } @@ -356,12 +357,12 @@ LPWSTR ME_ToUnicode(BOOL unicode, LPVOID psz) assert(psz != NULL); if (unicode) - return (LPWSTR)psz; + return psz; else { WCHAR *tmp; - int nChars = MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, NULL, 0); + int nChars = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0); if((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) - MultiByteToWideChar(CP_ACP, 0, (char *)psz, -1, tmp, nChars); + MultiByteToWideChar(CP_ACP, 0, psz, -1, tmp, nChars); return tmp; } } diff --git a/reactos/dll/win32/riched20/style.c b/reactos/dll/win32/riched20/style.c index b7dae3e97a5..3980400fb65 100644 --- a/reactos/dll/win32/riched20/style.c +++ b/reactos/dll/win32/riched20/style.c @@ -77,7 +77,7 @@ void ME_CopyToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from) *to = *from; } -CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) +static CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from) { assert(from->cbSize == sizeof(CHARFORMAT2W)); if (to->cbSize == sizeof(CHARFORMATA)) @@ -373,7 +373,6 @@ HFONT ME_SelectStyleFont(ME_Context *c, ME_Style *s) LOGFONTW lf; int i, nEmpty, nAge = 0x7FFFFFFF; ME_FontCacheItem *item; - assert(c->hDC); assert(s); ME_LogFontFromStyle(c, &lf, s); @@ -426,7 +425,6 @@ void ME_UnselectStyleFont(ME_Context *c, ME_Style *s, HFONT hOldFont) { int i; - assert(c->hDC); assert(s); SelectObject(c->hDC, hOldFont); for (i=0; ipCursors[nCursor]; } - tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, numCR, numLF, paraFlags); + tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, paraFlags); cursor->pRun = ME_FindItemFwd(tp, diRun); return tp; } @@ -78,7 +77,9 @@ static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor, ME_DisplayItem* ME_InsertTableRowStartFromCursor(ME_TextEditor *editor) { ME_DisplayItem *para; - para = ME_InsertEndParaFromCursor(editor, 0, 1, 1, MEPF_ROWSTART); + WCHAR cr_lf[] = {'\r', '\n', 0}; + ME_String *eol_str = ME_MakeStringN(cr_lf, 2); + para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWSTART); return para->member.para.prev_para; } @@ -118,14 +119,18 @@ ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor, ME_DisplayItem* ME_InsertTableCellFromCursor(ME_TextEditor *editor) { ME_DisplayItem *para; - para = ME_InsertEndParaFromCursor(editor, 0, 1, 0, MEPF_CELL); + WCHAR cr = '\r'; + ME_String *eol_str = ME_MakeStringN(&cr, 1); + para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_CELL); return para; } ME_DisplayItem* ME_InsertTableRowEndFromCursor(ME_TextEditor *editor) { ME_DisplayItem *para; - para = ME_InsertEndParaFromCursor(editor, 0, 1, 1, MEPF_ROWEND); + WCHAR cr_lf[] = {'\r', '\n', 0}; + ME_String *eol_str = ME_MakeStringN(cr_lf, 2); + para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWEND); return para->member.para.prev_para; } @@ -283,7 +288,7 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars) - end_para->member.para.nCharOfs; if (remaining) { - assert(remaining < c2.pRun->member.run.nCR + c2.pRun->member.run.nLF); + assert(remaining < c2.pRun->member.run.strText->nLen); end_para = end_para->member.para.next_para; } } @@ -331,7 +336,7 @@ void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, int nOfs,int *nChars) { ME_Run *end_run = &ME_FindItemBack(next_para, diRun)->member.run; int nCharsNew = (next_para->member.para.nCharOfs - nOfs - - end_run->nCR - end_run->nLF); + - end_run->strText->nLen); nCharsNew = max(nCharsNew, 0); assert(nCharsNew <= *nChars); *nChars = nCharsNew; @@ -581,7 +586,7 @@ void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow) } ME_InvalidateSelection(editor); ME_Repaint(editor); - HideCaret(editor->hWnd); + ITextHost_TxShowCaret(editor->texthost, FALSE); ME_ShowCaret(editor); ME_SendSelChange(editor); } diff --git a/reactos/dll/win32/riched20/txthost.c b/reactos/dll/win32/riched20/txthost.c new file mode 100644 index 00000000000..5b52b9f84cc --- /dev/null +++ b/reactos/dll/win32/riched20/txthost.c @@ -0,0 +1,727 @@ +/* + * RichEdit - ITextHost implementation for windowed richedit controls + * + * Copyright 2009 by Dylan Smith + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#define COBJMACROS + +#include "editor.h" +#include "ole2.h" +#include "richole.h" +#include "imm.h" +#include "textserv.h" +#include "wine/debug.h" +#include "editstr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +typedef struct ITextHostImpl { + const ITextHostVtbl *lpVtbl; + LONG ref; + HWND hWnd; + BOOL bEmulateVersion10; +} ITextHostImpl; + +static ITextHostVtbl textHostVtbl; + +ITextHost *ME_CreateTextHost(HWND hwnd, BOOL bEmulateVersion10) +{ + ITextHostImpl *texthost; + texthost = CoTaskMemAlloc(sizeof(*texthost)); + if (texthost) + { + ME_TextEditor *editor; + + texthost->lpVtbl = &textHostVtbl; + texthost->ref = 1; + texthost->hWnd = hwnd; + texthost->bEmulateVersion10 = bEmulateVersion10; + + editor = ME_MakeEditor((ITextHost*)texthost, bEmulateVersion10); + editor->exStyleFlags = GetWindowLongW(hwnd, GWL_EXSTYLE); + editor->hWnd = hwnd; /* FIXME: Remove editor's dependance on hWnd */ + SetWindowLongPtrW(hwnd, 0, (LONG_PTR)editor); + } + + return (ITextHost*)texthost; +} + +static HRESULT WINAPI ITextHostImpl_QueryInterface(ITextHost *iface, + REFIID riid, + LPVOID *ppvObject) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ITextHost)) { + *ppvObject = This; + ITextHost_AddRef((ITextHost *)*ppvObject); + return S_OK; + } + + FIXME("Unknown interface: %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ITextHostImpl_AddRef(ITextHost *iface) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + return ref; +} + +static ULONG WINAPI ITextHostImpl_Release(ITextHost *iface) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) + { + SetWindowLongPtrW(This->hWnd, 0, 0); + CoTaskMemFree(This); + } + return ref; +} + +HDC WINAPI ITextHostImpl_TxGetDC(ITextHost *iface) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return GetDC(This->hWnd); +} + +INT WINAPI ITextHostImpl_TxReleaseDC(ITextHost *iface, + HDC hdc) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return ReleaseDC(This->hWnd, hdc); +} + +BOOL WINAPI ITextHostImpl_TxShowScrollBar(ITextHost *iface, + INT fnBar, + BOOL fShow) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return ShowScrollBar(This->hWnd, fnBar, fShow); +} + +BOOL WINAPI ITextHostImpl_TxEnableScrollBar(ITextHost *iface, + INT fuSBFlags, + INT fuArrowflags) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return EnableScrollBar(This->hWnd, fuSBFlags, fuArrowflags); +} + +BOOL WINAPI ITextHostImpl_TxSetScrollRange(ITextHost *iface, + INT fnBar, + LONG nMinPos, + INT nMaxPos, + BOOL fRedraw) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return SetScrollRange(This->hWnd, fnBar, nMinPos, nMaxPos, fRedraw); +} + +BOOL WINAPI ITextHostImpl_TxSetScrollPos(ITextHost *iface, + INT fnBar, + INT nPos, + BOOL fRedraw) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + int pos = SetScrollPos(This->hWnd, fnBar, nPos, fRedraw); + return (pos ? TRUE : FALSE); +} + +void WINAPI ITextHostImpl_TxInvalidateRect(ITextHost *iface, + LPCRECT prc, + BOOL fMode) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + InvalidateRect(This->hWnd, prc, fMode); +} + +void WINAPI ITextHostImpl_TxViewChange(ITextHost *iface, + BOOL fUpdate) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + if (fUpdate) + UpdateWindow(This->hWnd); +} + +BOOL WINAPI ITextHostImpl_TxCreateCaret(ITextHost *iface, + HBITMAP hbmp, + INT xWidth, INT yHeight) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return CreateCaret(This->hWnd, hbmp, xWidth, yHeight); +} + +BOOL WINAPI ITextHostImpl_TxShowCaret(ITextHost *iface, BOOL fShow) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + if (fShow) + return ShowCaret(This->hWnd); + else + return HideCaret(This->hWnd); +} + +BOOL WINAPI ITextHostImpl_TxSetCaretPos(ITextHost *iface, + INT x, INT y) +{ + return SetCaretPos(x, y); +} + +BOOL WINAPI ITextHostImpl_TxSetTimer(ITextHost *iface, + UINT idTimer, UINT uTimeout) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return SetTimer(This->hWnd, idTimer, uTimeout, NULL) != 0; +} + +void WINAPI ITextHostImpl_TxKillTimer(ITextHost *iface, + UINT idTimer) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + KillTimer(This->hWnd, idTimer); +} + +void WINAPI ITextHostImpl_TxScrollWindowEx(ITextHost *iface, + INT dx, INT dy, + LPCRECT lprcScroll, + LPCRECT lprcClip, + HRGN hRgnUpdate, + LPRECT lprcUpdate, + UINT fuScroll) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ScrollWindowEx(This->hWnd, dx, dy, lprcScroll, lprcClip, + hRgnUpdate, lprcUpdate, fuScroll); +} + +void WINAPI ITextHostImpl_TxSetCapture(ITextHost *iface, + BOOL fCapture) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + if (fCapture) + SetCapture(This->hWnd); + else + ReleaseCapture(); +} + +void WINAPI ITextHostImpl_TxSetFocus(ITextHost *iface) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + SetFocus(This->hWnd); +} + +void WINAPI ITextHostImpl_TxSetCursor(ITextHost *iface, + HCURSOR hcur, + BOOL fText) +{ + SetCursor(hcur); +} + +BOOL WINAPI ITextHostImpl_TxScreenToClient(ITextHost *iface, + LPPOINT lppt) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return ScreenToClient(This->hWnd, lppt); +} + +BOOL WINAPI ITextHostImpl_TxClientToScreen(ITextHost *iface, + LPPOINT lppt) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return ClientToScreen(This->hWnd, lppt); +} + +HRESULT WINAPI ITextHostImpl_TxActivate(ITextHost *iface, + LONG *plOldState) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + *plOldState = (LONG)SetActiveWindow(This->hWnd); + return (*plOldState ? S_OK : E_FAIL); +} + +HRESULT WINAPI ITextHostImpl_TxDeactivate(ITextHost *iface, + LONG lNewState) +{ + HWND ret = SetActiveWindow((HWND)lNewState); + return (ret ? S_OK : E_FAIL); +} + +HRESULT WINAPI ITextHostImpl_TxGetClientRect(ITextHost *iface, + LPRECT prc) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + int ret = GetClientRect(This->hWnd, prc); + return (ret ? S_OK : E_FAIL); +} + +HRESULT WINAPI ITextHostImpl_TxGetViewInset(ITextHost *iface, + LPRECT prc) +{ + prc->top = 0; + prc->left = 0; + prc->bottom = 0; + prc->right = 0; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetCharFormat(ITextHost *iface, + const CHARFORMATW **ppCF) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetParaFormat(ITextHost *iface, + const PARAFORMAT **ppPF) +{ + return E_NOTIMPL; +} + +COLORREF WINAPI ITextHostImpl_TxGetSysColor(ITextHost *iface, + int nIndex) +{ + return GetSysColor(nIndex); +} + +HRESULT WINAPI ITextHostImpl_TxGetBackStyle(ITextHost *iface, + TXTBACKSTYLE *pStyle) +{ + *pStyle = TXTBACK_OPAQUE; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetMaxLength(ITextHost *iface, + DWORD *pLength) +{ + *pLength = INFINITE; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetScrollBars(ITextHost *iface, + DWORD *pdwScrollBar) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ME_TextEditor *editor = (ME_TextEditor*)GetWindowLongW(This->hWnd, 0); + const DWORD mask = WS_VSCROLL| + WS_HSCROLL| + ES_AUTOVSCROLL| + ES_AUTOHSCROLL| + ES_DISABLENOSCROLL; + if (editor) + { + *pdwScrollBar = editor->styleFlags & mask; + } else { + DWORD style = GetWindowLongW(This->hWnd, GWL_STYLE); + if (style & WS_VSCROLL) + style |= ES_AUTOVSCROLL; + if (!This->bEmulateVersion10 && (style & WS_HSCROLL)) + style |= ES_AUTOHSCROLL; + *pdwScrollBar = style & mask; + } + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetPasswordChar(ITextHost *iface, + WCHAR *pch) +{ + *pch = '*'; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetAcceleratorPos(ITextHost *iface, + LONG *pch) +{ + *pch = -1; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetExtent(ITextHost *iface, + LPSIZEL lpExtent) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_OnTxCharFormatChange(ITextHost *iface, + const CHARFORMATW *pcf) +{ + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_OnTxParaFormatChange(ITextHost *iface, + const PARAFORMAT *ppf) +{ + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetPropertyBits(ITextHost *iface, + DWORD dwMask, + DWORD *pdwBits) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongPtrW(This->hWnd, 0); + DWORD style; + DWORD dwBits = 0; + + if (editor) + { + style = editor->styleFlags; + if (editor->mode & TM_RICHTEXT) + dwBits |= TXTBIT_RICHTEXT; + if (editor->bWordWrap) + dwBits |= TXTBIT_WORDWRAP; + if (style & ECO_AUTOWORDSELECTION) + dwBits |= TXTBIT_AUTOWORDSEL; + } else { + DWORD dwScrollBar; + + style = GetWindowLongW(This->hWnd, GWL_STYLE); + ITextHostImpl_TxGetScrollBars(iface, &dwScrollBar); + + dwBits |= TXTBIT_RICHTEXT|TXTBIT_AUTOWORDSEL; + if (!(dwScrollBar & ES_AUTOHSCROLL)) + dwBits |= TXTBIT_WORDWRAP; + } + + /* Bits that correspond to window styles. */ + if (style & ES_MULTILINE) + dwBits |= TXTBIT_MULTILINE; + if (style & ES_READONLY) + dwBits |= TXTBIT_READONLY; + if (style & ES_PASSWORD) + dwBits |= TXTBIT_USEPASSWORD; + if (!(style & ES_NOHIDESEL)) + dwBits |= TXTBIT_HIDESELECTION; + if (style & ES_SAVESEL) + dwBits |= TXTBIT_SAVESELECTION; + if (style & ES_VERTICAL) + dwBits |= TXTBIT_VERTICAL; + if (style & ES_NOOLEDRAGDROP) + dwBits |= TXTBIT_DISABLEDRAG; + + dwBits |= TXTBIT_ALLOWBEEP; + + /* The following bits are always FALSE because they are probably only + * needed for ITextServices_OnTxPropertyBitsChange: + * TXTBIT_VIEWINSETCHANGE + * TXTBIT_BACKSTYLECHANGE + * TXTBIT_MAXLENGTHCHANGE + * TXTBIT_CHARFORMATCHANGE + * TXTBIT_PARAFORMATCHANGE + * TXTBIT_SHOWACCELERATOR + * TXTBIT_EXTENTCHANGE + * TXTBIT_SELBARCHANGE + * TXTBIT_SCROLLBARCHANGE + * TXTBIT_CLIENTRECTCHANGE + * + * Documented by MSDN as not supported: + * TXTBIT_USECURRENTBKG + */ + + *pdwBits = dwBits & dwMask; + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface, + DWORD iNotify, + void *pv) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + HWND hwnd = This->hWnd; + HWND parent = GetParent(hwnd); + UINT id = GetWindowLongW(hwnd, GWLP_ID); + + /* Note: EN_MSGFILTER is documented as not being sent to TxNotify */ + + switch (iNotify) + { + case EN_DROPFILES: + case EN_LINK: + case EN_OLEOPFAILED: + case EN_PROTECTED: + case EN_REQUESTRESIZE: + case EN_SAVECLIPBOARD: + case EN_SELCHANGE: + case EN_STOPNOUNDO: + { + /* FIXME: Verify this assumption that pv starts with NMHDR. */ + NMHDR *info = pv; + if (!info) + return E_FAIL; + + info->hwndFrom = hwnd; + info->idFrom = id; + info->code = iNotify; + SendMessageW(parent, WM_NOTIFY, id, (LPARAM)info); + break; + } + + case EN_UPDATE: + /* Only sent when the window is visible. */ + if (!IsWindowVisible(This->hWnd)) + break; + /* Fall through */ + case EN_CHANGE: + case EN_ERRSPACE: + case EN_HSCROLL: + case EN_KILLFOCUS: + case EN_MAXTEXT: + case EN_SETFOCUS: + case EN_VSCROLL: + SendMessageW(parent, WM_COMMAND, MAKEWPARAM(id, iNotify), (LPARAM)hwnd); + break; + + default: + return E_FAIL; + } + return S_OK; +} + +HIMC WINAPI ITextHostImpl_TxImmGetContext(ITextHost *iface) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + return ImmGetContext(This->hWnd); +} + +void WINAPI ITextHostImpl_TxImmReleaseContext(ITextHost *iface, + HIMC himc) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ImmReleaseContext(This->hWnd, himc); +} + +HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface, + LONG *lSelBarWidth) +{ + ITextHostImpl *This = (ITextHostImpl *)iface; + ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongPtrW(This->hWnd, 0); + + DWORD style = editor ? editor->styleFlags + : GetWindowLongW(This->hWnd, GWL_STYLE); + *lSelBarWidth = (style & ES_SELECTIONBAR) ? 225 : 0; /* in HIMETRIC */ + return S_OK; +} + + +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define THISCALL(func) __thiscall_ ## func +#define DEFINE_THISCALL_WRAPPER(func) \ + extern typeof(func) THISCALL(func); \ + __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ + "popl %eax\n\t" \ + "pushl %ecx\n\t" \ + "pushl %eax\n\t" \ + "jmp " __ASM_NAME(#func) ) + +#else /* __i386__ */ + +#define THISCALL(func) func +#define DEFINE_THISCALL_WRAPPER(func) /* nothing */ + +#endif /* __i386__ */ + +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetDC); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxReleaseDC); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowScrollBar); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxEnableScrollBar); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollRange); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollPos); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxInvalidateRect); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxViewChange); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxCreateCaret); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowCaret); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCaretPos); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetTimer); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxKillTimer); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScrollWindowEx); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCapture); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetFocus); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCursor); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScreenToClient); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxClientToScreen); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxActivate); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxDeactivate); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetClientRect); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetViewInset); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetCharFormat); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetParaFormat); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSysColor); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetBackStyle); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetMaxLength); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetScrollBars); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPasswordChar); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetAcceleratorPos); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetExtent); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxCharFormatChange); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxParaFormatChange); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPropertyBits); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxNotify); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmGetContext); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmReleaseContext); +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSelectionBarWidth); + +static ITextHostVtbl textHostVtbl = { + ITextHostImpl_QueryInterface, + ITextHostImpl_AddRef, + ITextHostImpl_Release, + THISCALL(ITextHostImpl_TxGetDC), + THISCALL(ITextHostImpl_TxReleaseDC), + THISCALL(ITextHostImpl_TxShowScrollBar), + THISCALL(ITextHostImpl_TxEnableScrollBar), + THISCALL(ITextHostImpl_TxSetScrollRange), + THISCALL(ITextHostImpl_TxSetScrollPos), + THISCALL(ITextHostImpl_TxInvalidateRect), + THISCALL(ITextHostImpl_TxViewChange), + THISCALL(ITextHostImpl_TxCreateCaret), + THISCALL(ITextHostImpl_TxShowCaret), + THISCALL(ITextHostImpl_TxSetCaretPos), + THISCALL(ITextHostImpl_TxSetTimer), + THISCALL(ITextHostImpl_TxKillTimer), + THISCALL(ITextHostImpl_TxScrollWindowEx), + THISCALL(ITextHostImpl_TxSetCapture), + THISCALL(ITextHostImpl_TxSetFocus), + THISCALL(ITextHostImpl_TxSetCursor), + THISCALL(ITextHostImpl_TxScreenToClient), + THISCALL(ITextHostImpl_TxClientToScreen), + THISCALL(ITextHostImpl_TxActivate), + THISCALL(ITextHostImpl_TxDeactivate), + THISCALL(ITextHostImpl_TxGetClientRect), + THISCALL(ITextHostImpl_TxGetViewInset), + THISCALL(ITextHostImpl_TxGetCharFormat), + THISCALL(ITextHostImpl_TxGetParaFormat), + THISCALL(ITextHostImpl_TxGetSysColor), + THISCALL(ITextHostImpl_TxGetBackStyle), + THISCALL(ITextHostImpl_TxGetMaxLength), + THISCALL(ITextHostImpl_TxGetScrollBars), + THISCALL(ITextHostImpl_TxGetPasswordChar), + THISCALL(ITextHostImpl_TxGetAcceleratorPos), + THISCALL(ITextHostImpl_TxGetExtent), + THISCALL(ITextHostImpl_OnTxCharFormatChange), + THISCALL(ITextHostImpl_OnTxParaFormatChange), + THISCALL(ITextHostImpl_TxGetPropertyBits), + THISCALL(ITextHostImpl_TxNotify), + THISCALL(ITextHostImpl_TxImmGetContext), + THISCALL(ITextHostImpl_TxImmReleaseContext), + THISCALL(ITextHostImpl_TxGetSelectionBarWidth), +}; + +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define STDCALL(func) __stdcall_ ## func +#define DEFINE_STDCALL_WRAPPER(num,func) \ + extern typeof(func) __stdcall_ ## func; \ + __ASM_GLOBAL_FUNC(__stdcall_ ## func, \ + "popl %eax\n\t" \ + "popl %ecx\n\t" \ + "pushl %eax\n\t" \ + "movl (%ecx), %eax\n\t" \ + "jmp *(4*(" #num "))(%eax)" ) + +DEFINE_STDCALL_WRAPPER(3,ITextHostImpl_TxGetDC); +DEFINE_STDCALL_WRAPPER(4,ITextHostImpl_TxReleaseDC); +DEFINE_STDCALL_WRAPPER(5,ITextHostImpl_TxShowScrollBar); +DEFINE_STDCALL_WRAPPER(6,ITextHostImpl_TxEnableScrollBar); +DEFINE_STDCALL_WRAPPER(7,ITextHostImpl_TxSetScrollRange); +DEFINE_STDCALL_WRAPPER(8,ITextHostImpl_TxSetScrollPos); +DEFINE_STDCALL_WRAPPER(9,ITextHostImpl_TxInvalidateRect); +DEFINE_STDCALL_WRAPPER(10,ITextHostImpl_TxViewChange); +DEFINE_STDCALL_WRAPPER(11,ITextHostImpl_TxCreateCaret); +DEFINE_STDCALL_WRAPPER(12,ITextHostImpl_TxShowCaret); +DEFINE_STDCALL_WRAPPER(13,ITextHostImpl_TxSetCaretPos); +DEFINE_STDCALL_WRAPPER(14,ITextHostImpl_TxSetTimer); +DEFINE_STDCALL_WRAPPER(15,ITextHostImpl_TxKillTimer); +DEFINE_STDCALL_WRAPPER(16,ITextHostImpl_TxScrollWindowEx); +DEFINE_STDCALL_WRAPPER(17,ITextHostImpl_TxSetCapture); +DEFINE_STDCALL_WRAPPER(18,ITextHostImpl_TxSetFocus); +DEFINE_STDCALL_WRAPPER(19,ITextHostImpl_TxSetCursor); +DEFINE_STDCALL_WRAPPER(20,ITextHostImpl_TxScreenToClient); +DEFINE_STDCALL_WRAPPER(21,ITextHostImpl_TxClientToScreen); +DEFINE_STDCALL_WRAPPER(22,ITextHostImpl_TxActivate); +DEFINE_STDCALL_WRAPPER(23,ITextHostImpl_TxDeactivate); +DEFINE_STDCALL_WRAPPER(24,ITextHostImpl_TxGetClientRect); +DEFINE_STDCALL_WRAPPER(25,ITextHostImpl_TxGetViewInset); +DEFINE_STDCALL_WRAPPER(26,ITextHostImpl_TxGetCharFormat); +DEFINE_STDCALL_WRAPPER(27,ITextHostImpl_TxGetParaFormat); +DEFINE_STDCALL_WRAPPER(28,ITextHostImpl_TxGetSysColor); +DEFINE_STDCALL_WRAPPER(29,ITextHostImpl_TxGetBackStyle); +DEFINE_STDCALL_WRAPPER(30,ITextHostImpl_TxGetMaxLength); +DEFINE_STDCALL_WRAPPER(31,ITextHostImpl_TxGetScrollBars); +DEFINE_STDCALL_WRAPPER(32,ITextHostImpl_TxGetPasswordChar); +DEFINE_STDCALL_WRAPPER(33,ITextHostImpl_TxGetAcceleratorPos); +DEFINE_STDCALL_WRAPPER(34,ITextHostImpl_TxGetExtent); +DEFINE_STDCALL_WRAPPER(35,ITextHostImpl_OnTxCharFormatChange); +DEFINE_STDCALL_WRAPPER(36,ITextHostImpl_OnTxParaFormatChange); +DEFINE_STDCALL_WRAPPER(37,ITextHostImpl_TxGetPropertyBits); +DEFINE_STDCALL_WRAPPER(38,ITextHostImpl_TxNotify); +DEFINE_STDCALL_WRAPPER(39,ITextHostImpl_TxImmGetContext); +DEFINE_STDCALL_WRAPPER(40,ITextHostImpl_TxImmReleaseContext); +DEFINE_STDCALL_WRAPPER(41,ITextHostImpl_TxGetSelectionBarWidth); + +ITextHostVtbl itextHostStdcallVtbl = { + NULL, + NULL, + NULL, + __stdcall_ITextHostImpl_TxGetDC, + __stdcall_ITextHostImpl_TxReleaseDC, + __stdcall_ITextHostImpl_TxShowScrollBar, + __stdcall_ITextHostImpl_TxEnableScrollBar, + __stdcall_ITextHostImpl_TxSetScrollRange, + __stdcall_ITextHostImpl_TxSetScrollPos, + __stdcall_ITextHostImpl_TxInvalidateRect, + __stdcall_ITextHostImpl_TxViewChange, + __stdcall_ITextHostImpl_TxCreateCaret, + __stdcall_ITextHostImpl_TxShowCaret, + __stdcall_ITextHostImpl_TxSetCaretPos, + __stdcall_ITextHostImpl_TxSetTimer, + __stdcall_ITextHostImpl_TxKillTimer, + __stdcall_ITextHostImpl_TxScrollWindowEx, + __stdcall_ITextHostImpl_TxSetCapture, + __stdcall_ITextHostImpl_TxSetFocus, + __stdcall_ITextHostImpl_TxSetCursor, + __stdcall_ITextHostImpl_TxScreenToClient, + __stdcall_ITextHostImpl_TxClientToScreen, + __stdcall_ITextHostImpl_TxActivate, + __stdcall_ITextHostImpl_TxDeactivate, + __stdcall_ITextHostImpl_TxGetClientRect, + __stdcall_ITextHostImpl_TxGetViewInset, + __stdcall_ITextHostImpl_TxGetCharFormat, + __stdcall_ITextHostImpl_TxGetParaFormat, + __stdcall_ITextHostImpl_TxGetSysColor, + __stdcall_ITextHostImpl_TxGetBackStyle, + __stdcall_ITextHostImpl_TxGetMaxLength, + __stdcall_ITextHostImpl_TxGetScrollBars, + __stdcall_ITextHostImpl_TxGetPasswordChar, + __stdcall_ITextHostImpl_TxGetAcceleratorPos, + __stdcall_ITextHostImpl_TxGetExtent, + __stdcall_ITextHostImpl_OnTxCharFormatChange, + __stdcall_ITextHostImpl_OnTxParaFormatChange, + __stdcall_ITextHostImpl_TxGetPropertyBits, + __stdcall_ITextHostImpl_TxNotify, + __stdcall_ITextHostImpl_TxImmGetContext, + __stdcall_ITextHostImpl_TxImmReleaseContext, + __stdcall_ITextHostImpl_TxGetSelectionBarWidth, +}; + +#endif /* __i386__ */ diff --git a/reactos/dll/win32/riched20/txtsrv.c b/reactos/dll/win32/riched20/txtsrv.c index d4679f78313..d7b915cc1c9 100644 --- a/reactos/dll/win32/riched20/txtsrv.c +++ b/reactos/dll/win32/riched20/txtsrv.c @@ -27,6 +27,7 @@ #include "editor.h" #include "ole2.h" +#include "oleauto.h" #include "richole.h" #include "imm.h" #include "textserv.h" @@ -57,6 +58,7 @@ typedef struct ITextServicesImpl { ITextHost *pMyHost; LONG ref; CRITICAL_SECTION csTxtSrv; + ME_TextEditor *editor; char spare[256]; } ITextServicesImpl; @@ -70,6 +72,7 @@ HRESULT WINAPI CreateTextServices(IUnknown * pUnkOuter, IUnknown **ppUnk) { ITextServicesImpl *ITextImpl; + HRESULT hres; TRACE("%p %p --> %p\n", pUnkOuter, pITextHost, ppUnk); if (pITextHost == NULL) return E_POINTER; @@ -83,6 +86,8 @@ HRESULT WINAPI CreateTextServices(IUnknown * pUnkOuter, ITextHost_AddRef(pITextHost); ITextImpl->pMyHost = pITextHost; ITextImpl->lpVtbl = &textservices_Vtbl; + ITextImpl->editor = ME_MakeEditor(pITextHost, FALSE); + ME_HandleMessage(ITextImpl->editor, WM_CREATE, 0, 0, TRUE, &hres); if (pUnkOuter) { @@ -105,7 +110,7 @@ static HRESULT WINAPI fnTextSrv_QueryInterface(ITextServices * iface, TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv); *ppv = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ITextServices)) - *ppv = (LPVOID)This; + *ppv = This; if (*ppv) { @@ -150,9 +155,10 @@ HRESULT WINAPI fnTextSrv_TxSendMessage(ITextServices *iface, LRESULT* plresult) { ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface); + HRESULT hresult; - FIXME("%p: STUB\n", This); - return E_NOTIMPL; + *plresult = ME_HandleMessage(This->editor, msg, wparam, lparam, TRUE, &hresult); + return hresult; } HRESULT WINAPI fnTextSrv_TxDraw(ITextServices *iface, @@ -184,8 +190,12 @@ HRESULT WINAPI fnTextSrv_TxGetHScroll(ITextServices *iface, { ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface); - FIXME("%p: STUB\n", This); - return E_NOTIMPL; + *plMin = This->editor->horz_si.nMin; + *plMax = This->editor->horz_si.nMax; + *plPos = This->editor->horz_si.nPos; + *plPage = This->editor->horz_si.nPage; + *pfEnabled = (This->editor->styleFlags & WS_HSCROLL) != 0; + return S_OK; } HRESULT WINAPI fnTextSrv_TxGetVScroll(ITextServices *iface, @@ -197,8 +207,12 @@ HRESULT WINAPI fnTextSrv_TxGetVScroll(ITextServices *iface, { ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface); - FIXME("%p: STUB\n", This); - return E_NOTIMPL; + *plMin = This->editor->vert_si.nMin; + *plMax = This->editor->vert_si.nMax; + *plPos = This->editor->vert_si.nPos; + *plPage = This->editor->vert_si.nPage; + *pfEnabled = (This->editor->styleFlags & WS_VSCROLL) != 0; + return S_OK; } HRESULT WINAPI fnTextSrv_OnTxSetCursor(ITextServices *iface, @@ -271,9 +285,23 @@ HRESULT WINAPI fnTextSrv_TxGetText(ITextServices *iface, BSTR* pbstrText) { ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface); + int length; - FIXME("%p: STUB\n", This); - return E_NOTIMPL; + length = ME_GetTextLength(This->editor); + if (length) + { + BSTR bstr; + bstr = SysAllocStringByteLen(NULL, length * sizeof(WCHAR)); + if (bstr == NULL) + return E_OUTOFMEMORY; + + ME_GetTextW(This->editor, bstr , 0, length, FALSE); + *pbstrText = bstr; + } else { + *pbstrText = NULL; + } + + return S_OK; } HRESULT WINAPI fnTextSrv_TxSetText(ITextServices *iface, @@ -281,8 +309,17 @@ HRESULT WINAPI fnTextSrv_TxSetText(ITextServices *iface, { ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface); - FIXME("%p: STUB\n", This); - return E_NOTIMPL; + ME_InternalDeleteText(This->editor, 0, ME_GetTextLength(This->editor), + FALSE); + ME_InsertTextFromCursor(This->editor, 0, pszText, -1, + This->editor->pBuffer->pDefaultStyle); + ME_SetSelection(This->editor, 0, 0); + This->editor->nModifyStep = 0; + OleFlushClipboard(); + ME_EmptyUndoStack(This->editor); + ME_UpdateRepaint(This->editor); + + return S_OK; } HRESULT WINAPI fnTextSrv_TxGetCurrentTargetX(ITextServices *iface, diff --git a/reactos/dll/win32/riched20/undo.c b/reactos/dll/win32/riched20/undo.c index 49802a357d4..423a6d463e7 100644 --- a/reactos/dll/win32/riched20/undo.c +++ b/reactos/dll/win32/riched20/undo.c @@ -55,8 +55,7 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_Disp return NULL; else { - ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem); - ((ME_UndoItem *)pItem)->nCR = ((ME_UndoItem *)pItem)->nLF = -1; + ME_DisplayItem *pItem = ALLOC_OBJ(ME_UndoItem); switch(type) { case diUndoPotentialEndTransaction: @@ -329,8 +328,7 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem) ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp); if (tmp.nOffset) tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset); - assert(pUItem->nCR >= 0); - assert(pUItem->nLF >= 0); + assert(pUItem->eol_str); this_para = ME_GetParagraph(tmp.pRun); bFixRowStart = this_para->member.para.nFlags & MEPF_ROWSTART; if (bFixRowStart) @@ -340,7 +338,7 @@ static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem) this_para->member.para.nFlags &= ~MEPF_ROWSTART; } new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style, - pUItem->nCR, pUItem->nLF, paraFlags); + pUItem->eol_str, paraFlags); if (bFixRowStart) new_para->member.para.nFlags |= MEPF_ROWSTART; assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2)); diff --git a/reactos/dll/win32/riched20/wrap.c b/reactos/dll/win32/riched20/wrap.c index 9012cfe7d21..4edbbb2d849 100644 --- a/reactos/dll/win32/riched20/wrap.c +++ b/reactos/dll/win32/riched20/wrap.c @@ -582,7 +582,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) int yStart = -1; int totalWidth = 0; - ME_InitContext(&c, editor, GetDC(editor->hWnd)); + ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); c.pt.x = 0; item = editor->pBuffer->pFirst->next; while(item != editor->pBuffer->pLast) { @@ -723,7 +723,7 @@ BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) editor->pBuffer->pLast->member.para.pt.x = 0; editor->pBuffer->pLast->member.para.pt.y = c.pt.y; - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); if (bModified || editor->nTotalLength < editor->nLastTotalLength) ME_InvalidateMarkedParagraphs(editor); @@ -737,7 +737,7 @@ void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) int ofs; ME_DisplayItem *item; - ME_InitContext(&c, editor, GetDC(editor->hWnd)); + ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost)); rc = c.rcView; ofs = editor->vert_si.nPos; @@ -748,7 +748,7 @@ void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) rc.bottom = max(c.rcView.top + item->member.para.pt.y + item->member.para.nHeight - ofs, c.rcView.bottom); - InvalidateRect(editor->hWnd, &rc, TRUE); + ITextHost_TxInvalidateRect(editor->texthost, &rc, TRUE); } item = item->member.para.next_para; } @@ -756,9 +756,9 @@ void ME_InvalidateMarkedParagraphs(ME_TextEditor *editor) { rc.top = c.rcView.top + editor->nTotalLength - ofs; rc.bottom = c.rcView.top + editor->nLastTotalLength - ofs; - InvalidateRect(editor->hWnd, &rc, TRUE); + ITextHost_TxInvalidateRect(editor->texthost, &rc, TRUE); } - ME_DestroyContext(&c, editor->hWnd); + ME_DestroyContext(&c); } @@ -769,22 +769,19 @@ ME_SendRequestResize(ME_TextEditor *editor, BOOL force) { RECT rc; - GetClientRect(editor->hWnd, &rc); + ITextHost_TxGetClientRect(editor->texthost, &rc); if (force || rc.bottom != editor->nTotalLength) { REQRESIZE info; - info.nmhdr.hwndFrom = editor->hWnd; - info.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID); info.nmhdr.code = EN_REQUESTRESIZE; info.rc = rc; info.rc.right = editor->nTotalWidth; info.rc.bottom = editor->nTotalLength; editor->nEventMask &= ~ENM_REQUESTRESIZE; - SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, - info.nmhdr.idFrom, (LPARAM)&info); + ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info); editor->nEventMask |= ENM_REQUESTRESIZE; } } diff --git a/reactos/dll/win32/riched20/writer.c b/reactos/dll/win32/riched20/writer.c index 98bb9d3ba66..5a5135e986f 100644 --- a/reactos/dll/win32/riched20/writer.c +++ b/reactos/dll/win32/riched20/writer.c @@ -877,8 +877,7 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC return FALSE; } /* Skip as many characters as required by current line break */ - nChars -= (p->member.run.nCR <= nChars) ? p->member.run.nCR : nChars; - nChars -= (p->member.run.nLF <= nChars) ? p->member.run.nLF : nChars; + nChars = max(0, nChars - p->member.run.strText->nLen); } else if (p->member.run.nFlags & MERF_ENDROW) { if (!ME_StreamOutPrint(pStream, "\\line \r\n")) return FALSE; @@ -916,63 +915,35 @@ ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nC static BOOL ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int nChars, DWORD dwFormat) { - /* FIXME: use ME_RunOfsFromCharOfs */ - ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart); + ME_DisplayItem *item; int nLen; UINT nCodePage = CP_ACP; char *buffer = NULL; int nBufLen = 0; BOOL success = TRUE; + ME_RunOfsFromCharOfs(editor, nStart, &item, &nStart); + if (!item) return FALSE; - + if (dwFormat & SF_USECODEPAGE) nCodePage = HIWORD(dwFormat); /* TODO: Handle SF_TEXTIZED */ - + while (success && nChars && item) { - nLen = ME_StrLen(item->member.run.strText) - nStart; - if (nLen > nChars) - nLen = nChars; + nLen = min(nChars, ME_StrLen(item->member.run.strText) - nStart); - if (item->member.run.nFlags & MERF_ENDPARA) { + if (!editor->bEmulateVersion10 && item->member.run.nFlags & MERF_ENDPARA) + { static const WCHAR szEOL[2] = { '\r', '\n' }; - - if (!editor->bEmulateVersion10) { - /* richedit 2.0 - all line breaks are \r\n */ - if (dwFormat & SF_UNICODE) - success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL)); - else - success = ME_StreamOutMove(pStream, "\r\n", 2); - assert(nLen == 1); - } else { - int i; int tnLen; - /* richedit 1.0 - need to honor actual \r and \n amounts */ - nLen = item->member.run.nCR + item->member.run.nLF; - if (nLen > nChars) - nLen = nChars; - tnLen = nLen; - - i = 0; - while (tnLen > 0 && i < item->member.run.nCR) { - if (dwFormat & SF_UNICODE) - success = ME_StreamOutMove(pStream, (const char *)(&szEOL[0]), sizeof(WCHAR)); - else - success = ME_StreamOutMove(pStream, "\r", 1); - tnLen--; i++; - } - i = 0; - while (tnLen > 0 && i < item->member.run.nLF) { - if (dwFormat & SF_UNICODE) - success = ME_StreamOutMove(pStream, (const char *)(&szEOL[1]), sizeof(WCHAR)); - else - success = ME_StreamOutMove(pStream, "\n", 1); - tnLen--; i++; - } - } + /* richedit 2.0 - all line breaks are \r\n */ + if (dwFormat & SF_UNICODE) + success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL)); + else + success = ME_StreamOutMove(pStream, "\r\n", 2); } else { if (dwFormat & SF_UNICODE) success = ME_StreamOutMove(pStream, (const char *)(item->member.run.strText->szData + nStart), @@ -992,12 +963,12 @@ ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream, int nStart, int n success = ME_StreamOutMove(pStream, buffer, nSize); } } - + nChars -= nLen; nStart = 0; item = ME_FindItemFwd(item, diRun); } - + FREE_OBJ(buffer); return success; } diff --git a/reactos/include/psdk/textserv.h b/reactos/include/psdk/textserv.h index e9ff4da627e..7a0cfbf4648 100644 --- a/reactos/include/psdk/textserv.h +++ b/reactos/include/psdk/textserv.h @@ -357,46 +357,6 @@ DECLARE_INTERFACE_(ITextHost,IUnknown) #define ITextHost_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) #define ITextHost_AddRef(p) (p)->lpVtbl->AddRef(p) #define ITextHost_Release(p) (p)->lpVtbl->Release(p) -/*** ITextHost methods ***/ -#define ITextHost_TxGetDC(p) (p)->lpVtbl->TxGetDC(p) -#define ITextHost_TxReleaseDC(p,a) (p)->lpVtbl->TxReleaseDC(p,a) -#define ITextHost_TxShowScrollBar(p,a,b) (p)->lpVtbl->TxShowScrollBar(p,a,b) -#define ITextHost_TxEnableScrollBar(p,a,b) (p)->lpVtbl->TxEnableScrollBar(p,a,b) -#define ITextHost_TxSetScrollRange(p,a,b,c,d) (p)->lpVtbl->TxSetScrollRange(p,a,b,c,d) -#define ITextHost_TxSetScrollPos(p,a,b,c) (p)->lpVtbl->TxSetScrollPos(p,a,b,c) -#define ITextHost_TxInvalidateRect(p,a,b) (p)->lpVtbl->TxInvalidateRect(p,a,b) -#define ITextHost_TxViewChange(p,a) (p)->lpVtbl->TxViewChange(p,a) -#define ITextHost_TxCreateCaret(p,a,b,c) (p)->lpVtbl->TxCreateCaret(p,a,b,c) -#define ITextHost_TxShowCaret(p,a) (p)->lpVtbl->TxShowCaret(p,a) -#define ITextHost_TxSetCarentPos(p,a,b) (p)->lpVtbl->TxSetCarentPos(p,a,b) -#define ITextHost_TxSetTimer(p,a,b) (p)->lpVtbl->TxSetTimer(p,a,b) -#define ITextHost_TxKillTimer(p,a) (p)->lpVtbl->TxKillTimer(p,a) -#define ITextHost_TxScrollWindowEx(p,a,b,c,d,e,f,g) (p)->lpVtbl->TxScrollWindowEx(p,a,b,c,d,e,f,g) -#define ITextHost_TxSetCapture(p,a) (p)->lpVtbl->TxSetCapture(p,a) -#define ITextHost_TxSetFocus(p) (p)->lpVtbl->TxSetFocus(p) -#define ITextHost_TxSetCursor(p,a,b) (p)->lpVtbl->TxSetCursor(p,a,b) -#define ITextHost_TxScreenToClient(p,a) (p)->lpVtbl->TxScreenToClient(p,a) -#define ITextHost_TxClientToScreen(p,a) (p)->lpVtbl->TxClientToScreen(p,a) -#define ITextHost_TxActivate(p,a) (p)->lpVtbl->TxActivate(p,a) -#define ITextHost_TxDeactivate(p,a) (p)->lpVtbl->TxDeactivate(p,a) -#define ITextHost_TxGetClientRect(p,a) (p)->lpVtbl->TxGetClientRect(p,a) -#define ITextHost_TxGetViewInset(p,a) (p)->lpVtbl->TxGetViewInset(p,a) -#define ITextHost_TxGetCharFormat(p,a) (p)->lpVtbl->TxGetCharFormat(p,a) -#define ITextHost_TxGetParaFormat(p,a) (p)->lpVtbl->TxGetParaFormat(p,a) -#define ITextHost_TxGetSysColor(p,a) (p)->lpVtbl->TxGetSysColor(p,a) -#define ITextHost_TxGetBackStyle(p,a) (p)->lpVtbl->TxGetBackStyle(p,a) -#define ITextHost_TxGetMaxLength(p,a) (p)->lpVtbl->TxGetMaxLength(p,a) -#define ITextHost_TxGetScrollBars(p,a) (p)->lpVtbl->TxGetScrollBars(p,a) -#define ITextHost_TxGetPasswordChar(p,a) (p)->lpVtbl->TxGetPasswordChar(p,a) -#define ITextHost_TxGetAcceleratorPos(p,a) (p)->lpVtbl->TxGetAcceleratorPos(p,a) -#define ITextHost_TxGetExtent(p,a) (p)->lpVtbl->TxGetExtent(p,a) -#define ITextHost_OnTxCharFormatChange(p,a) (p)->lpVtbl->OnTxCharFormatChange(p,a) -#define ITextHost_OnTxParaFormatChange(p,a) (p)->lpVtbl->OnTxParaFormatChange(p,a) -#define ITextHost_TxGetPropertyBits(p,a,b) (p)->lpVtbl->TxGetPropertyBits(p,a,b) -#define ITextHost_TxNotify(p,a,b) (p)->lpVtbl->TxNotify(p,a,b) -#define ITextHost_TxImmGetContext(p) (p)->lpVtbl->TxImmGetContext(p) -#define ITextHost_TxImmReleaseContext(p,a) (p)->lpVtbl->TxImmReleaseContext(p,a) -#define ITextHost_TxGetSelectionBarWidth(p,a) (p)->lpVtbl->TxGetSelectionBarWidth(p,a) #endif #undef INTERFACE