Signed-off-by: Jactry Zeng jzeng@codeweavers.com
-- v2: riched20: Add font fallback support.
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com --- dlls/riched20/editor.c | 7 +++---- dlls/riched20/editor.h | 2 +- dlls/riched20/para.c | 2 +- dlls/riched20/reader.c | 2 +- dlls/riched20/run.c | 3 +-- dlls/riched20/style.c | 13 ++++++------- dlls/riched20/undo.c | 3 +-- 7 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 3628e51ac9b..f7106512705 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -1524,8 +1524,7 @@ static void ME_RTFReadHook(RTF_Info *info) { case rtfBeginGroup: if (info->stackTop < maxStack) { - info->stack[info->stackTop].style = info->style; - ME_AddRefStyle(info->style); + info->stack[info->stackTop].style = style_add_ref(info->style); info->stack[info->stackTop].codePage = info->codePage; info->stack[info->stackTop].unicodeLength = info->unicodeLength; } @@ -1608,7 +1607,7 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre else { style = editor->pBuffer->pDefaultStyle; - ME_AddRefStyle(style); + style_add_ref(style); set_selection_cursors(editor, 0, 0); ME_InternalDeleteText(editor, &editor->pCursors[1], ME_GetTextLength(editor), FALSE); @@ -4189,7 +4188,7 @@ LRESULT editor_handle_message( ME_TextEditor *editor, UINT msg, WPARAM wParam, editor->pCursors[1] = editor->pCursors[0]; /* plain text can only have the default style. */ ME_ClearTempStyle(editor); - ME_AddRefStyle(editor->pBuffer->pDefaultStyle); + style_add_ref(editor->pBuffer->pDefaultStyle); ME_ReleaseStyle( editor->pCursors[0].run->style ); editor->pCursors[0].run->style = editor->pBuffer->pDefaultStyle; } diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index 3028d9bdbd5..e3f196c8bdc 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -49,7 +49,7 @@ static inline const char *debugstr_run( const ME_Run *run ) /* style.c */ ME_Style *style_get_insert_style( ME_TextEditor *editor, ME_Cursor *cursor ) DECLSPEC_HIDDEN; ME_Style *ME_MakeStyle(CHARFORMAT2W *style) DECLSPEC_HIDDEN; -void ME_AddRefStyle(ME_Style *item) DECLSPEC_HIDDEN; +ME_Style *style_add_ref( ME_Style *item ) DECLSPEC_HIDDEN; void ME_DestroyStyle(ME_Style *item) DECLSPEC_HIDDEN; void ME_ReleaseStyle(ME_Style *item) DECLSPEC_HIDDEN; ME_Style *ME_ApplyStyle(ME_TextEditor *ed, ME_Style *sSrc, CHARFORMAT2W *style) DECLSPEC_HIDDEN; diff --git a/dlls/riched20/para.c b/dlls/riched20/para.c index 166b1fcd45b..79788c09a02 100644 --- a/dlls/riched20/para.c +++ b/dlls/riched20/para.c @@ -412,7 +412,7 @@ void para_num_init( ME_Context *c, ME_Paragraph *para ) } else { - ME_AddRefStyle( style ); + style_add_ref( style ); }
para->para_num.style = style; diff --git a/dlls/riched20/reader.c b/dlls/riched20/reader.c index b17d6835f25..22986d31fe3 100644 --- a/dlls/riched20/reader.c +++ b/dlls/riched20/reader.c @@ -445,7 +445,7 @@ static void RTFUngetToken(RTF_Info *info) if(RTFCheckCM (info, rtfGroup, rtfEndGroup)) { info->stack[info->stackTop].style = info->style; - ME_AddRefStyle(info->style); + style_add_ref(info->style); info->stackTop++; } } diff --git a/dlls/riched20/run.c b/dlls/riched20/run.c index f6e6f08d12a..2fc498571b8 100644 --- a/dlls/riched20/run.c +++ b/dlls/riched20/run.c @@ -347,8 +347,7 @@ ME_Run *run_create( ME_Style *s, int flags )
if (!item) return NULL;
- ME_AddRefStyle( s ); - run->style = s; + run->style = style_add_ref( s ); run->reobj = NULL; run->nFlags = flags; run->nCharOfs = -1; diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c index 9c9b5cbb4e0..1e57b87d948 100644 --- a/dlls/riched20/style.c +++ b/dlls/riched20/style.c @@ -215,8 +215,7 @@ ME_Style *ME_ApplyStyle(ME_TextEditor *editor, ME_Style *sSrc, CHARFORMAT2W *mod if (!memcmp( &s->fmt, &fmt, sizeof(fmt) )) { TRACE_(richedit_style)("found existing style %p\n", s); - ME_AddRefStyle( s ); - return s; + return style_add_ref( s ); } }
@@ -451,12 +450,13 @@ void ME_DestroyStyle(ME_Style *s) heap_free(s); }
-void ME_AddRefStyle(ME_Style *s) +ME_Style *style_add_ref( ME_Style *s ) { assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */ s->nRefs++; all_refs++; - TRACE_(richedit_style)("ME_AddRefStyle %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs); + TRACE_(richedit_style)( "style %p, new refs %d, total refs %d.\n", s, s->nRefs, all_refs ); + return s; }
void ME_ReleaseStyle(ME_Style *s) @@ -491,15 +491,14 @@ ME_Style *style_get_insert_style( ME_TextEditor *editor, ME_Cursor *cursor ) else style = cursor->run->style;
- ME_AddRefStyle( style ); - return style; + return style_add_ref( style ); }
void ME_SaveTempStyle(ME_TextEditor *editor, ME_Style *style) { ME_Style *old_style = editor->pBuffer->pCharStyle;
- if (style) ME_AddRefStyle( style ); + if (style) style_add_ref( style ); editor->pBuffer->pCharStyle = style; if (old_style) ME_ReleaseStyle( old_style ); } diff --git a/dlls/riched20/undo.c b/dlls/riched20/undo.c index d95ce121234..e500a3e704d 100644 --- a/dlls/riched20/undo.c +++ b/dlls/riched20/undo.c @@ -144,8 +144,7 @@ BOOL add_undo_insert_run( ME_TextEditor *editor, int pos, const WCHAR *str, int undo->u.insert_run.pos = pos; undo->u.insert_run.len = len; undo->u.insert_run.flags = flags; - undo->u.insert_run.style = style; - ME_AddRefStyle( style ); + undo->u.insert_run.style = style_add_ref( style ); return TRUE; }
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com --- dlls/riched20/editor.h | 11 +++++++++ dlls/riched20/editstr.h | 1 + dlls/riched20/run.c | 2 ++ dlls/riched20/wrap.c | 49 ++++++++++++++++++++++++++++++++--------- 4 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index e3f196c8bdc..c4be5eed88b 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -36,6 +36,12 @@ extern HINSTANCE dll_instance DECLSPEC_HIDDEN; (fe).lindex=-1;\ };
+#define MAKE_OPENTYPE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (ULONG)_x4 << 24 ) | \ + ( (ULONG)_x3 << 16 ) | \ + ( (ULONG)_x2 << 8 ) | \ + (ULONG)_x1 ) + static inline WCHAR *get_text( const ME_Run *run, int offset ) { return run->para->text->szData + run->nCharOfs + offset; @@ -46,6 +52,11 @@ static inline const char *debugstr_run( const ME_Run *run ) return debugstr_wn( get_text( run, 0 ), run->len ); }
+static inline const char *debugstr_tag( OPENTYPE_TAG tag ) +{ + return debugstr_an( (char *)&tag, 4 ); +} + /* style.c */ ME_Style *style_get_insert_style( ME_TextEditor *editor, ME_Cursor *cursor ) DECLSPEC_HIDDEN; ME_Style *ME_MakeStyle(CHARFORMAT2W *style) DECLSPEC_HIDDEN; diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 3b166234f23..683a83e7154 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -176,6 +176,7 @@ typedef struct tagME_Run GOFFSET *offsets; int max_clusters; WORD *clusters; + OPENTYPE_TAG script_tag; } ME_Run;
typedef struct tagME_Border diff --git a/dlls/riched20/run.c b/dlls/riched20/run.c index 2fc498571b8..0a81acdec8a 100644 --- a/dlls/riched20/run.c +++ b/dlls/riched20/run.c @@ -314,6 +314,7 @@ ME_Run *run_split( ME_TextEditor *editor, ME_Cursor *cursor ) new_run->nCharOfs = run->nCharOfs + nOffset; new_run->len = run->len - nOffset; new_run->para = run->para; + new_run->script_tag = run->script_tag; run->len = nOffset; cursor->run = new_run; cursor->nOffset = 0; @@ -361,6 +362,7 @@ ME_Run *run_create( ME_Style *s, int flags ) run->offsets = NULL; run->max_clusters = 0; run->clusters = NULL; + run->script_tag = 0; return run; }
diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index db3e2806239..2c2ee46371f 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -63,6 +63,8 @@ static BOOL get_run_glyph_buffers( ME_Run *run )
static HRESULT shape_run( ME_Context *c, ME_Run *run ) { + SCRIPT_GLYPHPROP *glyph_prop; + SCRIPT_CHARPROP *char_prop; HRESULT hr; int i;
@@ -80,11 +82,20 @@ static HRESULT shape_run( ME_Context *c, ME_Run *run ) run->clusters = heap_alloc( run->max_clusters * sizeof(WORD) ); }
+ if (!(char_prop = heap_alloc( run->len * sizeof( *char_prop ) ))) + return E_OUTOFMEMORY; + if (!(glyph_prop = heap_alloc( run->len * sizeof( *glyph_prop ) ))) + { + heap_free( char_prop ); + return E_OUTOFMEMORY; + } + select_style( c, run->style ); while (1) { - 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 ); + hr = ScriptShapeOpenType( c->hDC, &run->style->script_cache, &run->script_analysis, run->script_tag, 0, + NULL, NULL, 0, get_text( run, 0 ), run->len, run->max_glyphs, run->clusters, + char_prop, run->glyphs, glyph_prop, &run->num_glyphs ); if (hr != E_OUTOFMEMORY) break; if (run->max_glyphs > 10 * run->len) break; /* something has clearly gone wrong */ run->max_glyphs *= 2; @@ -92,8 +103,12 @@ 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, - &run->script_analysis, run->advances, run->offsets, NULL ); + hr = ScriptPlaceOpenType( c->hDC, &run->style->script_cache, &run->script_analysis, run->script_tag, 0, + NULL, NULL, 0, get_text( run, 0 ), run->clusters, char_prop, run->len, run->glyphs, + glyph_prop, run->num_glyphs, run->advances, run->offsets, NULL ); + + heap_free( char_prop ); + heap_free( glyph_prop );
if (SUCCEEDED(hr)) { @@ -725,6 +740,7 @@ static HRESULT itemize_para( ME_Context *c, ME_Paragraph *para ) { ME_Run *run; SCRIPT_ITEM buf[16], *items = buf; + OPENTYPE_TAG tags[16], *script_tags = tags; int items_passed = ARRAY_SIZE( buf ), num_items, cur_item; SCRIPT_CONTROL control = { LANG_USER_DEFAULT, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0 }; @@ -738,16 +754,23 @@ static HRESULT itemize_para( ME_Context *c, ME_Paragraph *para )
while (1) { - hr = ScriptItemize( para->text->szData, para->text->nLen, items_passed, &control, - &state, items, &num_items ); + hr = ScriptItemizeOpenType( para->text->szData, para->text->nLen, items_passed, &control, + &state, items, script_tags, &num_items ); + if (hr != E_OUTOFMEMORY) break; /* may not be enough items if hr == E_OUTOFMEMORY */ if (items_passed > para->text->nLen + 1) break; /* something else has gone wrong */ items_passed *= 2; if (items == buf) + { items = heap_alloc( items_passed * sizeof( *items ) ); + script_tags = heap_alloc( items_passed * sizeof( *script_tags ) ); + } else + { items = heap_realloc( items, items_passed * sizeof( *items ) ); - if (!items) break; + script_tags = heap_realloc( script_tags, items_passed * sizeof( *script_tags ) ); + } + if (!items || !script_tags) break; } if (FAILED( hr )) goto end;
@@ -760,9 +783,10 @@ static HRESULT itemize_para( ME_Context *c, ME_Paragraph *para ) items[cur_item].a.fRTL, items[cur_item].a.s.uBidiLevel ); }
- TRACE( "before splitting runs into ranges\n" ); + TRACE( "before splitting runs into ranges:\n" ); for (run = para_first_run( para ); run; run = run_next( run )) - TRACE( "\t%d: %s\n", run->nCharOfs, debugstr_run( run ) ); + TRACE( "\t%d %s: %s\n", run->nCharOfs, run->script_tag ? debugstr_tag( run->script_tag ) : " ", + debugstr_run( run ) ); }
/* split runs into ranges at item boundaries */ @@ -772,6 +796,7 @@ static HRESULT itemize_para( ME_Context *c, ME_Paragraph *para )
items[cur_item].a.fLogicalOrder = TRUE; run->script_analysis = items[cur_item].a; + run->script_tag = script_tags[cur_item];
if (run->nFlags & MERF_ENDPARA) break; /* don't split eop runs */
@@ -784,15 +809,17 @@ static HRESULT itemize_para( ME_Context *c, ME_Paragraph *para )
if (TRACE_ON( richedit )) { - TRACE( "after splitting into ranges\n" ); + TRACE( "after splitting runs into ranges:\n" ); for (run = para_first_run( para ); run; run = run_next( run )) - TRACE( "\t%d: %s\n", run->nCharOfs, debugstr_run( run ) ); + TRACE( "\t%d %s: %s\n", run->nCharOfs, run->script_tag ? debugstr_tag( run->script_tag ) : " ", + debugstr_run( run ) ); }
para->nFlags |= MEPF_COMPLEX;
end: if (items != buf) heap_free( items ); + if (script_tags != tags) heap_free( script_tags ); return hr; }
From: Jactry Zeng jzeng@codeweavers.com
Signed-off-by: Jactry Zeng jzeng@codeweavers.com --- dlls/riched20/editor.h | 1 + dlls/riched20/editstr.h | 1 + dlls/riched20/paint.c | 17 +++++ dlls/riched20/run.c | 5 +- dlls/riched20/style.c | 12 ++++ dlls/riched20/tests/editor.c | 52 ++++++++++++++ dlls/riched20/wrap.c | 127 +++++++++++++++++++++++++++++++++++ 7 files changed, 214 insertions(+), 1 deletion(-)
diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index c4be5eed88b..9fc70a3e4c4 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -74,6 +74,7 @@ BOOL cfany_to_cf2w(CHARFORMAT2W *to, const CHARFORMAT2W *from) DECLSPEC_HIDDEN; BOOL cf2w_to_cfany(CHARFORMAT2W *to, const CHARFORMAT2W *from) DECLSPEC_HIDDEN; void ME_CopyCharFormat(CHARFORMAT2W *pDest, const CHARFORMAT2W *pSrc) DECLSPEC_HIDDEN; /* only works with 2W structs */ void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt) DECLSPEC_HIDDEN; /* ditto */ +ME_Style *duplicate_style( ME_Style *style );
/* list.c */ void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) DECLSPEC_HIDDEN; diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 683a83e7154..12339f0a541 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -76,6 +76,7 @@ typedef struct tagME_Style int nRefs; /* reference count */ SCRIPT_CACHE script_cache; struct list entry; + LOGFONTW fallback_font; } ME_Style;
typedef enum { diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index 245afff77dc..ebedd19b321 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -363,9 +363,26 @@ 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) + { + HFONT old_font = NULL, fallback = NULL; + + if (run->style->fallback_font.lfFaceName[0]) + { + fallback = CreateFontIndirectW( &run->style->fallback_font ); + if (fallback) + old_font = SelectObject( c->hDC, fallback ); + } + 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 ); + + if (old_font) + { + SelectObject( c->hDC, old_font ); + DeleteObject( fallback ); + } + } else ExtTextOutW( c->hDC, x, y, paint_bg ? ETO_OPAQUE : 0, sel_rect, text, run->len, NULL );
diff --git a/dlls/riched20/run.c b/dlls/riched20/run.c index 0a81acdec8a..fb16adc4d39 100644 --- a/dlls/riched20/run.c +++ b/dlls/riched20/run.c @@ -348,7 +348,10 @@ ME_Run *run_create( ME_Style *s, int flags )
if (!item) return NULL;
- run->style = style_add_ref( s ); + if (s->fallback_font.lfFaceName[0]) + run->style = duplicate_style( s ); + else + run->style = style_add_ref( s ); run->reobj = NULL; run->nFlags = flags; run->nCharOfs = -1; diff --git a/dlls/riched20/style.c b/dlls/riched20/style.c index 1e57b87d948..034ce924b93 100644 --- a/dlls/riched20/style.c +++ b/dlls/riched20/style.c @@ -129,12 +129,24 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) memset(&s->tm, 0, sizeof(s->tm)); s->tm.tmAscent = -1; s->script_cache = NULL; + memset( &s->fallback_font, 0, sizeof( s->fallback_font ) ); list_init(&s->entry); all_refs++; TRACE_(richedit_style)("ME_MakeStyle %p, total refs=%d\n", s, all_refs); return s; }
+ME_Style *duplicate_style( ME_Style *style ) +{ + ME_Style *new_style; + + new_style = ME_MakeStyle( &style->fmt ); + new_style->tm = style->tm; + new_style->fallback_font = style->fallback_font; + + return new_style; +} + #define COPY_STYLE_ITEM(mask, member) \ if (mod->dwMask & mask) { \ fmt.dwMask |= mask;\ diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c index 03c07829ee4..7e6325da1a9 100644 --- a/dlls/riched20/tests/editor.c +++ b/dlls/riched20/tests/editor.c @@ -9026,6 +9026,57 @@ static void test_window_classes(void) } }
+static void test_font_fallback(void) +{ + static const WCHAR text[] = L"English\x65e5\x672c\x8a9e\x306b\x307b\x3093\x3054\x30cb\x30db\x30f3\x30b4" + "\xd55c\xad6d\xc5b4\x7b80\x4f53\x5b57\x7e41\x9ad4\x5b57"; + CHARFORMAT2W format; + WCHAR buffer[1024]; + LRESULT result; + HWND hwnd; + int i; + struct font_fallback_test + { + int start, end; + const WCHAR *expected_string; + } font_fallback_tests[] = + { + { 0, 7, L"English" }, + { 7, 10, L"\x65e5\x672c\x8a9e" }, /* Kanji */ + { 10, 14, L"\x306b\x307b\x3093\x3054" }, /* Hiragana */ + { 14, 18, L"\x30cb\x30db\x30f3\x30b4" }, /* Katakana */ + { 18, 21, L"\xd55c\xad6d\xc5b4" }, /* Hangeul */ + { 21, 24, L"\x7b80\x4f53\x5b57" }, /* Simplified Chinese */ + { 24, 27, L"\x7e41\x9ad4\x5b57" }, /* Traditional Chinese */ + { 5, 9, L"sh\x65e5\x672c" }, /* Latin and Kanji */ + }; + + hwnd = new_richeditW(NULL); + + SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)text); + memset(&format, 0, sizeof(format)); + format.cbSize = sizeof(format); + format.dwMask = CFM_FACE; + lstrcpyW(format.szFaceName, L"Tahoma"); + result = SendMessageW(hwnd, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&format); + ok(result, "Failed to set default format.\n"); + + for (i = 0; i < ARRAYSIZE(font_fallback_tests); i++) + { + SendMessageW(hwnd, EM_SETSEL, font_fallback_tests[i].start, font_fallback_tests[i].end); + memset(buffer, 0, sizeof(buffer)); + result = SendMessageW(hwnd, EM_GETSELTEXT, sizeof(buffer), (LPARAM)buffer); + ok(!lstrcmpW(buffer, font_fallback_tests[i].expected_string), "Got wrong string %s.\n", debugstr_w(buffer)); + memset(&format, 0, sizeof(format)); + format.cbSize = sizeof(format); + result = SendMessageW(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); + ok(result, "Failed to get format.\n"); + ok(!lstrcmpW(format.szFaceName, L"Tahoma"), "Got wrong font name %s.\n", debugstr_w(format.szFaceName)); + } + + DestroyWindow(hwnd); +} + START_TEST( editor ) { BOOL ret; @@ -9102,6 +9153,7 @@ START_TEST( editor ) test_eop_char_fmt(); test_para_numbering(); test_EM_SELECTIONTYPE(); + test_font_fallback();
/* Set the environment variable WINETEST_RICHED20 to keep windows * responsive and open for 30 seconds. This is useful for debugging. diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index 2c2ee46371f..21cbcb3e420 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -61,8 +61,102 @@ static BOOL get_run_glyph_buffers( ME_Run *run ) return TRUE; }
+static WCHAR hang_font[LF_FACESIZE] = L"Gulim"; +static WCHAR hani_font[LF_FACESIZE] = L"Simsun"; +static WCHAR kana_font[LF_FACESIZE] = L"MS UI Gothic"; +static BOOL fallbacks_initialized = FALSE; + +struct richedit_fallback +{ + OPENTYPE_TAG script_tag; + WCHAR *font_name; +} richedit_fallbacks[] = +{ + { MAKE_OPENTYPE_TAG( 'h','a','n','g' ), hang_font }, + { MAKE_OPENTYPE_TAG( 'h','a','n','i' ), hani_font }, + { MAKE_OPENTYPE_TAG( 'k','a','n','a' ), kana_font }, +}; + +static void init_richedit_fallbacks( void ) +{ + LCID lcid; + + if (fallbacks_initialized) + return; + + /* Setting proper font for "hani". */ + lcid = GetSystemDefaultLangID(); + switch (PRIMARYLANGID( lcid )) + { + case LANG_CHINESE: + { + switch (SUBLANGID( lcid )) + { + case SUBLANG_CHINESE_HONGKONG: + case SUBLANG_CHINESE_MACAU: + case SUBLANG_CHINESE_TRADITIONAL: + lstrcpyW( hani_font, L"PMingLiU" ); + break; + case SUBLANG_CHINESE_SIMPLIFIED: + lstrcpyW( hani_font, L"Simsun" ); + break; + } + break; + } + case LANG_JAPANESE: + lstrcpyW( hani_font, L"MS UI Gothic" ); + break; + case LANG_KOREAN: + lstrcpyW( hani_font, L"Gulim" ); + break; + } + + fallbacks_initialized = TRUE; +} + +static const WCHAR *find_fallback_font( OPENTYPE_TAG script_tag ) +{ + int count; + + init_richedit_fallbacks(); + + count = ARRAYSIZE( richedit_fallbacks ); + while (count--) + if (richedit_fallbacks[count].script_tag == script_tag) + return richedit_fallbacks[count].font_name; + + WARN( "Failed to find a fallback font for %s.\n", debugstr_tag( script_tag ) ); + return NULL; +} + +static BOOL requires_fallback( HDC dc, ME_Run *run ) +{ + SCRIPT_CACHE script_cache = NULL; + static const WCHAR *text; + WORD *glyphs; + int len; + + if (!run->script_tag) + return FALSE; + + len = run->len; + if (!(glyphs = heap_calloc( len, sizeof( *glyphs ) ))) + return FALSE; + + text = get_text( run, 0 ); + if (ScriptGetCMap( dc, &script_cache, text, len, 0, glyphs ) != S_OK) + { + heap_free( glyphs ); + return TRUE; + } + heap_free( glyphs ); + + return FALSE; +} + static HRESULT shape_run( ME_Context *c, ME_Run *run ) { + HFONT old_font = NULL, fallback = NULL; SCRIPT_GLYPHPROP *glyph_prop; SCRIPT_CHARPROP *char_prop; HRESULT hr; @@ -91,6 +185,33 @@ static HRESULT shape_run( ME_Context *c, ME_Run *run ) }
select_style( c, run->style ); + if (requires_fallback( c->hDC, run )) + { + static const WCHAR *font_name; + + font_name = find_fallback_font( run->script_tag ); + if (font_name) + { + if ( lstrcmpW( run->style->fallback_font.lfFaceName, font_name )) + { + ME_Style *style; + + GetObjectW( GetCurrentObject( c->hDC, OBJ_FONT ), sizeof( run->style->fallback_font ), + &run->style->fallback_font ); + style = duplicate_style( run->style ); + ME_ReleaseStyle( run->style ); + run->style = style; + lstrcpyW( run->style->fallback_font.lfFaceName, font_name ); + } + TRACE( "Falling back to %s font for %s.\n", debugstr_w( font_name ), debugstr_tag( run->script_tag ) ); + fallback = CreateFontIndirectW( &run->style->fallback_font ); + if (fallback) + old_font = SelectObject( c->hDC, fallback ); + } + } + else + run->style->fallback_font.lfFaceName[0] = 0; + while (1) { hr = ScriptShapeOpenType( c->hDC, &run->style->script_cache, &run->script_analysis, run->script_tag, 0, @@ -107,6 +228,12 @@ static HRESULT shape_run( ME_Context *c, ME_Run *run ) NULL, NULL, 0, get_text( run, 0 ), run->clusters, char_prop, run->len, run->glyphs, glyph_prop, run->num_glyphs, run->advances, run->offsets, NULL );
+ if (old_font) + { + SelectObject( c->hDC, old_font ); + DeleteObject( fallback ); + } + heap_free( char_prop ); heap_free( glyph_prop );
Huw Davies (@huw) commented about dlls/riched20/style.c:
heap_free(s); }
-void ME_AddRefStyle(ME_Style *s) +ME_Style *style_add_ref( ME_Style *s ) { assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */ s->nRefs++; all_refs++;
- TRACE_(richedit_style)("ME_AddRefStyle %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs);
- TRACE_(richedit_style)( "style %p, new refs %d, total refs %d.\n", s, s->nRefs, all_refs );
- return s;
}
I'm not convinced that this is an improvement. Whilst it does allow an assignment and the reference to be written on a single line, it's not very conventional and I found myself checking that the returned ptr was the same as the passed in ptr.
Huw Davies (@huw) commented about dlls/riched20/wrap.c:
run->clusters = heap_alloc( run->max_clusters * sizeof(WORD) ); }
- if (!(char_prop = heap_alloc( run->len * sizeof( *char_prop ) )))
return E_OUTOFMEMORY;
- if (!(glyph_prop = heap_alloc( run->len * sizeof( *glyph_prop ) )))
This needs to be `max_glyphs` long.
However it should be allocated in `get_run_glyph_buffers()` instead of `run->vis_attr`. The code that uses `run->vis_attr` should then be changed to use the glpyh props instead. It may help to reduce the patch size by making this simple change first.