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)