vcl/inc/skia/win/gdiimpl.hxx |    4 ++
 vcl/skia/win/gdiimpl.cxx     |   70 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 68 insertions(+), 6 deletions(-)

New commits:
commit 68818db0ec0e9c308c8a0772d46af551f439b32c
Author:     Caolán McNamara <[email protected]>
AuthorDate: Sun Jan 2 21:55:10 2022 +0000
Commit:     Caolán McNamara <[email protected]>
CommitDate: Tue Jan 11 18:11:23 2022 +0100

    build a IDWriteFontCollection1 of our FR_PRIVATE fonts
    
    so we don't need to fallback to gdi in skia for those
    
    we build it incrementally as GetFontFromFontFace fails
    in the system font set
    
    Change-Id: I2ac6d151657b9b720eed46dd7bcee0e9682e462a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127877
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 58043e5f6a83..a8897d0d7c20 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -25,6 +25,8 @@
 #include <SkFont.h>
 #include <SkFontMgr.h>
 
+#include <dwrite_3.h>
+
 class SkTypeface;
 class ControlCacheKey;
 
@@ -64,6 +66,8 @@ protected:
     static void initFontInfo();
     inline static sal::systools::COMReference<IDWriteFactory> dwriteFactory;
     inline static sal::systools::COMReference<IDWriteGdiInterop> 
dwriteGdiInterop;
+    inline static sal::systools::COMReference<IDWriteFontSetBuilder> 
dwriteFontSetBuilder;
+    inline static sal::systools::COMReference<IDWriteFontCollection1> 
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 a10351888eac..6686ecd0e8ed 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -163,11 +163,7 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
     // different version of the same font installed system-wide).
     // For that CreateFromFaceFromHdc() is necessary. The simpler
     // CreateFontFromLOGFONT() seems to search for the best matching font,
-    // which may not be the exact font. Our private fonts are installed
-    // using AddFontResourceExW( FR_PRIVATE ) and that apparently does
-    // not make them available to DirectWrite (at least, they are not
-    // included the DWrite system font collection). For such cases, we'll
-    // need to fall back to Skia's GDI-based font rendering.
+    // which may not be the exact font.
     HFONT oldFont = SelectFont(hdc, hfont);
     sal::systools::COMReference<IDWriteFontFace> fontFace;
     if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFaceFromHdc(hdc, 
&fontFace))))
@@ -175,6 +171,7 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
         SelectFont(hdc, oldFont);
         return nullptr;
     }
+
     SelectFont(hdc, oldFont);
     sal::systools::COMReference<IDWriteFontCollection> collection;
     if (FAILED(CHECKHR(dwriteFactory->GetSystemFontCollection(&collection))))
@@ -182,7 +179,66 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
     sal::systools::COMReference<IDWriteFont> font;
     // Do not use CHECKHR() here, as said above, this fails for our fonts.
     if (FAILED(collection->GetFontFromFontFace(fontFace.get(), &font)))
-        return nullptr;
+    {
+        // If not found in system collection, try our private font collection.
+        // If that's not possible we'll fall back to Skia's GDI-based font 
rendering.
+        if (!dwritePrivateCollection
+            || 
FAILED(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), &font)))
+        {
+            // Our private fonts are installed using AddFontResourceExW( 
FR_PRIVATE )
+            // and that does not make them available to the DWrite system font
+            // collection. For such cases attempt to update a collection of
+            // private fonts with this newly used font.
+
+            sal::systools::COMReference<IDWriteFactory3> dwriteFactory3;
+            if 
(FAILED(dwriteFactory->QueryInterface<IDWriteFactory3>(&dwriteFactory3)))
+                return nullptr;
+
+            if (!dwriteFontSetBuilder
+                && 
FAILED(dwriteFactory3->CreateFontSetBuilder(&dwriteFontSetBuilder)))
+                return nullptr;
+
+            UINT32 numberOfFiles;
+            if (FAILED(fontFace->GetFiles(&numberOfFiles, nullptr)) || 
numberOfFiles != 1)
+                return nullptr;
+
+            sal::systools::COMReference<IDWriteFontFile> fontFile;
+            if (FAILED(fontFace->GetFiles(&numberOfFiles, &fontFile)))
+                return nullptr;
+
+            BOOL isSupported;
+            DWRITE_FONT_FILE_TYPE fileType;
+            UINT32 numberOfFonts;
+            if (FAILED(fontFile->Analyze(&isSupported, &fileType, nullptr, 
&numberOfFonts))
+                || !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());
+            }
+
+            dwritePrivateCollection.clear();
+            sal::systools::COMReference<IDWriteFontSet> fontSet;
+            if 
(SUCCEEDED(CHECKHR(dwriteFontSetBuilder->CreateFontSet(&fontSet))))
+                dwriteFactory3->CreateFontCollectionFromFontSet(fontSet.get(),
+                                                                
&dwritePrivateCollection);
+        }
+
+        if (!dwritePrivateCollection)
+            return nullptr;
+        // CHECKHR because we expect to succeed here
+        if 
(FAILED(CHECKHR(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), 
&font))))
+            return nullptr;
+    }
     sal::systools::COMReference<IDWriteFontFamily> fontFamily;
     if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily))))
         return nullptr;
@@ -296,6 +352,8 @@ void WinSkiaSalGraphicsImpl::initFontInfo()
 void WinSkiaSalGraphicsImpl::ClearDevFontCache()
 {
     dwriteFontMgr.reset();
+    dwriteFontSetBuilder.clear();
+    dwritePrivateCollection.clear();
     dwriteFactory.clear();
     dwriteGdiInterop.clear();
     dwriteDone = false;

Reply via email to