-- v5: gdiplus: Implement font linking for gdiplus. gdiplus/tests: Add interactive test for font linking. mlang: Fix bug with codepage priority in GetStrCodePages. mlang/tests: Test codepages priority bug in GetStrCodepages. mlang: Implement GetGlobalFontLinkObject. mlang/tests: Test for GetGlobalFontLinkObject.
From: Santino Mazza smazza@codeweavers.com
--- dlls/mlang/tests/mlang.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/mlang/tests/mlang.c b/dlls/mlang/tests/mlang.c index ee5ef5af738..b3e568a7316 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -2295,6 +2295,11 @@ static void test_GetGlobalFontLinkObject(void) { HRESULT ret; void *unknown; + LONG refcount; + IMLangFontLink2 *IMLFL2; + IMLangFontLink *IMLFL; + IMLangCodePages *IMLCP; + IMultiLanguage *IML;
ret = GetGlobalFontLinkObject(NULL); ok(ret == E_INVALIDARG, "expected E_INVALIDARG got %#lx\n", ret); @@ -2305,7 +2310,26 @@ todo_wine { ok(ret == S_OK, "expected S_OK got %#lx\n", ret); ok(unknown != NULL && unknown != (void *)0xdeadbeef, "GetGlobalFontLinkObject() returned %p\n", unknown); + if (unknown == (void *)0xdeadbeef || !unknown) return; } + + ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink2, (void**)&IMLFL2); + ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + + ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMultiLanguage, (void**)&IML); + ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + + ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink, (void**)&IMLFL); + ok(ret == S_OK, "expected E_NOINTERFACE got %#lx\n", ret); + IMLangFontLink_Release(IMLFL); + + ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangCodePages, (void**)&IMLCP); + ok(ret == S_OK, "expected E_NOINTERFACE got %#lx\n", ret); + IMLangCodePages_Release(IMLCP); + + + refcount = IUnknown_Release((IUnknown*)unknown); + ok(refcount == 1, "Got refcount %ld\n", refcount); }
static void test_IMLangConvertCharset(IMultiLanguage *ml) @@ -2778,6 +2802,8 @@ START_TEST(mlang) if (!init_function_ptrs()) return;
+ test_GetGlobalFontLinkObject(); + CoInitialize(NULL); test_Rfc1766ToLcid(); test_LcidToRfc1766(); @@ -2785,8 +2811,6 @@ START_TEST(mlang) test_ConvertINetUnicodeToMultiByte(); test_JapaneseConversion();
- test_GetGlobalFontLinkObject(); - trace("IMultiLanguage\n"); ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, &IID_IMultiLanguage, (void **)&iML);
From: Santino Mazza smazza@codeweavers.com
--- dlls/mlang/mlang.c | 12 ++++++++++-- dlls/mlang/tests/mlang.c | 8 ++++---- 2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/dlls/mlang/mlang.c b/dlls/mlang/mlang.c index f424c87b860..1a6a2ed5dc6 100644 --- a/dlls/mlang/mlang.c +++ b/dlls/mlang/mlang.c @@ -44,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mlang);
#include "initguid.h"
+static IUnknown *font_link_global = NULL; + static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj); static HRESULT MLangConvertCharset_create(IUnknown *outer, void **obj); static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum); @@ -3884,9 +3886,15 @@ HRESULT WINAPI DllCanUnloadNow(void)
HRESULT WINAPI GetGlobalFontLinkObject(void **unknown) { + TRACE("%p\n", unknown); + if (!unknown) return E_INVALIDARG;
- FIXME("%p: stub\n", unknown); + if (!font_link_global) + MultiLanguage_create(NULL, (void**)&font_link_global);
- return S_FALSE; + IUnknown_AddRef(font_link_global); + *unknown = font_link_global; + + return S_OK; } diff --git a/dlls/mlang/tests/mlang.c b/dlls/mlang/tests/mlang.c index b3e568a7316..046dc2a3463 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -2306,18 +2306,18 @@ static void test_GetGlobalFontLinkObject(void)
unknown = (void *)0xdeadbeef; ret = GetGlobalFontLinkObject(&unknown); -todo_wine { ok(ret == S_OK, "expected S_OK got %#lx\n", ret); ok(unknown != NULL && unknown != (void *)0xdeadbeef, "GetGlobalFontLinkObject() returned %p\n", unknown); if (unknown == (void *)0xdeadbeef || !unknown) return; - }
ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink2, (void**)&IMLFL2); - ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + todo_wine ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + if (ret == S_OK) IMLangFontLink2_Release(IMLFL2);
ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMultiLanguage, (void**)&IML); - ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + todo_wine ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret); + if (ret == S_OK) IMultiLanguage_Release(IML);
ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink, (void**)&IMLFL); ok(ret == S_OK, "expected E_NOINTERFACE got %#lx\n", ret);
From: Santino Mazza smazza@codeweavers.com
--- dlls/mlang/tests/mlang.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/mlang/tests/mlang.c b/dlls/mlang/tests/mlang.c index 046dc2a3463..9241ebead87 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -1324,6 +1324,14 @@ static void IMLangFontLink_Test(IMLangFontLink* iMLFL) ok(dwCodePages == dwCmpCodePages, "expected %lx, got %lx\n", dwCmpCodePages, dwCodePages); ok(processed == 2, "expected 2, got %ld\n", processed);
+ dwCmpCodePages = FS_JISJAPAN; + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, L"\uff90a", 2, FS_LATIN1, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %lx\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %lx, got %lx\n", dwCmpCodePages, dwCodePages); + todo_wine ok(processed == 1, "expected 1, got %ld\n", processed); + dwCodePages = 0xffff; processed = -1; ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
From: Santino Mazza smazza@codeweavers.com
--- dlls/mlang/mlang.c | 3 ++- dlls/mlang/tests/mlang.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/mlang/mlang.c b/dlls/mlang/mlang.c index 1a6a2ed5dc6..cc797ecac6b 100644 --- a/dlls/mlang/mlang.c +++ b/dlls/mlang/mlang.c @@ -3344,7 +3344,8 @@ static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* iface, if (ret != S_OK) return E_FAIL;
if (!cps) cps = cp; - else if ((cps & cp) != 0) cps &= cp; + else if ((cps & cp) != 0 && + ((priority_cp & cps) || !(priority_cp & cp))) cps &= cp; else { i--; diff --git a/dlls/mlang/tests/mlang.c b/dlls/mlang/tests/mlang.c index 9241ebead87..06a288419db 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -1330,7 +1330,7 @@ static void IMLangFontLink_Test(IMLangFontLink* iMLFL) ret = IMLangFontLink_GetStrCodePages(iMLFL, L"\uff90a", 2, FS_LATIN1, &dwCodePages, &processed); ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %lx\n", ret); ok(dwCodePages == dwCmpCodePages, "expected %lx, got %lx\n", dwCmpCodePages, dwCodePages); - todo_wine ok(processed == 1, "expected 1, got %ld\n", processed); + ok(processed == 1, "expected 1, got %ld\n", processed);
dwCodePages = 0xffff; processed = -1;
From: Santino Mazza smazza@codeweavers.com
--- dlls/gdiplus/tests/graphics.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index d71bc78c2ae..f23a26ad0c8 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -2305,10 +2305,26 @@ static void test_GdipDrawString(void) } expect(Ok, status);
- status = GdipCreateSolidFill((ARGB)0xdeadbeef, (GpSolidFill**)&brush); + status = GdipCreateStringFormat(0,0,&format); expect(Ok, status);
- status = GdipCreateStringFormat(0,0,&format); + if (winetest_interactive) + { + status = GdipCreateSolidFill(0xF0000000, (GpSolidFill**)&brush); + expect(Ok, status); + rect.X = 0; + rect.Y = 0; + rect.Width = 0; + rect.Height = 14; + GdipGraphicsClear(graphics, 0xF0FFFFFF); + status = GdipDrawString(graphics, L"\u8336Hola\u8336", 6, fnt, &rect, format, brush); + expect(Ok, status); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); /* FIXME: In Windows this test works without this line. */ + Sleep(4000); + GdipDeleteBrush(brush); + } + + status = GdipCreateSolidFill((ARGB)0xdeadbeef, (GpSolidFill**)&brush); expect(Ok, status);
rect.X = 0;
From: Santino Mazza smazza@codeweavers.com
--- dlls/gdiplus/Makefile.in | 2 +- dlls/gdiplus/gdiplus_private.h | 24 ++++++- dlls/gdiplus/graphics.c | 119 ++++++++++++++++++++++++++++++--- dlls/gdiplus/graphicspath.c | 2 +- 4 files changed, 136 insertions(+), 11 deletions(-)
diff --git a/dlls/gdiplus/Makefile.in b/dlls/gdiplus/Makefile.in index 382033be901..76474f2e086 100644 --- a/dlls/gdiplus/Makefile.in +++ b/dlls/gdiplus/Makefile.in @@ -1,6 +1,6 @@ MODULE = gdiplus.dll IMPORTLIB = gdiplus -IMPORTS = uuid shlwapi ole32 oleaut32 user32 gdi32 +IMPORTS = uuid shlwapi ole32 oleaut32 user32 gdi32 mlang DELAYIMPORTS = windowscodecs
SOURCES = \ diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 6f7e72124c2..35511b3e612 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -606,8 +606,30 @@ static inline const void *buffer_read(struct memory_buffer *mbuf, INT size) return NULL; }
+/* Represents a string section and the font it should use. */ +struct gdip_font_link_section { + DWORD index; /* The starting index of the string where the font applies. */ + DWORD len; /* The length of the section. */ + GpFont *font; +}; + +struct gdip_font_link_info { + GDIPCONST GpFont *base_font; + struct gdip_font_link_section *sections; + INT count; +}; + +/* Get the corresponding section for the specified index */ + +void generate_font_link_info(HDC hdc, WCHAR *string, DWORD length, GDIPCONST GpFont *base_font, + struct gdip_font_link_info *font_link_info); + +struct gdip_font_link_section *get_font_link_section(struct gdip_font_link_info *font_link_info, DWORD index); + +void release_font_link_info(struct gdip_font_link_info *font_link_info); + typedef GpStatus (*gdip_format_string_callback)(HDC hdc, - GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, + GDIPCONST WCHAR *string, INT index, INT length, struct gdip_font_link_info *sections, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, INT lineno, const RectF *bounds, INT *underlined_indexes, INT underlined_index_count, void *user_data); diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 5101378d0e1..5818fa49fd9 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -34,6 +34,7 @@ #include "winreg.h" #include "shlwapi.h"
+#include "mlang.h" #include "gdiplus.h" #include "gdiplus_private.h" #include "wine/debug.h" @@ -5161,6 +5162,88 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT w return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result); }
+/* Populates gdip_font_link_info struct based on the base_font and input string */ +void generate_font_link_info(HDC hdc, WCHAR *string, DWORD length, GDIPCONST GpFont *base_font, + struct gdip_font_link_info *font_link_info) +{ + IUnknown *unk; + IMLangFontLink *iMLFL; + GpFont *gpfont; + GpGraphics *graphics; + HFONT map_hfont, hfont, old_font; + LONG processed, progress = 0; + DWORD sections_count = 0; + struct gdip_font_link_section section; + DWORD font_codepages, string_codepages; + + font_link_info->base_font = base_font; + + GetGlobalFontLinkObject((void**)&unk); + IUnknown_QueryInterface(unk, &IID_IMLangFontLink, (void**)&iMLFL); + IUnknown_Release(unk); + + GdipCreateFromHDC(hdc, &graphics); + get_font_hfont(graphics, base_font, NULL, &hfont, NULL, NULL); + IMLangFontLink_GetFontCodePages(iMLFL, hdc, hfont, &font_codepages); + GdipDeleteGraphics(graphics); + + while (progress < length) + { + section.index = progress; + IMLangFontLink_GetStrCodePages(iMLFL, &string[progress], length - progress, + font_codepages, &string_codepages, &processed); + + if (font_codepages & string_codepages) + { + section.font = (GpFont *)base_font; + } + else + { + IMLangFontLink_MapFont(iMLFL, hdc, string_codepages, hfont, &map_hfont); + old_font = SelectObject(hdc, map_hfont); + GdipCreateFontFromDC(hdc, &gpfont); + SelectObject(hdc, old_font); + IMLangFontLink_ReleaseFont(iMLFL, map_hfont); + section.font = gpfont; + } + + section.len = processed; + sections_count = ++font_link_info->count; + font_link_info->sections = realloc(font_link_info->sections, sizeof(section) * sections_count); + font_link_info->sections[sections_count - 1] = section; + progress += processed; + } + + DeleteObject(hfont); + IMLangFontLink_Release(iMLFL); +} + +struct gdip_font_link_section *get_font_link_section(struct gdip_font_link_info *font_link_info, DWORD index) +{ + struct gdip_font_link_section *section = &font_link_info->sections[0]; + for (int i = 0; i < font_link_info->count; ++i) + { + section = &font_link_info->sections[i]; + if (index <= section->index && (index - section->index) < section->len) + break; + } + + return section; +} + +void release_font_link_info(struct gdip_font_link_info *font_link_info) +{ + for (int i = 0; i < font_link_info->count; ++i) + { + if (font_link_info->sections[i].font != font_link_info->base_font) + GdipDeleteFont(font_link_info->sections[i].font); + } + + free(font_link_info->sections); + font_link_info->count = 0; + font_link_info->sections = NULL; +} + GpStatus gdip_format_string(HDC hdc, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, int ignore_empty_clip, @@ -5177,6 +5260,7 @@ GpStatus gdip_format_string(HDC hdc, INT *hotkeyprefix_offsets=NULL; INT hotkeyprefix_count=0; INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0; + struct gdip_font_link_info font_link_info = { 0 }; BOOL seen_prefix = FALSE, unixstyle_newline = TRUE;
if(length == -1) length = lstrlenW(string); @@ -5242,6 +5326,8 @@ GpStatus gdip_format_string(HDC hdc,
halign = format->align;
+ generate_font_link_info(hdc, stringdup, length, font, &font_link_info); + while(sum < length){ GetTextExtentExPointW(hdc, stringdup + sum, length - sum, nwidth, &fit, NULL, &size); @@ -5327,7 +5413,7 @@ GpStatus gdip_format_string(HDC hdc, break;
stat = callback(hdc, stringdup, sum, lineend, - font, rect, format, lineno, &bounds, + &font_link_info, rect, format, lineno, &bounds, &hotkeyprefix_offsets[hotkeyprefix_pos], hotkeyprefix_end_pos-hotkeyprefix_pos, user_data);
@@ -5358,6 +5444,7 @@ GpStatus gdip_format_string(HDC hdc, break; }
+ release_font_link_info(&font_link_info); free(stringdup); free(hotkeyprefix_offsets);
@@ -5393,7 +5480,8 @@ struct measure_ranges_args { };
static GpStatus measure_ranges_callback(HDC hdc, - GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, + GDIPCONST WCHAR *string, INT index, INT length, + struct gdip_font_link_info *font_link_info, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, INT lineno, const RectF *bounds, INT *underlined_indexes, INT underlined_index_count, void *user_data) @@ -5518,7 +5606,8 @@ struct measure_string_args { };
static GpStatus measure_string_callback(HDC hdc, - GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, + GDIPCONST WCHAR *string, INT index, INT length, + struct gdip_font_link_info *font_link_info, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, INT lineno, const RectF *bounds, INT *underlined_indexes, INT underlined_index_count, void *user_data) @@ -5637,21 +5726,35 @@ struct draw_string_args { };
static GpStatus draw_string_callback(HDC hdc, - GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, + GDIPCONST WCHAR *string, INT index, INT length, + struct gdip_font_link_info *font_link_info, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, INT lineno, const RectF *bounds, INT *underlined_indexes, INT underlined_index_count, void *user_data) { struct draw_string_args *args = user_data; PointF position; - GpStatus stat; + GpStringFormat *generic_format; + RectF bound_box; + DWORD to_draw_length; + struct gdip_font_link_section *section; + GpStatus stat = Ok;
position.X = args->x + bounds->X / args->rel_width; position.Y = args->y + bounds->Y / args->rel_height + args->ascent;
- stat = draw_driver_string(args->graphics, &string[index], length, font, format, - args->brush, &position, - DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + GdipStringFormatGetGenericTypographic(&generic_format); + for (int i = 0; i < length; i += to_draw_length) + { + section = get_font_link_section(font_link_info, index + i); + to_draw_length = min(length, section->len - ((index + i) - section->index)); + TRACE("i %d, todraw %ld, used %s\n", index + i, to_draw_length, section->font == font_link_info->base_font ? "base font" : "map"); + GdipMeasureString(args->graphics, &string[index + i], to_draw_length, section->font, rect, generic_format, &bound_box, NULL, NULL); + stat = draw_driver_string(args->graphics, &string[index + i], to_draw_length, + section->font, format, args->brush, &position, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + position.X += bound_box.Width; + }
if (stat == Ok && underlined_index_count) { diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 24c2888cfe8..8fab007da06 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -950,7 +950,7 @@ struct format_string_args };
static GpStatus format_string_callback(HDC dc, - GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, + GDIPCONST WCHAR *string, INT index, INT length, struct gdip_font_link_info *font_link_info, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, INT lineno, const RectF *bounds, INT *underlined_indexes, INT underlined_index_count, void *priv)
I created an interactive test, but I had to add as a workaround a call to RedrawWindow because of a bug in wine. In Windows it draws the string right away when I call GdipDrawString, but in Wine it does it after a second call to GdipDrawString or GdipDrawDriverString, so I had to call RedrawWindow before the call to Sleep so the results of GdipDrawString are shown. I tried to find the cause of the bug and fix it, but I got stuck.
Esme Povirk (@madewokherd) commented about dlls/mlang/tests/mlang.c:
"GetGlobalFontLinkObject() returned %p\n", unknown);
- if (unknown == (void *)0xdeadbeef || !unknown) return; }
- ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink2, (void**)&IMLFL2);
- ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret);
- ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMultiLanguage, (void**)&IML);
- ok(ret == E_NOINTERFACE, "expected E_NOINTERFACE got %#lx\n", ret);
- ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangFontLink, (void**)&IMLFL);
- ok(ret == S_OK, "expected E_NOINTERFACE got %#lx\n", ret);
- IMLangFontLink_Release(IMLFL);
- ret = IUnknown_QueryInterface((IUnknown*)unknown, &IID_IMLangCodePages, (void**)&IMLCP);
- ok(ret == S_OK, "expected E_NOINTERFACE got %#lx\n", ret);
The ok() messages here are wrong.
Esme Povirk (@madewokherd) commented about dlls/mlang/mlang.c:
if (ret != S_OK) return E_FAIL; if (!cps) cps = cp;
else if ((cps & cp) != 0) cps &= cp;
else if ((cps & cp) != 0 &&
((priority_cp & cps) || !(priority_cp & cp))) cps &= cp;
I don't know mlang, but the original loop confuses me a lot. It feels to me like there shouldn't be a need to examine more than one character at a time. Since next_cp is only used at the end, couldn't the check be done in the next iteration?
I don't understand what this change does, but that may be because I don't understand the original loop.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
}
+/* Populates gdip_font_link_info struct based on the base_font and input string */ +void generate_font_link_info(HDC hdc, WCHAR *string, DWORD length, GDIPCONST GpFont *base_font,
This function isn't used outside of graphics.c and should be static.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
section.font = (GpFont *)base_font;
}
else
{
IMLangFontLink_MapFont(iMLFL, hdc, string_codepages, hfont, &map_hfont);
old_font = SelectObject(hdc, map_hfont);
GdipCreateFontFromDC(hdc, &gpfont);
SelectObject(hdc, old_font);
IMLangFontLink_ReleaseFont(iMLFL, map_hfont);
section.font = gpfont;
}
section.len = processed;
sections_count = ++font_link_info->count;
font_link_info->sections = realloc(font_link_info->sections, sizeof(section) * sections_count);
font_link_info->sections[sections_count - 1] = section;
Probably would make sense to allocate exponentially instead of linearly, in case there are a lot of these.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
- DeleteObject(hfont);
- IMLangFontLink_Release(iMLFL);
+}
+struct gdip_font_link_section *get_font_link_section(struct gdip_font_link_info *font_link_info, DWORD index) +{
- struct gdip_font_link_section *section = &font_link_info->sections[0];
- for (int i = 0; i < font_link_info->count; ++i)
- {
section = &font_link_info->sections[i];
if (index <= section->index && (index - section->index) < section->len)
break;
- }
- return section;
+}
This approach is unnecessarily quadratic, since the caller will only ever retrieve these in order.
On Mon Dec 11 16:52:25 2023 +0000, Esme Povirk wrote:
This approach is unnecessarily quadratic, since the caller will only ever retrieve these in order.
The function also looks broken to me in the general case. If you have a section with index 0 and length 3, and you search for index 1, it will reject the section because it checks that `1 <= 0`.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
lineend = fit; GetTextExtentExPointW(hdc, stringdup + sum, lineend, nwidth, &j, NULL, &size);
Does this need to account for font linking?
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
};
static GpStatus measure_ranges_callback(HDC hdc,
- GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
- GDIPCONST WCHAR *string, INT index, INT length,
- struct gdip_font_link_info *font_link_info, GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
Apparently this function doesn't use GpFont, but it probably will eventually have to be aware of the section fonts. Unless it really doesn't need that for some reason, I think a FIXME should be added for the case where there isn't just 1 section containing the base font.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphics.c:
GpStringFormat *generic_format;
RectF bound_box;
DWORD to_draw_length;
struct gdip_font_link_section *section;
GpStatus stat = Ok;
position.X = args->x + bounds->X / args->rel_width; position.Y = args->y + bounds->Y / args->rel_height + args->ascent;
- stat = draw_driver_string(args->graphics, &string[index], length, font, format,
args->brush, &position,
- GdipStringFormatGetGenericTypographic(&generic_format);
- for (int i = 0; i < length; i += to_draw_length)
- {
section = get_font_link_section(font_link_info, index + i);
to_draw_length = min(length, section->len - ((index + i) - section->index));
I think this should be `min(length - i, section->len - ((index + i) - section->index))`
Esme Povirk (@madewokherd) commented about dlls/gdiplus/gdiplus_private.h:
return NULL;
}
+/* Represents a string section and the font it should use. */ +struct gdip_font_link_section {
- DWORD index; /* The starting index of the string where the font applies. */
- DWORD len; /* The length of the section. */
It might be more convenient to store start and end index rather than length. Just something to consider.
On Mon Dec 11 17:04:37 2023 +0000, Esme Povirk wrote:
Does this need to account for font linking?
I think we should use GdipMeasureString, check if it should account for font linking, and implement it there.