-- v4: riched20: Implement ITextDocument::Freeze and ITextDocument::Unfreeze. riched20: Don't assume that TxDraw preserves the device context's brush selection.
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/riched20/tests/richole.c | 86 +++++++++++++++++++++++++++++++++++ dlls/riched20/tests/txtsrv.c | 28 ++++++++++++ 2 files changed, 114 insertions(+)
diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 7402541ed6e..08641ce6317 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -31,6 +31,8 @@ #include <richedit.h> #include <richole.h> #include <tom.h> +#include <imm.h> +#include <textserv.h> #include <wine/test.h>
#define EXPECT_TODO_WINE 0x80000000UL @@ -605,6 +607,7 @@ static HRESULT testoleobj_Create( struct testoleobj **objptr ) static HMODULE hmoduleRichEdit;
DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +DEFINE_GUID(IID_ITextServices, 0x8d33f740, 0xcf58, 0x11ce, 0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5);
static const WCHAR sysW[] = {'S','y','s','t','e','m',0};
@@ -5496,6 +5499,88 @@ static void test_undo_control(void) release_interfaces(&inst.hwnd, &reole, &inst.doc, &selection); }
+static void test_freeze(void) +{ + ITextSelection *selection = NULL; + DWORD lasterr, style1, style2; + IRichEditOle *reole = NULL; + ITextDocument *doc = NULL; + HRESULT hr; + LONG count; + HWND hwnd; + + create_interfaces(&hwnd, &reole, &doc, &selection); + + SetLastError(0xdeadbeef); + style1 = GetWindowLongW(hwnd, GWL_STYLE); + lasterr = GetLastError(); + ok(lasterr == 0xdeadbeefUL, "GetLastError() returned %#lx\n", lasterr); + + count = 0xdeadbeef; + hr = ITextDocument_Freeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); + todo_wine + ok(count == 1, "expected count to be %d, got %ld\n", 1, count); + + style2 = GetWindowLongW(hwnd, GWL_STYLE); + ok(style2 == style1, "expected window style to not change from %#lx, got %#lx\n", style1, style2); + + count = 0xdeadbeef; + hr = ITextDocument_Freeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); + todo_wine + ok(count == 2, "expected count to be %d, got %ld\n", 2, count); + + count = 0xdeadbeef; + hr = ITextDocument_Unfreeze(doc, &count); + todo_wine + ok(hr == S_FALSE, "ITextDocument_Unfreeze returned %#lx\n", hr); + todo_wine + ok(count == 1, "expected count to be %d, got %ld\n", 1, count); + + count = 0xdeadbeef; + hr = ITextDocument_Unfreeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); + todo_wine + ok(count == 0, "expected count to be %d, got %ld\n", 0, count); + + count = 0xdeadbeef; + hr = ITextDocument_Unfreeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); + todo_wine + ok(count == 0, "expected count to be %d, got %ld\n", 0, count); + + count = 0xdeadbeef; + hr = ITextDocument_Freeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); + todo_wine + ok(count == 1, "expected count to be %d, got %ld\n", 1, count); + + count = 0xdeadbeef; + hr = ITextDocument_Unfreeze(doc, &count); + todo_wine + ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); + todo_wine + ok(count == 0, "expected count to be %d, got %ld\n", 0, count); + + count = 0xdeadbeef; + hr = ITextDocument_Freeze(doc, NULL); + todo_wine + ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); + + count = 0xdeadbeef; + hr = ITextDocument_Unfreeze(doc, NULL); + todo_wine + ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); + + release_interfaces(&hwnd, &reole, &doc, &selection); +} + START_TEST(richole) { /* Must explicitly LoadLibrary(). The test has no references to functions in @@ -5539,4 +5624,5 @@ START_TEST(richole) test_clipboard(); test_undo(); test_undo_control(); + test_freeze(); } diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c index 16904347919..2777f4eea21 100644 --- a/dlls/riched20/tests/txtsrv.c +++ b/dlls/riched20/tests/txtsrv.c @@ -815,15 +815,20 @@ static void test_TxGetNaturalSize(void) static void test_TxDraw(void) { ITextServices *txtserv; + ITextDocument *txtdoc; ITextHost *host; HRESULT hr; RECT client = {0, 0, 100, 100}; ITextHostTestImpl *host_impl; + LONG freeze_count; HDC hdc;
if (!init_texthost(&txtserv, &host)) return;
+ hr = ITextServices_QueryInterface( txtserv, &IID_ITextDocument, (void **)&txtdoc ); + ok( hr == S_OK, "ITextServices_QueryInterface (ITextDocument) returned %#lx\n", hr ); + host_impl = impl_from_ITextHost( host ); host_impl->window = CreateWindowExA( 0, "static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 400, 400, 0, 0, 0, NULL ); @@ -856,9 +861,32 @@ static void test_TxDraw(void) NULL, NULL, 0, TXTVIEW_INACTIVE ); ok( hr == S_OK, "got %08lx\n", hr );
+ freeze_count = 0xdeadbeef; + hr = ITextDocument_Freeze( txtdoc, &freeze_count ); + todo_wine + ok( hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr ); + todo_wine + ok( freeze_count == 1, "expected count to be %d, got %ld\n", 1, freeze_count ); + + hr = ITextServices_TxDraw( txtserv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, (RECTL *)&client, NULL, + NULL, NULL, 0, TXTVIEW_INACTIVE ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ITextServices_TxDraw( txtserv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, (RECTL *)&client, NULL, + NULL, NULL, 0, TXTVIEW_ACTIVE ); + todo_wine + ok( hr == E_UNEXPECTED, "got %08lx\n", hr ); + + freeze_count = 0xdeadbeef; + hr = ITextDocument_Unfreeze( txtdoc, &freeze_count ); + todo_wine + ok( hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr ); + todo_wine + ok( freeze_count == 0, "expected count to be %d, got %ld\n", 0, freeze_count ); + hr = ITextServices_OnTxInPlaceDeactivate( txtserv );
ReleaseDC( host_impl->window, hdc ); + ITextDocument_Release(txtdoc); ITextServices_Release(txtserv); DestroyWindow( host_impl->window ); ITextHost_Release(host);
From: Jinoh Kang jinoh.kang.kr@gmail.com
Today, RichEditWndProc_common assumes that ITextServices::TxDraw preserves the brush selection of the given device context. However, this invariant may be broken by misbehaving embedded OLE objects in the text document.
Fix this by not assuming that the return value of the second SelectObject() call equals the brush passed to the first SelectObject() call in RichEditWndProc_common's WM_PAINT / WM_PRINTCLIENT case. --- dlls/riched20/txthost.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/riched20/txthost.c b/dlls/riched20/txthost.c index cb008f19c21..ec6f8e52fa5 100644 --- a/dlls/riched20/txthost.c +++ b/dlls/riched20/txthost.c @@ -1312,7 +1312,7 @@ static LRESULT RichEditWndProc_common( HWND hwnd, UINT msg, WPARAM wparam, HDC hdc; RECT rc, client, update; PAINTSTRUCT ps; - HBRUSH brush = CreateSolidBrush( ITextHost_TxGetSysColor( &host->ITextHost_iface, COLOR_WINDOW ) ); + HBRUSH brush, old_brush;
ITextHost_TxGetClientRect( &host->ITextHost_iface, &client );
@@ -1327,7 +1327,8 @@ static LRESULT RichEditWndProc_common( HWND hwnd, UINT msg, WPARAM wparam, update = client; }
- brush = SelectObject( hdc, brush ); + brush = CreateSolidBrush( ITextHost_TxGetSysColor( &host->ITextHost_iface, COLOR_WINDOW ) ); + old_brush = SelectObject( hdc, brush );
/* Erase area outside of the formatting rectangle */ if (update.top < client.top) @@ -1361,7 +1362,8 @@ static LRESULT RichEditWndProc_common( HWND hwnd, UINT msg, WPARAM wparam,
ITextServices_TxDraw( host->text_srv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, NULL, NULL, &update, NULL, 0, TXTVIEW_ACTIVE ); - DeleteObject( SelectObject( hdc, brush ) ); + SelectObject( hdc, old_brush ); + DeleteObject( brush ); if (msg == WM_PAINT) EndPaint( hwnd, &ps ); return 0; }
From: Jinoh Kang jinoh.kang.kr@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54617 --- dlls/riched20/editor.c | 1 + dlls/riched20/editstr.h | 1 + dlls/riched20/paint.c | 6 ++++-- dlls/riched20/richole.c | 15 +++++++++++---- dlls/riched20/tests/richole.c | 16 ---------------- dlls/riched20/tests/txtsrv.c | 5 ----- dlls/riched20/txthost.c | 6 +++++- dlls/riched20/txtsrv.c | 2 ++ 8 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 704546f1e95..9c84a810569 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -2994,6 +2994,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10) ed->mode |= (ed->props & TXTBIT_RICHTEXT) ? TM_RICHTEXT : TM_PLAINTEXT; ed->AutoURLDetect_bEnable = FALSE; ed->bHaveFocus = FALSE; + ed->freeze_count = 0; ed->bMouseCaptured = FALSE; ed->caret_hidden = FALSE; ed->caret_height = 0; diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index db219d7e4df..cc577de14db 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -429,6 +429,7 @@ typedef struct tagME_TextEditor BOOL AutoURLDetect_bEnable; WCHAR password_char; BOOL bHaveFocus; + DWORD freeze_count; /*for IME */ int imeStartIndex; DWORD selofs; /* The size of the selection bar on the left side of control */ diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index 245afff77dc..8bc1b8bcd2f 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -123,7 +123,8 @@ void ME_Repaint(ME_TextEditor *editor) ME_UpdateScrollBar(editor); FIXME("ME_Repaint had to call ME_WrapMarkedParagraphs\n"); } - ITextHost_TxViewChange(editor->texthost, TRUE); + if (!editor->freeze_count) + ITextHost_TxViewChange(editor->texthost, TRUE); }
void ME_UpdateRepaint(ME_TextEditor *editor, BOOL update_now) @@ -140,7 +141,8 @@ void ME_UpdateRepaint(ME_TextEditor *editor, BOOL update_now)
update_caret( editor );
- ITextHost_TxViewChange(editor->texthost, update_now); + if (!editor->freeze_count) + ITextHost_TxViewChange(editor->texthost, update_now);
ME_SendSelChange(editor);
diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index 8190a4e2753..90496742e36 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -4217,15 +4217,22 @@ static HRESULT WINAPI ITextDocument2Old_fnSave(ITextDocument2Old *iface, VARIANT static HRESULT WINAPI ITextDocument2Old_fnFreeze(ITextDocument2Old *iface, LONG *pCount) { struct text_services *services = impl_from_ITextDocument2Old(iface); - FIXME("stub %p\n", services); - return E_NOTIMPL; + + if (services->editor->freeze_count < LONG_MAX) services->editor->freeze_count++; + + if (pCount) *pCount = services->editor->freeze_count; + return services->editor->freeze_count != 0 ? S_OK : S_FALSE; }
static HRESULT WINAPI ITextDocument2Old_fnUnfreeze(ITextDocument2Old *iface, LONG *pCount) { struct text_services *services = impl_from_ITextDocument2Old(iface); - FIXME("stub %p\n", services); - return E_NOTIMPL; + + if (services->editor->freeze_count && !--services->editor->freeze_count) + ME_RewrapRepaint(services->editor); + + if (pCount) *pCount = services->editor->freeze_count; + return services->editor->freeze_count == 0 ? S_OK : S_FALSE; }
static HRESULT WINAPI ITextDocument2Old_fnBeginEditCollection(ITextDocument2Old *iface) diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 08641ce6317..fb5177b83e9 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -5518,9 +5518,7 @@ static void test_freeze(void)
count = 0xdeadbeef; hr = ITextDocument_Freeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); - todo_wine ok(count == 1, "expected count to be %d, got %ld\n", 1, count);
style2 = GetWindowLongW(hwnd, GWL_STYLE); @@ -5528,54 +5526,40 @@ static void test_freeze(void)
count = 0xdeadbeef; hr = ITextDocument_Freeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); - todo_wine ok(count == 2, "expected count to be %d, got %ld\n", 2, count);
count = 0xdeadbeef; hr = ITextDocument_Unfreeze(doc, &count); - todo_wine ok(hr == S_FALSE, "ITextDocument_Unfreeze returned %#lx\n", hr); - todo_wine ok(count == 1, "expected count to be %d, got %ld\n", 1, count);
count = 0xdeadbeef; hr = ITextDocument_Unfreeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); - todo_wine ok(count == 0, "expected count to be %d, got %ld\n", 0, count);
count = 0xdeadbeef; hr = ITextDocument_Unfreeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); - todo_wine ok(count == 0, "expected count to be %d, got %ld\n", 0, count);
count = 0xdeadbeef; hr = ITextDocument_Freeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr); - todo_wine ok(count == 1, "expected count to be %d, got %ld\n", 1, count);
count = 0xdeadbeef; hr = ITextDocument_Unfreeze(doc, &count); - todo_wine ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr); - todo_wine ok(count == 0, "expected count to be %d, got %ld\n", 0, count);
count = 0xdeadbeef; hr = ITextDocument_Freeze(doc, NULL); - todo_wine ok(hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr);
count = 0xdeadbeef; hr = ITextDocument_Unfreeze(doc, NULL); - todo_wine ok(hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr);
release_interfaces(&hwnd, &reole, &doc, &selection); diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c index 2777f4eea21..da8e9da5ea6 100644 --- a/dlls/riched20/tests/txtsrv.c +++ b/dlls/riched20/tests/txtsrv.c @@ -863,9 +863,7 @@ static void test_TxDraw(void)
freeze_count = 0xdeadbeef; hr = ITextDocument_Freeze( txtdoc, &freeze_count ); - todo_wine ok( hr == S_OK, "ITextDocument_Freeze returned %#lx\n", hr ); - todo_wine ok( freeze_count == 1, "expected count to be %d, got %ld\n", 1, freeze_count );
hr = ITextServices_TxDraw( txtserv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, (RECTL *)&client, NULL, @@ -873,14 +871,11 @@ static void test_TxDraw(void) ok( hr == S_OK, "got %08lx\n", hr ); hr = ITextServices_TxDraw( txtserv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, (RECTL *)&client, NULL, NULL, NULL, 0, TXTVIEW_ACTIVE ); - todo_wine ok( hr == E_UNEXPECTED, "got %08lx\n", hr );
freeze_count = 0xdeadbeef; hr = ITextDocument_Unfreeze( txtdoc, &freeze_count ); - todo_wine ok( hr == S_OK, "ITextDocument_Unfreeze returned %#lx\n", hr ); - todo_wine ok( freeze_count == 0, "expected count to be %d, got %ld\n", 0, freeze_count );
hr = ITextServices_OnTxInPlaceDeactivate( txtserv ); diff --git a/dlls/riched20/txthost.c b/dlls/riched20/txthost.c index ec6f8e52fa5..412733edaeb 100644 --- a/dlls/riched20/txthost.c +++ b/dlls/riched20/txthost.c @@ -1313,18 +1313,22 @@ static LRESULT RichEditWndProc_common( HWND hwnd, UINT msg, WPARAM wparam, RECT rc, client, update; PAINTSTRUCT ps; HBRUSH brush, old_brush; + LONG view_id;
ITextHost_TxGetClientRect( &host->ITextHost_iface, &client );
if (msg == WM_PAINT) { + /* TODO retrieve if the text document is frozen */ hdc = BeginPaint( hwnd, &ps ); update = ps.rcPaint; + view_id = TXTVIEW_ACTIVE; } else { hdc = (HDC)wparam; update = client; + view_id = TXTVIEW_INACTIVE; }
brush = CreateSolidBrush( ITextHost_TxGetSysColor( &host->ITextHost_iface, COLOR_WINDOW ) ); @@ -1361,7 +1365,7 @@ static LRESULT RichEditWndProc_common( HWND hwnd, UINT msg, WPARAM wparam, }
ITextServices_TxDraw( host->text_srv, DVASPECT_CONTENT, 0, NULL, NULL, hdc, NULL, NULL, NULL, - &update, NULL, 0, TXTVIEW_ACTIVE ); + &update, NULL, 0, view_id ); SelectObject( hdc, old_brush ); DeleteObject( brush ); if (msg == WM_PAINT) EndPaint( hwnd, &ps ); diff --git a/dlls/riched20/txtsrv.c b/dlls/riched20/txtsrv.c index 809bb5ac3ae..55e0c7e64bb 100644 --- a/dlls/riched20/txtsrv.c +++ b/dlls/riched20/txtsrv.c @@ -168,6 +168,8 @@ DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxDraw( ITextServices *iface, DWORD if (aspect != DVASPECT_CONTENT || aspect_info || td || target || mf_bounds || continue_fn ) FIXME( "Many arguments are ignored\n" );
+ if (view_id == TXTVIEW_ACTIVE && services->editor->freeze_count) return E_UNEXPECTED; + hr = update_client_rect( services, (RECT *)bounds ); if (FAILED( hr )) return hr; if (hr == S_OK) rewrap = TRUE;
This merge request was approved by Huw Davies.