Manipulating the font size results in the script_cache going stale. From MSDN[1]
`The application should never pass the same handle for different fonts or different sizes.`
This is however exactly what happens when the font size changes as a result of zooming(both in and out). ScriptShape and relative functions will only inspect the hardware device context only if the required data is not cached[2] and hence the data from a previous call to these functions is retrieved even though the font size has changed hence the bug where text both doesn't wrap and doesn't paint as it should.
In patch one, I have tried to keep track of the script_cache objects alongside the relevant font.
Patch two fixes an issue where the cursor doesn't scale after zooming until after one interacts with the editor.
Signed-off-by: David Kahurani k.kahurani@gmail.com
1. https://docs.microsoft.com/en-us/windows/win32/intl/caching 2. https://docs.microsoft.com/en-us/windows/win32/intl/script-cache
-- v3: riched20: update caret on zooming riched20: Cache script_cache alongside font cache
From: David Kahurani k.kahurani@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46475 Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/riched20/editor.c | 4 ++++ dlls/riched20/editstr.h | 3 ++- dlls/riched20/paint.c | 2 +- dlls/riched20/style.c | 5 +++-- dlls/riched20/wrap.c | 4 ++-- 5 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 57601745ab2..e143805e14c 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -2994,6 +2994,7 @@ ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10) ed->pFontCache[i].nRefs = 0; ed->pFontCache[i].nAge = 0; ed->pFontCache[i].hFont = NULL; + ed->pScriptCache[i] = NULL; }
ME_CheckCharOffsets(ed); @@ -3079,6 +3080,9 @@ void ME_DestroyEditor(ME_TextEditor *editor) { if (editor->pFontCache[i].hFont) DeleteObject(editor->pFontCache[i].hFont); + + if (editor->pScriptCache[i]) + ScriptFreeCache(&editor->pScriptCache[i]); } if(editor->lpOleCallback) IRichEditOleCallback_Release(editor->lpOleCallback); diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index db219d7e4df..08e9682dbd3 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -74,7 +74,7 @@ typedef struct tagME_Style ME_FontCacheItem *font_cache; /* cached font for the style */ TEXTMETRICW tm; /* cached font metrics for the style */ int nRefs; /* reference count */ - SCRIPT_CACHE script_cache; + SCRIPT_CACHE *script_cache; struct list entry; } ME_Style;
@@ -413,6 +413,7 @@ typedef struct tagME_TextEditor LONG nLastSelStart, nLastSelEnd; ME_Paragraph *last_sel_start_para, *last_sel_end_para; ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE]; + SCRIPT_CACHE pScriptCache[HFONT_CACHE_SIZE]; int nZoomNumerator, nZoomDenominator; RECT rcFormat; BOOL bWordWrap; diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index 245afff77dc..32dc13bc93f 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -363,7 +363,7 @@ static void draw_text( ME_Context *c, ME_Run *run, int x, int y, BOOL selected, if (paint_bg) old_back = SetBkColor( c->hDC, back_color );
if (run->para->nFlags & MEPF_COMPLEX) - ScriptTextOut( c->hDC, &run->style->script_cache, x, y, paint_bg ? ETO_OPAQUE : 0, sel_rect, + ScriptTextOut( c->hDC, run->style->script_cache, x, y, paint_bg ? ETO_OPAQUE : 0, sel_rect, &run->script_analysis, NULL, 0, run->glyphs, run->num_glyphs, run->advances, NULL, run->offsets ); else diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c index 9c9b5cbb4e0..a8941c59c2f 100644 --- a/dlls/riched20/style.c +++ b/dlls/riched20/style.c @@ -400,6 +400,7 @@ void select_style( ME_Context *c, ME_Style *s ) if (i < HFONT_CACHE_SIZE) /* found */ { item = &c->editor->pFontCache[i]; + s->script_cache = &c->editor->pScriptCache[i]; TRACE_(richedit_style)( "font reused %d\n", i ); item->nRefs++; } @@ -407,10 +408,12 @@ void select_style( ME_Context *c, ME_Style *s ) { assert(empty != -1); item = &c->editor->pFontCache[empty]; + s->script_cache = &c->editor->pScriptCache[empty]; if (item->hFont) { TRACE_(richedit_style)( "font deleted %d\n", empty ); DeleteObject(item->hFont); + ScriptFreeCache(s->script_cache); item->hFont = NULL; } item->hFont = CreateFontIndirectW( &lf ); @@ -447,7 +450,6 @@ void ME_DestroyStyle(ME_Style *s) release_font_cache( s->font_cache ); s->font_cache = NULL; } - ScriptFreeCache( &s->script_cache ); heap_free(s); }
@@ -534,7 +536,6 @@ void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod) release_font_cache( def->font_cache ); def->font_cache = NULL; } - ScriptFreeCache( &def->script_cache ); ME_ReleaseStyle( style ); editor_mark_rewrap_all( editor ); } diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index 8cfb1692ecd..68baf128d2b 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -83,7 +83,7 @@ static HRESULT shape_run( ME_Context *c, ME_Run *run ) select_style( c, run->style ); while (1) { - hr = ScriptShape( c->hDC, &run->style->script_cache, get_text( run, 0 ), run->len, run->max_glyphs, + hr = ScriptShape( c->hDC, run->style->script_cache, get_text( run, 0 ), run->len, run->max_glyphs, &run->script_analysis, run->glyphs, run->clusters, run->vis_attrs, &run->num_glyphs ); if (hr != E_OUTOFMEMORY) break; if (run->max_glyphs > 10 * run->len) break; /* something has clearly gone wrong */ @@ -92,7 +92,7 @@ static HRESULT shape_run( ME_Context *c, ME_Run *run ) }
if (SUCCEEDED(hr)) - hr = ScriptPlace( c->hDC, &run->style->script_cache, run->glyphs, run->num_glyphs, run->vis_attrs, + hr = ScriptPlace( c->hDC, run->style->script_cache, run->glyphs, run->num_glyphs, run->vis_attrs, &run->script_analysis, run->advances, run->offsets, NULL );
if (SUCCEEDED(hr))
From: David Kahurani k.kahurani@gmail.com
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/riched20/paint.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index 32dc13bc93f..468223bab7c 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -1319,5 +1319,7 @@ ME_SetZoom(ME_TextEditor *editor, int numerator, int denominator) editor->nZoomDenominator = denominator;
ME_RewrapRepaint(editor); + update_caret( editor ); + return TRUE; }
On Fri Aug 26 09:54:12 2022 +0000, David Kahurani wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/626/diffs?diff_id=8862&start_sha=27d98dcf2854bff924fa5fc8732ce31a6f8cf401#335b96cff496969d4b9c6774b9738828a552e0e5_453_453)
I didn't initially look at these but on taking a look it doesn't look like the script_cache needs to be freed on these two instances. select_style will free the script_cache when the slot is needed.
Any updates on this?