-- v3: 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 704576005d2..12116d770ad 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -2298,6 +2298,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); @@ -2308,7 +2313,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) @@ -2781,6 +2805,8 @@ START_TEST(mlang) if (!init_function_ptrs()) return;
+ test_GetGlobalFontLinkObject(); + CoInitialize(NULL); test_Rfc1766ToLcid(); test_LcidToRfc1766(); @@ -2788,8 +2814,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 9846e3ad0e4..19df817d4fe 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 12116d770ad..f07a0a3a2f7 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -2309,18 +2309,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 f07a0a3a2f7..97097d9da34 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -1327,6 +1327,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 19df817d4fe..91bc1e005ed 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 97097d9da34..91f77dbc562 100644 --- a/dlls/mlang/tests/mlang.c +++ b/dlls/mlang/tests/mlang.c @@ -1333,7 +1333,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 1bc058b3413..29b5220d5c8 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -607,8 +607,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 cc8411d54f7..3e6252f9f47 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" @@ -5153,6 +5154,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 = heap_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); + } + + heap_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, @@ -5169,6 +5252,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); @@ -5234,6 +5318,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); @@ -5319,7 +5405,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);
@@ -5350,6 +5436,7 @@ GpStatus gdip_format_string(HDC hdc, break; }
+ release_font_link_info(&font_link_info); heap_free(stringdup); heap_free(hotkeyprefix_offsets);
@@ -5387,7 +5474,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) @@ -5512,7 +5600,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) @@ -5631,21 +5720,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 63f120a6aba..cc71a4b54be 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)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=141108
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/gdiplus/graphics.c:5350 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/gdiplus/graphics.c:5350 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: dlls/gdiplus/graphics.c:5350 Task: Patch failed to apply