From 7f82b13fbfc68633c88d0376bd0087318c4c05b7 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Thu, 12 Jun 2025 09:37:21 +0200 Subject: [PATCH 01/12] Fix typo --- src/win32/cairo-dwrite-font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index 9f6d362b3..b60518297 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -1526,7 +1526,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface (cairo_dwrite_scaled_font_t *scaled if (subpixel_order_is_vertical) { // DirectWrite does not support vertical pixel geometries. - // As a workaround, apply a simmetry which swaps x and y + // As a workaround, apply a symmetry which swaps x and y // coordinates, then re-swap while copying the back into // the image surface From b1bc5a73f6da824c05bf9c81f05712989c5731f2 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Thu, 12 Jun 2025 09:38:07 +0200 Subject: [PATCH 02/12] DWrite: don't set component-alpha for A8 mask It was just a copy-paste leftover. Component-alpha makes sense only for color images. --- src/win32/cairo-dwrite-font.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index b60518297..57fe6f5b0 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -1375,10 +1375,6 @@ init_glyph_surface_fallback_a8 (cairo_dwrite_scaled_font_t *scaled_font, if (cairo_surface_status (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - // Tell pixman that it should use component alpha blending when the surface is - // used as a source - pixman_image_set_component_alpha (((cairo_image_surface_t*)surface)->pixman_image, TRUE); - int stride = cairo_image_surface_get_stride (surface); WICRect rect = { 0, 0, width, height }; bitmap->CopyPixels(&rect, From 306396ff53c61cf52494026b32db4e2d62a03887 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 11:27:28 +0200 Subject: [PATCH 03/12] Add definitions for ID2D1DeviceContext7 in d2d1-extra.h We're going to make use of ID2D1DeviceContext7::DrawPaintGlyphRun() for COLRv1 fonts. --- src/win32/d2d1-extra.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/win32/d2d1-extra.h b/src/win32/d2d1-extra.h index 16099d834..de6f68829 100644 --- a/src/win32/d2d1-extra.h +++ b/src/win32/d2d1-extra.h @@ -108,4 +108,46 @@ ID2D1DeviceContext4 : public ID2D1DeviceContext3 }; __CRT_UUID_DECL(ID2D1DeviceContext4, 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb) +DEFINE_GUID(IID_ID2D1DeviceContext5, 0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7); +MIDL_INTERFACE("7836d248-68cc-4df6-b9e8-de991bf62eb7") +ID2D1DeviceContext5 : public ID2D1DeviceContext4 +{ + virtual void STDMETHODCALLTYPE CreateSvgDocument() = 0; + virtual void STDMETHODCALLTYPE DrawSvgDocument() = 0; + virtual void STDMETHODCALLTYPE CreateColorContextFromDxgiColorSpace() = 0; + virtual void STDMETHODCALLTYPE CreateColorContextFromSimpleColorProfile() = 0; +}; +__CRT_UUID_DECL(ID2D1DeviceContext5, 0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7) + +DEFINE_GUID(IID_ID2D1DeviceContext6, 0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06); +MIDL_INTERFACE("985f7e37-4ed0-4a19-98a3-15b0edfde306") +ID2D1DeviceContext6 : public ID2D1DeviceContext5 +{ + virtual void STDMETHODCALLTYPE BlendImage() = 0; +}; +__CRT_UUID_DECL(ID2D1DeviceContext6, 0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06) + +DEFINE_GUID(IID_ID2D1DeviceContext7, 0xec891cf7, 0x9b69, 0x4851, 0x9d, 0xef, 0x4e, 0x09, 0x15, 0x77, 0x1e, 0x62); +MIDL_INTERFACE("ec891cf7-9b69-4851-9def-4e0915771e62") +ID2D1DeviceContext7 : public ID2D1DeviceContext6 +{ + STDMETHOD_(DWRITE_PAINT_FEATURE_LEVEL, GetPaintFeatureLevel)() PURE; + + STDMETHOD_(void, DrawPaintGlyphRun)(D2D1_POINT_2F baselineOrigin, + CONST DWRITE_GLYPH_RUN *glyphRun, + ID2D1Brush *defaultFillBrush = nullptr, + UINT32 colorPaletteIndex = 0, + DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL) PURE; + + STDMETHOD_(void, DrawGlyphRunWithColorSupport)(D2D1_POINT_2F baselineOrigin, + CONST DWRITE_GLYPH_RUN *glyphRun, + CONST DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription, + ID2D1Brush *foregroundBrush, + ID2D1SvgGlyphStyle *svgGlyphStyle, + UINT32 colorPaletteIndex = 0, + DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION bitmapSnapOption = D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT) PURE; +}; +__CRT_UUID_DECL(ID2D1DeviceContext7, 0xec891cf7, 0x9b69, 0x4851, 0x9d, 0xef, 0x4e, 0x09, 0x15, 0x77, 0x1e, 0x62) + #endif From bd930bc98de7e5915275b2b8f3782ea349a9d60b Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 11:30:12 +0200 Subject: [PATCH 04/12] Meson: Do not check for d2d1.h, dwrite.h, wincodec.h If the import libraries are found, we can assume that headers are present as well. All three headers were introduced many years ago in the Windows SDK and mingw-w64 headers. --- meson.build | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/meson.build b/meson.build index ee2a4e70b..baf59ec45 100644 --- a/meson.build +++ b/meson.build @@ -518,13 +518,10 @@ if host_machine.system() == 'windows' cpp_compiler = meson.get_compiler('cpp') d2d_dep = cpp_compiler.find_library('d2d1', required: get_option('dwrite')) dwrite_dep = cpp_compiler.find_library('dwrite', required: get_option('dwrite')) - d2d_header = cpp_compiler.has_header('d2d1.h') d2d_3_header = cpp_compiler.has_header('d2d1_3.h') - dwrite_header = cpp_compiler.has_header('dwrite.h') wincodec_dep = cpp_compiler.find_library('windowscodecs', required: get_option('dwrite')) - wincodec_header = cpp_compiler.has_header('wincodec.h') - if d2d_dep.found() and dwrite_dep.found() and d2d_header and dwrite_header and wincodec_dep.found() and wincodec_header + if d2d_dep.found() and dwrite_dep.found() feature_conf.set('CAIRO_HAS_DWRITE_FONT', 1) built_features += [{ 'name': 'cairo-dwrite-font', From 6c75de11abc01fb75b676412e7dbf52d2c9787ae Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 11:44:13 +0200 Subject: [PATCH 05/12] Meson: Simplify check for D2D, DWrite, WIC a bit --- meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index baf59ec45..126156bd0 100644 --- a/meson.build +++ b/meson.build @@ -516,12 +516,12 @@ if host_machine.system() == 'windows' ] cpp_compiler = meson.get_compiler('cpp') - d2d_dep = cpp_compiler.find_library('d2d1', required: get_option('dwrite')) - dwrite_dep = cpp_compiler.find_library('dwrite', required: get_option('dwrite')) - d2d_3_header = cpp_compiler.has_header('d2d1_3.h') - wincodec_dep = cpp_compiler.find_library('windowscodecs', required: get_option('dwrite')) - if d2d_dep.found() and dwrite_dep.found() + if get_option('dwrite').allowed() + d2d_dep = cpp_compiler.find_library('d2d1') + dwrite_dep = cpp_compiler.find_library('dwrite') + wincodec_dep = cpp_compiler.find_library('windowscodecs') + feature_conf.set('CAIRO_HAS_DWRITE_FONT', 1) built_features += [{ 'name': 'cairo-dwrite-font', From 6ec91df76ee6bfe0a9b91c89ff19cbc140c782f4 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 12:19:34 +0200 Subject: [PATCH 06/12] Check which ID2D1DeviceContext subclasses are defined in d2d1_3.h ...and make d2d1-extra.h provide the missing definitions --- meson.build | 28 ++++++++++-- src/win32/cairo-dwrite-private.hpp | 12 +---- src/win32/d2d1-extra.h | 73 +++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/meson.build b/meson.build index 126156bd0..eac9e9302 100644 --- a/meson.build +++ b/meson.build @@ -530,11 +530,33 @@ if host_machine.system() == 'windows' }] deps += [dwrite_dep, d2d_dep, wincodec_dep] - if cpp_compiler.has_header('d2d1_3.h') - conf.set('HAVE_D2D1_3_H', 1) + sdk_version_args = [ + '-DWINVER=_WIN32_WINNT_WIN10', + '-D_WIN32_WINNT=_WIN32_WINNT_WIN10', + # DWrite / D2D headers define types conditionally on the value of NTDDI_VERSION. + # Use an high version to avoid including definitions in-tree. 0x0A000010 == + # NTDDI_WIN11_GE; using the number to stay compatible with not bleeding-edge SDK + # headers. + '-DNTDDI_VERSION=0x0A000010', + ] + + if cpp_compiler.has_header('d2d1_2.h') + conf.set('HAVE_D2D1_2_H', 1) endif - add_project_arguments('-DWINVER=_WIN32_WINNT_WIN10', '-D_WIN32_WINNT=_WIN32_WINNT_WIN10', '-DNTDDI_VERSION=NTDDI_WIN10_RS3', language: ['c', 'cpp']) + if cpp_compiler.has_header('d2d1_3.h') + conf.set('HAVE_D2D1_3_H', 1) + + foreach i : range(2, 8) + if cpp_compiler.has_type('ID2D1DeviceContext' + i.to_string(), + prefix: ['#include ', '#include '], + args: sdk_version_args) + conf.set('HAVE_ID2D1DEVICECONTEXT' + i.to_string(), 1) + endif + endforeach + endif + + add_project_arguments(sdk_version_args, language: ['c', 'cpp']) else add_project_arguments('-DWINVER=_WIN32_WINNT_WIN2K', '-D_WIN32_WINNT=_WIN32_WINNT_WIN2K', language: ['c', 'cpp']) endif diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index 7834485f3..45c1e9741 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -37,7 +37,7 @@ #include "cairoint.h" #include "cairo-win32-refptr.hpp" #include -#include +#include "d2d1-extra.h" #ifdef __MINGW32__ #include "dw-extra.h" @@ -45,16 +45,6 @@ typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; #endif -/* If d2d1_3.h header required for color fonts is not available, - * include our own version containing just the functions we need. - */ - -#if HAVE_D2D1_3_H -#include -#else -#include "d2d1-extra.h" -#endif - // DirectWrite is not available on all platforms. typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( DWRITE_FACTORY_TYPE factoryType, diff --git a/src/win32/d2d1-extra.h b/src/win32/d2d1-extra.h index de6f68829..101bfb9f1 100644 --- a/src/win32/d2d1-extra.h +++ b/src/win32/d2d1-extra.h @@ -17,19 +17,17 @@ #ifndef D2D1_EXTRA_H #define D2D1_EXTRA_H +#include "config.h" + +#if defined (HAVE_D2D1_3_H) +#include +#elif defined (HAVE_D2D1_2_H) +#include +#else #include +#endif -interface ID2D1DeviceContext1; -interface ID2D1DeviceContext2; -interface ID2D1DeviceContext3; -interface ID2D1DeviceContext4; -interface ID2D1SvgGlyphStyle; - -enum D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION { - D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT, - D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DISABLE, - D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_FORCE_DWORD -}; +#ifndef HAVE_D2D1_2_H DEFINE_GUID(IID_ID2D1DeviceContext1, 0xd37f57e4, 0x6908, 0x459f, 0xa1, 0x99, 0xe7, 0x2f, 0x24, 0xf7, 0x99, 0x87); MIDL_INTERFACE("d37f57e4-6908-459f-a199-e72f24f79987") @@ -39,7 +37,13 @@ ID2D1DeviceContext1 : public ID2D1DeviceContext virtual void STDMETHODCALLTYPE CreateStrokedGeometryRealization() = 0; virtual void STDMETHODCALLTYPE DrawGeometryRealization() = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext1, 0xd37f57e4, 0x6908, 0x459f, 0xa1, 0x99, 0xe7, 0x2f, 0x24, 0xf7, 0x99, 0x87) +#endif + +#endif // !HAVE_D2D1_2_H + +#ifndef HAVE_ID2D1DEVICECONTEXT2 DEFINE_GUID(IID_ID2D1DeviceContext2, 0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7); MIDL_INTERFACE("394ea6a3-0c34-4321-950b-6ca20f0be6c7") @@ -57,8 +61,13 @@ ID2D1DeviceContext2 : public ID2D1DeviceContext1 virtual void STDMETHODCALLTYPE DrawGdiMetafile() = 0; virtual void STDMETHODCALLTYPE CreateTransformedImageSource() = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext2, 0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7) +#endif +#endif + +#ifndef HAVE_ID2D1DEVICECONTEXT3 DEFINE_GUID(IID_ID2D1DeviceContext3, 0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00); MIDL_INTERFACE("235a7496-8351-414c-bcd4-6672ab2d8e00") @@ -67,21 +76,21 @@ ID2D1DeviceContext3 : public ID2D1DeviceContext2 virtual void STDMETHODCALLTYPE CreateSpriteBatch() = 0; virtual void STDMETHODCALLTYPE DrawSpriteBatch() = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext3, 0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00) +#endif +#endif -DEFINE_GUID(IID_ID2D1SvgGlyphStyle, 0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38); -MIDL_INTERFACE("af671749-d241-4db8-8e41-dcc2e5c1a438") -ID2D1SvgGlyphStyle : public ID2D1Resource -{ - virtual void STDMETHODCALLTYPE SetFill() = 0; - virtual void STDMETHODCALLTYPE GetFill() = 0; - virtual void STDMETHODCALLTYPE SetStroke() = 0; - virtual void STDMETHODCALLTYPE GetStrokeDashesCount() = 0; - virtual void STDMETHODCALLTYPE GetStroke() = 0; +#ifndef HAVE_ID2D1DEVICECONTEXT4 + +enum D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION { + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DISABLE, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_FORCE_DWORD = 0xffffffff }; -__CRT_UUID_DECL(ID2D1SvgGlyphStyle, 0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38) +interface ID2D1SvgGlyphStyle; DEFINE_GUID(IID_ID2D1DeviceContext4, 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb); MIDL_INTERFACE("8c427831-3d90-4476-b647-c4fae349e4db") @@ -106,7 +115,13 @@ ID2D1DeviceContext4 : public ID2D1DeviceContext3 DWRITE_MEASURING_MODE measuringMode) = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext4, 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb) +#endif + +#endif + +#ifndef HAVE_ID2D1DEVICECONTEXT5 DEFINE_GUID(IID_ID2D1DeviceContext5, 0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7); MIDL_INTERFACE("7836d248-68cc-4df6-b9e8-de991bf62eb7") @@ -117,7 +132,13 @@ ID2D1DeviceContext5 : public ID2D1DeviceContext4 virtual void STDMETHODCALLTYPE CreateColorContextFromDxgiColorSpace() = 0; virtual void STDMETHODCALLTYPE CreateColorContextFromSimpleColorProfile() = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext5, 0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7) +#endif + +#endif + +#ifndef HAVE_ID2D1DEVICECONTEXT6 DEFINE_GUID(IID_ID2D1DeviceContext6, 0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06); MIDL_INTERFACE("985f7e37-4ed0-4a19-98a3-15b0edfde306") @@ -125,7 +146,13 @@ ID2D1DeviceContext6 : public ID2D1DeviceContext5 { virtual void STDMETHODCALLTYPE BlendImage() = 0; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext6, 0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06) +#endif + +#endif + +#ifndef HAVE_ID2D1DEVICECONTEXT7 DEFINE_GUID(IID_ID2D1DeviceContext7, 0xec891cf7, 0x9b69, 0x4851, 0x9d, 0xef, 0x4e, 0x09, 0x15, 0x77, 0x1e, 0x62); MIDL_INTERFACE("ec891cf7-9b69-4851-9def-4e0915771e62") @@ -148,6 +175,10 @@ ID2D1DeviceContext7 : public ID2D1DeviceContext6 DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL, D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION bitmapSnapOption = D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT) PURE; }; +#ifdef __CRT_UUID_DECL __CRT_UUID_DECL(ID2D1DeviceContext7, 0xec891cf7, 0x9b69, 0x4851, 0x9d, 0xef, 0x4e, 0x09, 0x15, 0x77, 0x1e, 0x62) +#endif + +#endif #endif From 27411659d8ef69ba5b31ad3f5e14c98c8308369f Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 15:06:57 +0200 Subject: [PATCH 07/12] Rename dwrite / d2d1 polyfill headers to .hpp extension They are only usable from C++ now --- src/win32/cairo-dwrite-private.hpp | 4 ++-- src/win32/{d2d1-extra.h => d2d1-extra.hpp} | 0 src/win32/{dw-extra.h => dwrite-extra.hpp} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/win32/{d2d1-extra.h => d2d1-extra.hpp} (100%) rename src/win32/{dw-extra.h => dwrite-extra.hpp} (100%) diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index 45c1e9741..ea09c7ad2 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -37,10 +37,10 @@ #include "cairoint.h" #include "cairo-win32-refptr.hpp" #include -#include "d2d1-extra.h" +#include "d2d1-extra.hpp" #ifdef __MINGW32__ -#include "dw-extra.h" +#include "dwrite-extra.hpp" #else typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; #endif diff --git a/src/win32/d2d1-extra.h b/src/win32/d2d1-extra.hpp similarity index 100% rename from src/win32/d2d1-extra.h rename to src/win32/d2d1-extra.hpp diff --git a/src/win32/dw-extra.h b/src/win32/dwrite-extra.hpp similarity index 100% rename from src/win32/dw-extra.h rename to src/win32/dwrite-extra.hpp From 02763155e8eed3610487c330915060834a4b4b9e Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 15:12:34 +0200 Subject: [PATCH 08/12] dwrite-extra.hpp: Rework a bit --- src/win32/dwrite-extra.hpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/win32/dwrite-extra.hpp b/src/win32/dwrite-extra.hpp index a9daced21..56e445f90 100644 --- a/src/win32/dwrite-extra.hpp +++ b/src/win32/dwrite-extra.hpp @@ -3,24 +3,21 @@ /* MinGW workarounds * * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS. - * The DWRITE_COLOR_GLYPH_RUN struct isn't valid. - * */ #ifndef DWRITE_EXTRA_H #define DWRITE_EXTRA_H #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10 - -typedef struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +// The DWRITE_COLOR_GLYPH_RUN struct isn't valid. +// struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN { DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat; DWRITE_MEASURING_MODE measuringMode; }; - #else -typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +using DWRITE_COLOR_GLYPH_RUN1_WORKAROUND = DWRITE_COLOR_GLYPH_RUN1; #endif #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 11 From 53c3702686e24ee7aaf26ce84a47383abfcea388 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 15:13:44 +0200 Subject: [PATCH 09/12] dwrite-extra.hpp: Fix check for mingw-w64 workaround --- src/win32/dwrite-extra.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/win32/dwrite-extra.hpp b/src/win32/dwrite-extra.hpp index 56e445f90..e8caf8f0f 100644 --- a/src/win32/dwrite-extra.hpp +++ b/src/win32/dwrite-extra.hpp @@ -1,10 +1,5 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* MinGW workarounds - * - * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS. - */ - #ifndef DWRITE_EXTRA_H #define DWRITE_EXTRA_H @@ -20,7 +15,7 @@ struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN using DWRITE_COLOR_GLYPH_RUN1_WORKAROUND = DWRITE_COLOR_GLYPH_RUN1; #endif -#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 11 +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 11 DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS); #endif From 2a306f8e5f3c8121c4490d3997b913620fb636fa Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 15:28:25 +0200 Subject: [PATCH 10/12] Always include dwrite-extra.hpp --- src/win32/cairo-dwrite-private.hpp | 8 +------- src/win32/dwrite-extra.hpp | 2 ++ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index ea09c7ad2..62fe8d6ad 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -36,14 +36,8 @@ #include "cairoint.h" #include "cairo-win32-refptr.hpp" -#include -#include "d2d1-extra.hpp" - -#ifdef __MINGW32__ #include "dwrite-extra.hpp" -#else -typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; -#endif +#include "d2d1-extra.hpp" // DirectWrite is not available on all platforms. typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( diff --git a/src/win32/dwrite-extra.hpp b/src/win32/dwrite-extra.hpp index e8caf8f0f..5ad7aea9a 100644 --- a/src/win32/dwrite-extra.hpp +++ b/src/win32/dwrite-extra.hpp @@ -3,6 +3,8 @@ #ifndef DWRITE_EXTRA_H #define DWRITE_EXTRA_H +#include + #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10 // The DWRITE_COLOR_GLYPH_RUN struct isn't valid. // From 457ab827c9b22b813239486ac190468e9adecf65 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Mon, 16 Jun 2025 15:29:08 +0200 Subject: [PATCH 11/12] Add definition for IDWriteFactory8 --- meson.build | 8 ++++++++ src/win32/dwrite-extra.hpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/meson.build b/meson.build index eac9e9302..f6431aab6 100644 --- a/meson.build +++ b/meson.build @@ -540,6 +540,14 @@ if host_machine.system() == 'windows' '-DNTDDI_VERSION=0x0A000010', ] + foreach i : range(8, 9) + if cpp_compiler.has_type('IDWriteFactory' + i.to_string(), + prefix: ['#include ', '#include '], + args: sdk_version_args) + conf.set('HAVE_IDWRITEFACTORY' + i.to_string(), 1) + endif + endforeach + if cpp_compiler.has_header('d2d1_2.h') conf.set('HAVE_D2D1_2_H', 1) endif diff --git a/src/win32/dwrite-extra.hpp b/src/win32/dwrite-extra.hpp index 5ad7aea9a..3978badb6 100644 --- a/src/win32/dwrite-extra.hpp +++ b/src/win32/dwrite-extra.hpp @@ -5,6 +5,35 @@ #include +#ifndef HAVE_IDWRITEFACTORY8 + +typedef enum DWRITE_PAINT_FEATURE_LEVEL { + DWRITE_PAINT_FEATURE_LEVEL_NONE = 0, + DWRITE_PAINT_FEATURE_LEVEL_COLR_V0 = 1, + DWRITE_PAINT_FEATURE_LEVEL_COLR_V1 = 2 +} DWRITE_PAINT_FEATURE_LEVEL; + +DEFINE_GUID(IID_IDWriteFactory8, 0xee0a7fb5, 0xdef4, 0x4c23, 0xa4,0x54, 0xc9,0xc7,0xdc,0x87,0x83,0x98); +MIDL_INTERFACE("ee0a7fb5-def4-4c23-a454-c9c7dc878398") +IDWriteFactory8 : public IDWriteFactory7 +{ + virtual HRESULT STDMETHODCALLTYPE TranslateColorGlyphRun( + D2D1_POINT_2F origin, + const DWRITE_GLYPH_RUN *glyph_run, + const DWRITE_GLYPH_RUN_DESCRIPTION *glyph_run_desc, + DWRITE_GLYPH_IMAGE_FORMATS image_formats, + DWRITE_PAINT_FEATURE_LEVEL feature_level, + DWRITE_MEASURING_MODE measuring_mode, + const DWRITE_MATRIX *world_and_dpi_transform, + UINT32 palette_index, + IDWriteColorGlyphRunEnumerator1 **enumerator) = 0; +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IDWriteFactory8, 0xee0a7fb5, 0xdef4, 0x4c23, 0xa4,0x54, 0xc9,0xc7,0xdc,0x87,0x83,0x98) +#endif + +#endif + #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10 // The DWRITE_COLOR_GLYPH_RUN struct isn't valid. // From 1aaa23aefbddb01af07cc5ef1a3ad418cdd20a4b Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Sat, 14 Jun 2025 15:54:53 +0200 Subject: [PATCH 12/12] DWrite: Add support for COLRv1 fonts Fixes https://gitlab.freedesktop.org/cairo/cairo/-/issues/903 --- src/win32/cairo-dwrite-font.cpp | 91 +++++++++++++++++++++--------- src/win32/cairo-dwrite-private.hpp | 11 ++++ src/win32/dwrite-extra.hpp | 14 +++++ 3 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index 57fe6f5b0..aca908723 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -219,6 +219,7 @@ RefPtr DWriteFactory::mFactoryInstance1; RefPtr DWriteFactory::mFactoryInstance2; RefPtr DWriteFactory::mFactoryInstance3; RefPtr DWriteFactory::mFactoryInstance4; +RefPtr DWriteFactory::mFactoryInstance8; RefPtr WICImagingFactory::mFactoryInstance; RefPtr DWriteFactory::mSystemCollection; @@ -1140,13 +1141,16 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat); /* The list of glyph image formats this renderer is prepared to support. */ - DWRITE_GLYPH_IMAGE_FORMATS supported_formats = static_cast( - DWRITE_GLYPH_IMAGE_FORMATS_COLR | - DWRITE_GLYPH_IMAGE_FORMATS_SVG | - DWRITE_GLYPH_IMAGE_FORMATS_PNG | - DWRITE_GLYPH_IMAGE_FORMATS_JPEG | - DWRITE_GLYPH_IMAGE_FORMATS_TIFF | - DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8); + const DWRITE_GLYPH_IMAGE_FORMATS_ base_formats = ( + DWRITE_GLYPH_IMAGE_FORMATS_COLR_ | + DWRITE_GLYPH_IMAGE_FORMATS_SVG_ | + DWRITE_GLYPH_IMAGE_FORMATS_PNG_ | + DWRITE_GLYPH_IMAGE_FORMATS_JPEG_ | + DWRITE_GLYPH_IMAGE_FORMATS_TIFF_ | + DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8_); + + // Level of support for DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE + DWRITE_PAINT_FEATURE_LEVEL dwrite_paint_feature_level = DWRITE_PAINT_FEATURE_LEVEL_COLR_V1; RefPtr fontFace2; UINT32 palette_count = 0; @@ -1157,15 +1161,35 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s if (scaled_font->base.options.palette_index < palette_count) palette_index = scaled_font->base.options.palette_index; - hr = DWriteFactory::Instance4()->TranslateColorGlyphRun( - origin, - &run, - NULL, /* glyphRunDescription */ - supported_formats, - dwrite_font_face->measuring_mode, - &matrix, - palette_index, - &run_enumerator); + if (DWriteFactory::Instance8().get()) { + hr = DWriteFactory::Instance8()->TranslateColorGlyphRun( + origin, + &run, + NULL, /* glyphRunDescription */ + static_cast + (base_formats | DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE_), + dwrite_paint_feature_level, + dwrite_font_face->measuring_mode, + &matrix, + palette_index, + &run_enumerator); + } + else if (DWriteFactory::Instance4().get()) { + hr = DWriteFactory::Instance4()->TranslateColorGlyphRun( + origin, + &run, + NULL, /* glyphRunDescription */ + static_cast + (base_formats), + dwrite_font_face->measuring_mode, + &matrix, + palette_index, + &run_enumerator); + } + else { + // TODO + return CAIRO_INT_STATUS_UNSUPPORTED; + } if (hr == DWRITE_E_NOCOLOR) { /* No color glyphs */ @@ -1242,11 +1266,12 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s if (FAILED(hr)) return _cairo_dwrite_error (hr, "GetCurrentRun failed"); - switch (color_run->glyphImageFormat) { - case DWRITE_GLYPH_IMAGE_FORMATS_PNG: - case DWRITE_GLYPH_IMAGE_FORMATS_JPEG: - case DWRITE_GLYPH_IMAGE_FORMATS_TIFF: - case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8: + const auto format = static_cast(color_run->glyphImageFormat); + switch (format) { + case DWRITE_GLYPH_IMAGE_FORMATS_PNG_: + case DWRITE_GLYPH_IMAGE_FORMATS_JPEG_: + case DWRITE_GLYPH_IMAGE_FORMATS_TIFF_: + case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8_: /* Bitmap glyphs */ dc4->DrawColorBitmapGlyphRun(color_run->glyphImageFormat, origin, @@ -1255,7 +1280,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT); break; - case DWRITE_GLYPH_IMAGE_FORMATS_SVG: + case DWRITE_GLYPH_IMAGE_FORMATS_SVG_: /* SVG glyphs */ dc4->DrawSvgGlyphRun(origin, &color_run->glyphRun, @@ -1265,9 +1290,9 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s dwrite_font_face->measuring_mode); uses_foreground_color = TRUE; break; - case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE: - case DWRITE_GLYPH_IMAGE_FORMATS_CFF: - case DWRITE_GLYPH_IMAGE_FORMATS_COLR: + case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE_: + case DWRITE_GLYPH_IMAGE_FORMATS_CFF_: + case DWRITE_GLYPH_IMAGE_FORMATS_COLR_: /* Outline glyphs */ if (color_run->paletteIndex == 0xFFFF) { D2D1_COLOR_F color = foreground_color_brush->GetColor(); @@ -1291,7 +1316,21 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s color_run->glyphRunDescription, color_brush, dwrite_font_face->measuring_mode); - case DWRITE_GLYPH_IMAGE_FORMATS_NONE: + break; + case DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE_: + { + RefPtr dc7; + hr = rt->QueryInterface(&dc7); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "QueryInterface(&dc7) failed"); + dc7->DrawPaintGlyphRun (origin, + &color_run->glyphRun, + foreground_color_brush, + palette_index, + dwrite_font_face->measuring_mode); + break; + } + case DWRITE_GLYPH_IMAGE_FORMATS_NONE_: break; } } diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index 62fe8d6ad..ac0c3614e 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -125,6 +125,16 @@ public: return mFactoryInstance4; } + static RefPtr Instance8() + { + if (!mFactoryInstance8) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance8); + } + } + return mFactoryInstance8; + } + static RefPtr SystemCollection() { if (!mSystemCollection) { @@ -169,6 +179,7 @@ private: static RefPtr mFactoryInstance2; static RefPtr mFactoryInstance3; static RefPtr mFactoryInstance4; + static RefPtr mFactoryInstance8; static RefPtr mSystemCollection; static RefPtr mDefaultRenderingParams; }; diff --git a/src/win32/dwrite-extra.hpp b/src/win32/dwrite-extra.hpp index 3978badb6..f87fdecf0 100644 --- a/src/win32/dwrite-extra.hpp +++ b/src/win32/dwrite-extra.hpp @@ -5,6 +5,20 @@ #include +typedef enum DWRITE_GLYPH_IMAGE_FORMATS_ { + DWRITE_GLYPH_IMAGE_FORMATS_NONE_ = 0, + DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE_ = 1 << 0, + DWRITE_GLYPH_IMAGE_FORMATS_CFF_ = 1 << 1, + DWRITE_GLYPH_IMAGE_FORMATS_COLR_ = 1 << 2, + DWRITE_GLYPH_IMAGE_FORMATS_SVG_ = 1 << 3, + DWRITE_GLYPH_IMAGE_FORMATS_PNG_ = 1 << 4, + DWRITE_GLYPH_IMAGE_FORMATS_JPEG_ = 1 << 5, + DWRITE_GLYPH_IMAGE_FORMATS_TIFF_ = 1 << 6, + DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8_ = 1 << 7, + DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE_ = 1 << 8 +} DWRITE_GLYPH_IMAGE_FORMATS_; +DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS_) + #ifndef HAVE_IDWRITEFACTORY8 typedef enum DWRITE_PAINT_FEATURE_LEVEL {