-- v2: gdiplus: Implement font linking in GdipDrawString. gdiplus: Initialize COM for gdiplus.
From: Santino Mazza smazza@codeweavers.com
--- dlls/gdiplus/gdiplus.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/gdiplus/gdiplus.c b/dlls/gdiplus/gdiplus.c index a3c85986ffc..c26540e4568 100644 --- a/dlls/gdiplus/gdiplus.c +++ b/dlls/gdiplus/gdiplus.c @@ -100,6 +100,7 @@ Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput output->NotificationUnhook = NotificationUnhook; }
+ CoInitialize(NULL); *token = 0xdeadbeef;
/* FIXME: DebugEventCallback ignored */ @@ -133,6 +134,7 @@ ULONG WINAPI GdiplusShutdown_wrapper(ULONG_PTR token) /* "bricksntiles" expects a return value of 0, which native * coincidentally gives. */ + CoUninitialize(); return 0; }
From: Santino Mazza smazza@codeweavers.com
--- dlls/gdiplus/graphics.c | 66 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 65b33cdc960..5315da89d49 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -30,6 +30,7 @@ #include "ocidl.h" #include "olectl.h" #include "ole2.h" +#include "mlang.h"
#include "winreg.h" #include "shlwapi.h" @@ -5641,13 +5642,71 @@ static GpStatus draw_string_callback(HDC hdc, struct draw_string_args *args = user_data; PointF position; GpStatus stat; + IMLangFontLink2 *iMLFL2; + DWORD codepages, font_codepages; + INT current_index, current_length; + LONG processed; + HFONT new_font, old_font, hfont; + GpFont *new_gpfont; + LOGFONTW lfw; + HRESULT hr;
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); + if (FAILED(hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_ALL, &IID_IMLangFontLink2, (void**)&iMLFL2))) + { + ERR("Failed to create font linking interface %lx\n", hr); + return hr; + }; + + get_font_hfont(args->graphics, font, format, &hfont, &lfw, NULL); + IMLangFontLink2_GetFontCodePages(iMLFL2, hdc, hfont, &font_codepages); + + current_index = index; + current_length = length; + do + { + IMLangFontLink2_GetStrCodePages(iMLFL2, &string[current_index], current_length, 0, &codepages, &processed); + if (font_codepages & codepages) /* if the font supports the required codepages don't do anything. */ + stat = draw_driver_string(args->graphics, &string[current_index], processed, font, format, + args->brush, &position, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + else + { + old_font = SelectObject(hdc, hfont); + hr = IMLangFontLink2_MapFont(iMLFL2, hdc, codepages, 0, &new_font); + if (FAILED(hr)) + { + SelectObject(hdc, old_font); + break; + } + SelectObject(hdc, new_font); + stat = GdipCreateFontFromDC(hdc, &new_gpfont); + if (stat != Ok) + { + SelectObject(hdc, old_font); + IMLangFontLink2_ReleaseFont(iMLFL2, new_font); + break; + } + SelectObject(hdc, old_font); + stat = draw_driver_string(args->graphics, &string[current_index], processed, new_gpfont, format, + args->brush, &position, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + IMLangFontLink2_ReleaseFont(iMLFL2, new_font); + } + + current_index += processed; + current_length -= processed; + } + while (current_length > 0); + + if (stat != Ok || FAILED(hr)) /* If font linking failed, draw the rest without it. */ + { + stat = draw_driver_string(args->graphics, &string[current_index], current_length, font, format, + args->brush, &position, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + }
if (stat == Ok && underlined_index_count) { @@ -5676,6 +5735,7 @@ static GpStatus draw_string_callback(HDC hdc, } }
+ IMLangFontLink2_Release(iMLFL2); return stat; }
Nikolay Sivov (@nsivov) commented about dlls/gdiplus/gdiplus.c:
output->NotificationUnhook = NotificationUnhook; }
- CoInitialize(NULL); *token = 0xdeadbeef;
That would be very unusual for a library to do.
On Thu Oct 12 20:52:37 2023 +0000, Nikolay Sivov wrote:
That would be very unusual for a library to do.
Where should I initialize it? GdipDrawString works without having to call CoInitialize in Windows.
On Thu Oct 12 21:02:44 2023 +0000, Santino Mazza wrote:
Where should I initialize it? GdipDrawString works without having to call CoInitialize in Windows.
That's a thing, you shouldn't do that in a library, it's main application decision to how and when initialize it. Again, unless gdiplus for some reason does initialize COM on Windows.
On Thu Oct 12 21:04:40 2023 +0000, Nikolay Sivov wrote:
That's a thing, you shouldn't do that in a library, it's main application decision to how and when initialize it. Again, unless gdiplus for some reason does initialize COM on Windows.
Mmm, so I will have to find a way to do font linking without mlang.
On Thu Oct 12 21:11:03 2023 +0000, Santino Mazza wrote:
Mmm, so I will have to find a way to do font linking without mlang.
There is also the undocumented GetGlobalFontLinkObject(), which may work without COM. I'm not sure whether we want to use such an undocumented API, though.
On Thu Oct 12 21:28:08 2023 +0000, Zebediah Figura wrote:
There is also the undocumented GetGlobalFontLinkObject(), which may work without COM. I'm not sure whether we want to use such an undocumented API, though.
If it works for this purpose then I think we should. We already use WICCreateImagingFactory_Proxy for a similar reason.
This needs to be handled in gdip_format_string first, and probably the info we get out of mlang should be passed on to the various callback functions.
On Sat Oct 14 15:40:39 2023 +0000, Esme Povirk wrote:
If it works for this purpose then I think we should. We already use WICCreateImagingFactory_Proxy for a similar reason.
I think I'm going to check for GetGlobalFontLinkObject, I will have to write some tests.
On Thu Oct 19 15:56:32 2023 +0000, Esme Povirk wrote:
This needs to be handled in gdip_format_string first, and probably the info we get out of mlang should be passed on to the various callback functions.
Mmm I'm stuck on this, how should I do it? The first I thing I thought was calling the callback for each string section with the specific font, but I realized that some functions like GdipMeasureString count the amount of times the callback is called for counting each line. I also thought in passing an array containing each section of the string, but that would require more refactoring and I'm not sure if that is desired.
While prototyping some solutions I found a bug in GetStrCodePages, it doesn't return when a character with different codepage appears in the string, it only continues assuming that character has the same codepage as the rest of the string.
For example: `Abc\u307b`, in windows you would require two calls for processing the entire string, the first call would return the codepage for the first three characters and in the second one the last character. In Wine it processes the 4 characters and returns as if it had processed 4 characters, when it should return 3.
On Thu Oct 19 15:56:32 2023 +0000, Santino Mazza wrote:
Mmm I'm stuck on this, how should I do it? The first I thing I thought was calling the callback for each string section with the specific font, but I realized that some functions like GdipMeasureString count the amount of times the callback is called for counting each line. I also thought in passing an array containing each section of the string, but that would require more refactoring and I'm not sure if that is desired.
If an array of runs is the cleanest way to do it in the end then I'd like to see the code refactored. If multiple callbacks is preferable then the assumption in GdipMeasureString should be changed (maybe pass in a variable indicating whether it's the first run in a line?).
Revising the callback signature to pass in a struct instead of so many arguments might also be a good idea.
On Fri Nov 3 15:45:46 2023 +0000, Esme Povirk wrote:
If an array of runs is the cleanest way to do it in the end then I'd like to see the code refactored. If multiple callbacks is preferable then the assumption in GdipMeasureString should be changed (maybe pass in a variable indicating whether it's the first run in a line?). Revising the callback signature to pass in a struct instead of so many arguments might also be a good idea.
Thanks! I think I'm going with the array.