summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/skia/win/gdiimpl.hxx3
-rw-r--r--vcl/skia/win/gdiimpl.cxx254
2 files changed, 213 insertions, 44 deletions
diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index c5b12d08811a..7e399c59effb 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -65,8 +65,7 @@ protected:
virtual void createWindowSurfaceInternal(bool forceRaster = false) override;
static sk_sp<SkTypeface> createDirectWriteTypeface(const WinFontInstance* pWinFont);
static void initFontInfo();
- inline static sal::systools::COMReference<IDWriteFontSetBuilder> dwriteFontSetBuilder;
- inline static sal::systools::COMReference<IDWriteFontCollection1> dwritePrivateCollection;
+ inline static sal::systools::COMReference<IDWriteFontCollection> dwritePrivateCollection;
inline static sk_sp<SkFontMgr> dwriteFontMgr;
inline static bool dwriteDone = false;
static SkFont::Edging fontEdging;
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index 1d48fb9bbe71..4a8e6266fe63 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -32,6 +32,217 @@
#include <windows.h>
+#include <type_traits>
+
+namespace
+{
+sal::systools::COMReference<IDWriteFontCollection>
+getDWritePrivateFontCollection_w10(IDWriteFontFile* fontFile)
+{
+ static sal::systools::COMReference<IDWriteFactory3> dwriteFactory3 = [] {
+ IDWriteFactory* dwriteFactory = WinSalGraphics::getDWriteFactory();
+ sal::systools::COMReference<IDWriteFactory3> factory3;
+ dwriteFactory->QueryInterface(&factory3);
+ return factory3;
+ }();
+ if (!dwriteFactory3)
+ return {};
+
+ static sal::systools::COMReference<IDWriteFontSetBuilder> dwriteFontSetBuilder = [] {
+ sal::systools::COMReference<IDWriteFontSetBuilder> builder;
+ dwriteFactory3->CreateFontSetBuilder(&dwriteFontSetBuilder);
+ return builder;
+ }();
+ if (!dwriteFontSetBuilder)
+ return {};
+
+ BOOL isSupported;
+ DWRITE_FONT_FILE_TYPE fileType;
+ UINT32 numberOfFonts;
+ sal::systools::ThrowIfFailed(
+ fontFile->Analyze(&isSupported, &fileType, nullptr, &numberOfFonts), SAL_WHERE);
+ if (!isSupported)
+ return {};
+
+ // For each font within the font file, get a font face reference and add to the builder.
+ for (UINT32 fontIndex = 0; fontIndex < numberOfFonts; ++fontIndex)
+ {
+ sal::systools::COMReference<IDWriteFontFaceReference> fontFaceReference;
+ if (FAILED(dwriteFactory3->CreateFontFaceReference(
+ fontFile, fontIndex, DWRITE_FONT_SIMULATIONS_NONE, &fontFaceReference)))
+ continue;
+
+ // Leave it to DirectWrite to read properties directly out of the font files
+ dwriteFontSetBuilder->AddFontFaceReference(fontFaceReference);
+ }
+
+ sal::systools::COMReference<IDWriteFontSet> fontSet;
+ sal::systools::ThrowIfFailed(dwriteFontSetBuilder->CreateFontSet(&fontSet), SAL_WHERE);
+
+ sal::systools::COMReference<IDWriteFontCollection1> fc1;
+ sal::systools::ThrowIfFailed(dwriteFactory3->CreateFontCollectionFromFontSet(fontSet, &fc1),
+ SAL_WHERE);
+ return { fc1.get() };
+}
+
+// The following is only needed until we bump baseline to Windows 10
+
+template <class I> requires std::is_base_of_v<IUnknown, I> class IUnknown_Impl : public I
+{
+public:
+ virtual ~IUnknown_Impl() {}
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) override
+ {
+ if (iid == IID_IUnknown || iid == __uuidof(I))
+ {
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObject = nullptr;
+ return E_NOINTERFACE;
+ }
+ ULONG STDMETHODCALLTYPE AddRef() override { return ++m_nRef; }
+ ULONG STDMETHODCALLTYPE Release() override
+ {
+ ULONG n = --m_nRef;
+ if (n == 0)
+ delete this;
+ return n;
+ };
+
+private:
+ std::atomic<ULONG> m_nRef = 0;
+};
+
+// A simple loader class, which only stores the font files (to fulfill the requirement that
+// "each key is ... valid until the loader is unregistered using the factory"), and creates
+// instances of enumerator
+class FontCollectionLoader_w7 : public IUnknown_Impl<IDWriteFontCollectionLoader>
+{
+public:
+ // IDWriteFontCollectionLoader
+ HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
+ IDWriteFactory* factory, void const* collectionKey, UINT32 collectionKeySize,
+ /* OUT */ IDWriteFontFileEnumerator** fontFileEnumerator) override;
+
+private:
+ std::vector<sal::systools::COMReference<IDWriteFontFile>> m_fontFiles;
+};
+
+// A singleton class, that (1) caches IDWriteFactory, to avoid destruction order problems,
+// (2) holds the FontCollectionLoader_w7 singleton, and (3) calls IDWriteFactory's
+// (Un)RegisterFontCollectionLoader, because these can't be called from destructor of
+// FontCollectionLoader_w7, because RegisterFontCollectionLoader calls AddRef.
+struct FontCollectionLoader_w7_singleton_t
+{
+ sal::systools::COMReference<IDWriteFactory> factory;
+ sal::systools::COMReference<FontCollectionLoader_w7> loader;
+ FontCollectionLoader_w7_singleton_t()
+ : factory(WinSalGraphics::getDWriteFactory())
+ , loader(new FontCollectionLoader_w7)
+ {
+ factory->RegisterFontCollectionLoader(loader);
+ }
+ ~FontCollectionLoader_w7_singleton_t() { factory->UnregisterFontCollectionLoader(loader); }
+};
+
+// A simple enumerator class, which only operates on a single font file.
+class FontFileEnumerator_w7 : public IUnknown_Impl<IDWriteFontFileEnumerator>
+{
+public:
+ FontFileEnumerator_w7(IDWriteFontFile* collectionKey)
+ : m_fontFile(collectionKey)
+ {
+ assert(collectionKey);
+ AddRef();
+ }
+
+ // IDWriteFontFileEnumerator
+ HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile) override;
+ HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile) override;
+
+private:
+ sal::systools::COMReference<IDWriteFontFile> m_fontFile;
+ size_t m_nextIndex = 0;
+};
+
+HRESULT STDMETHODCALLTYPE FontCollectionLoader_w7::CreateEnumeratorFromKey(
+ IDWriteFactory* /*factory*/, void const* collectionKey, UINT32 collectionKeySize,
+ /* OUT */ IDWriteFontFileEnumerator** fontFileEnumerator)
+{
+ if (!fontFileEnumerator)
+ return E_INVALIDARG;
+ *fontFileEnumerator = nullptr;
+ if (!collectionKey || collectionKeySize != sizeof(IDWriteFontFile*))
+ return E_INVALIDARG;
+
+ auto pFontFile = *static_cast<IDWriteFontFile* const*>(collectionKey);
+ auto it = std::find_if(m_fontFiles.begin(), m_fontFiles.end(),
+ [pFontFile](const auto& el) { return el.get() == pFontFile; });
+ if (it == m_fontFiles.end())
+ m_fontFiles.emplace_back(pFontFile); // cals AddRef
+
+ *fontFileEnumerator = new (std::nothrow) FontFileEnumerator_w7(pFontFile);
+ return *fontFileEnumerator ? S_OK : E_OUTOFMEMORY;
+}
+
+HRESULT STDMETHODCALLTYPE FontFileEnumerator_w7::MoveNext(BOOL* hasCurrentFile)
+{
+ if (!hasCurrentFile)
+ return E_INVALIDARG;
+ *hasCurrentFile = m_nextIndex == 0 ? TRUE : FALSE;
+ ++m_nextIndex;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FontFileEnumerator_w7::GetCurrentFontFile(IDWriteFontFile** fontFile)
+{
+ if (!fontFile)
+ return E_INVALIDARG;
+ if (m_nextIndex == 1)
+ {
+ *fontFile = m_fontFile;
+ m_fontFile->AddRef();
+ return S_OK;
+ }
+ *fontFile = nullptr;
+ return E_FAIL;
+}
+
+sal::systools::COMReference<IDWriteFontCollection>
+getDWritePrivateFontCollection_w7(IDWriteFontFile* fontFile)
+{
+ static FontCollectionLoader_w7_singleton_t singleton;
+ sal::systools::COMReference<IDWriteFontCollection> collection;
+ sal::systools::ThrowIfFailed(singleton.factory->CreateCustomFontCollection(
+ singleton.loader, &fontFile, sizeof(fontFile), &collection),
+ SAL_WHERE);
+ return collection;
+}
+
+// End of pre-Windows 10 compatibility code
+
+sal::systools::COMReference<IDWriteFontCollection>
+getDWritePrivateFontCollection(IDWriteFontFace* fontFace)
+{
+ UINT32 numberOfFiles;
+ sal::systools::ThrowIfFailed(fontFace->GetFiles(&numberOfFiles, nullptr), SAL_WHERE);
+ if (numberOfFiles != 1)
+ return {};
+
+ sal::systools::COMReference<IDWriteFontFile> fontFile;
+ sal::systools::ThrowIfFailed(fontFace->GetFiles(&numberOfFiles, &fontFile), SAL_WHERE);
+
+ if (auto collection = getDWritePrivateFontCollection_w10(fontFile))
+ return collection;
+ return getDWritePrivateFontCollection_w7(fontFile);
+}
+}
+
using namespace SkiaHelper;
WinSkiaSalGraphicsImpl::WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics,
@@ -155,47 +366,7 @@ WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const WinFontInstance* pWinFon
// collection. For such cases attempt to update a collection of
// private fonts with this newly used font.
- sal::systools::COMReference<IDWriteFactory3> dwriteFactory3;
- ThrowIfFailed(dwriteFactory->QueryInterface(&dwriteFactory3), SAL_WHERE);
-
- if (!dwriteFontSetBuilder)
- ThrowIfFailed(dwriteFactory3->CreateFontSetBuilder(&dwriteFontSetBuilder),
- SAL_WHERE);
-
- UINT32 numberOfFiles;
- ThrowIfFailed(fontFace->GetFiles(&numberOfFiles, nullptr), SAL_WHERE);
- if (numberOfFiles != 1)
- return nullptr;
-
- sal::systools::COMReference<IDWriteFontFile> fontFile;
- ThrowIfFailed(fontFace->GetFiles(&numberOfFiles, &fontFile), SAL_WHERE);
-
- BOOL isSupported;
- DWRITE_FONT_FILE_TYPE fileType;
- UINT32 numberOfFonts;
- ThrowIfFailed(fontFile->Analyze(&isSupported, &fileType, nullptr, &numberOfFonts),
- SAL_WHERE);
- if (!isSupported)
- return nullptr;
-
- // For each font within the font file, get a font face reference and add to the builder.
- for (UINT32 fontIndex = 0; fontIndex < numberOfFonts; ++fontIndex)
- {
- sal::systools::COMReference<IDWriteFontFaceReference> fontFaceReference;
- if (FAILED(dwriteFactory3->CreateFontFaceReference(fontFile.get(), fontIndex,
- DWRITE_FONT_SIMULATIONS_NONE,
- &fontFaceReference)))
- continue;
-
- // Leave it to DirectWrite to read properties directly out of the font files
- dwriteFontSetBuilder->AddFontFaceReference(fontFaceReference.get());
- }
-
- sal::systools::COMReference<IDWriteFontSet> fontSet;
- ThrowIfFailed(dwriteFontSetBuilder->CreateFontSet(&fontSet), SAL_WHERE);
- ThrowIfFailed(dwriteFactory3->CreateFontCollectionFromFontSet(fontSet.get(),
- &dwritePrivateCollection),
- SAL_WHERE);
+ dwritePrivateCollection = getDWritePrivateFontCollection(fontFace);
ThrowIfFailed(dwritePrivateCollection->GetFontFromFontFace(fontFace, &font), SAL_WHERE);
}
}
@@ -323,7 +494,6 @@ void WinSkiaSalGraphicsImpl::initFontInfo()
void WinSkiaSalGraphicsImpl::ClearDevFontCache()
{
dwriteFontMgr.reset();
- dwriteFontSetBuilder.clear();
dwritePrivateCollection.clear();
dwriteDone = false;
initFontInfo(); // get font info again, just in case