From 132b1492280a97d04ed4fdffbcdc40426d3c8d86 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 4 Mar 2026 16:23:28 +0100 Subject: [PATCH] DWriteFactory: Make thread-safe TODO: add comment about shared factory and concurrent accesses --- src/win32/cairo-dwrite-font.cpp | 15 +++- src/win32/cairo-dwrite-private.hpp | 127 ++++++++++++----------------- 2 files changed, 64 insertions(+), 78 deletions(-) diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index 689aef461..16da3108d 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -180,14 +180,15 @@ private: RefPtr WICImagingFactory::mFactoryInstance; +cairo_atomic_once_t DWriteFactory::mOnceFactories = CAIRO_ATOMIC_ONCE_INIT; RefPtr DWriteFactory::mFactoryInstance; RefPtr DWriteFactory::mFactoryInstance1; RefPtr DWriteFactory::mFactoryInstance2; RefPtr DWriteFactory::mFactoryInstance3; RefPtr DWriteFactory::mFactoryInstance4; RefPtr DWriteFactory::mFactoryInstance8; +cairo_atomic_once_t DWriteFactory::mOnceSystemCollection = CAIRO_ATOMIC_ONCE_INIT; RefPtr DWriteFactory::mSystemCollection; -RefPtr DWriteFactory::mDefaultRenderingParams; RefPtr D2DFactory::mFactoryInstance; @@ -196,8 +197,15 @@ _create_rendering_params(IDWriteRenderingParams *params, const cairo_font_options_t *options, cairo_antialias_t antialias) { - if (!params) - params = DWriteFactory::DefaultRenderingParams(); + RefPtr default_rendering_params; + HRESULT hr; + + if (!params) { + hr = DWriteFactory::Instance()->CreateRenderingParams(&default_rendering_params); + assert(SUCCEEDED(hr)); + params = default_rendering_params.get(); + } + FLOAT gamma = params->GetGamma(); FLOAT enhanced_contrast = params->GetEnhancedContrast(); FLOAT clear_type_level = params->GetClearTypeLevel(); @@ -242,7 +250,6 @@ _create_rendering_params(IDWriteRenderingParams *params, if (!modified) return params; - HRESULT hr; RefPtr params1; hr = params->QueryInterface(¶ms1); if (FAILED(hr)) { diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index ac0c3614e..35b540de3 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -39,13 +39,6 @@ #include "dwrite-extra.hpp" #include "d2d1-extra.hpp" -// DirectWrite is not available on all platforms. -typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( - DWRITE_FACTORY_TYPE factoryType, - REFIID iid, - IUnknown **factory -); - /* #cairo_scaled_font_t implementation */ struct _cairo_dwrite_scaled_font { cairo_scaled_font_t base; @@ -63,96 +56,56 @@ class DWriteFactory public: static RefPtr Instance() { - if (!mFactoryInstance) { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - HMODULE dwrite = _cairo_win32_load_library_from_system32 (L"dwrite.dll"); - DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc) - GetProcAddress(dwrite, "DWriteCreateFactory"); -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - if (createDWriteFactory) { - HRESULT hr = createDWriteFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast(&mFactoryInstance)); - assert(SUCCEEDED(hr)); - } - } - return mFactoryInstance; + InitializeFactories(); + return mFactoryInstance; } static RefPtr Instance1() { - if (!mFactoryInstance1) { - if (Instance()) { - Instance()->QueryInterface(&mFactoryInstance1); - } - } - return mFactoryInstance1; + InitializeFactories(); + return mFactoryInstance1; } static RefPtr Instance2() { - if (!mFactoryInstance2) { - if (Instance()) { - Instance()->QueryInterface(&mFactoryInstance2); - } - } - return mFactoryInstance2; + InitializeFactories(); + return mFactoryInstance2; } static RefPtr Instance3() { - if (!mFactoryInstance3) { - if (Instance()) { - Instance()->QueryInterface(&mFactoryInstance3); - } - } - return mFactoryInstance3; + InitializeFactories(); + return mFactoryInstance3; } static RefPtr Instance4() { - if (!mFactoryInstance4) { - if (Instance()) { - Instance()->QueryInterface(&mFactoryInstance4); - } - } - return mFactoryInstance4; + InitializeFactories(); + return mFactoryInstance4; } static RefPtr Instance8() { - if (!mFactoryInstance8) { - if (Instance()) { - Instance()->QueryInterface(&mFactoryInstance8); - } - } + InitializeFactories(); return mFactoryInstance8; } static RefPtr SystemCollection() { - if (!mSystemCollection) { - if (Instance()) { - HRESULT hr = Instance()->GetSystemFontCollection(&mSystemCollection); - assert(SUCCEEDED(hr)); - } - } - return mSystemCollection; + if (_cairo_atomic_init_once_enter (&mOnceSystemCollection)) { + HRESULT hr = Instance()->GetSystemFontCollection(&mSystemCollection); + assert(SUCCEEDED(hr)); + + _cairo_atomic_init_once_leave (&mOnceSystemCollection); + } + return mSystemCollection; } static RefPtr FindSystemFontFamily(const WCHAR *aFamilyName) { UINT32 idx; BOOL found; - if (!SystemCollection()) { - return NULL; - } + SystemCollection()->FindFamilyName(aFamilyName, &idx, &found); if (!found) { return NULL; @@ -163,25 +116,51 @@ public: return family; } - static RefPtr DefaultRenderingParams() +private: + static void InitializeFactories() { - if (!mDefaultRenderingParams) { - if (Instance()) { - Instance()->CreateRenderingParams(&mDefaultRenderingParams); - } - } - return mDefaultRenderingParams; + if (_cairo_atomic_init_once_enter (&mOnceFactories)) { + typedef HRESULT + (WINAPI *pDWriteCreateFactory_t) (DWRITE_FACTORY_TYPE factoryType, + REFIID iid, + IUnknown **factory); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + HMODULE dwrite = _cairo_win32_load_library_from_system32 (L"dwrite.dll"); + pDWriteCreateFactory_t pDWriteCreateFactory = (pDWriteCreateFactory_t) + GetProcAddress (dwrite, "DWriteCreateFactory"); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + HRESULT hr = pDWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, + __uuidof (IDWriteFactory), + reinterpret_cast(&mFactoryInstance)); + assert(SUCCEEDED(hr)); + + mFactoryInstance->QueryInterface(&mFactoryInstance1); + mFactoryInstance->QueryInterface(&mFactoryInstance2); + mFactoryInstance->QueryInterface(&mFactoryInstance3); + mFactoryInstance->QueryInterface(&mFactoryInstance4); + mFactoryInstance->QueryInterface(&mFactoryInstance8); + + _cairo_atomic_init_once_leave (&mOnceFactories); + } } private: + static cairo_atomic_once_t mOnceFactories; static RefPtr mFactoryInstance; static RefPtr mFactoryInstance1; static RefPtr mFactoryInstance2; static RefPtr mFactoryInstance3; static RefPtr mFactoryInstance4; static RefPtr mFactoryInstance8; + + static cairo_atomic_once_t mOnceSystemCollection; static RefPtr mSystemCollection; - static RefPtr mDefaultRenderingParams; }; class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN