[Libreoffice-commits] core.git: external/skia vcl/inc vcl/skia vcl/win

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Wed Mar 18 09:48:44 UTC 2020


 external/skia/UnpackedTarball_skia.mk        |    1 
 external/skia/windows-hfont-typeface.patch.0 |  134 +++++++++++++++++++++++++++
 vcl/inc/skia/win/gdiimpl.hxx                 |    3 
 vcl/inc/win/wingdiimpl.hxx                   |    3 
 vcl/skia/win/gdiimpl.cxx                     |   55 +++++++++++
 vcl/win/gdi/winlayout.cxx                    |    6 -
 6 files changed, 200 insertions(+), 2 deletions(-)

New commits:
commit 271e8c99a2a1e28b7eb9fdc5fe16f8be1e8ee763
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Mon Mar 16 15:08:11 2020 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Wed Mar 18 10:48:19 2020 +0100

    implement text rendering using directly Skia (Windows)
    
    The Windows code needed for Skia text rendering. Like with the X11
    code, the font is slightly lighter than with Skia disabled, but
    otherwise it seems to work.
    And like the X11 code this also requires patching Skia to use
    the font we want.
    
    Change-Id: Ib5ba52e4ba51b6523617072b77ed5446e7343f46
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90582
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk
index 6ffde2006590..42276177ab33 100644
--- a/external/skia/UnpackedTarball_skia.mk
+++ b/external/skia/UnpackedTarball_skia.mk
@@ -28,6 +28,7 @@ skia_patches := \
     msvc-vectorcall-sse.patch.1 \
     clang11-flax-vector-conversion.patch.0 \
     fontconfig-get-typeface.patch.0 \
+    windows-hfont-typeface.patch.0 \
 
 $(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1))
 
diff --git a/external/skia/windows-hfont-typeface.patch.0 b/external/skia/windows-hfont-typeface.patch.0
new file mode 100644
index 000000000000..459595a7b3d6
--- /dev/null
+++ b/external/skia/windows-hfont-typeface.patch.0
@@ -0,0 +1,134 @@
+--- ./include/ports/SkTypeface_win.h.sav	2019-09-19 11:38:00.943185300 +0200
++++ ./include/ports/SkTypeface_win.h	2020-03-16 15:11:38.347067100 +0100
+@@ -28,6 +28,8 @@
+  */
+ SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
+ 
++SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&, HFONT);
++
+ /**
+  *  Copy the LOGFONT associated with this typeface into the lf parameter. Note
+  *  that the lfHeight will need to be set afterwards, since the typeface does
+--- ./src/ports/SkFontHost_win.cpp.sav	2020-03-16 15:22:02.620518100 +0100
++++ ./src/ports/SkFontHost_win.cpp	2020-03-16 15:27:12.733594400 +0100
+@@ -215,6 +215,11 @@
+         , fFont(::CreateFontIndirect(&lf))
+         , fSavefont((HFONT)::SelectObject(fHdc, fFont))
+     { }
++    explicit SkAutoHDC(const HFONT hf)
++        : fHdc(::CreateCompatibleDC(nullptr))
++        , fFont(nullptr)
++        , fSavefont((HFONT)::SelectObject(fHdc, hf))
++    { }
+     ~SkAutoHDC() {
+         if (fHdc) {
+             ::SelectObject(fHdc, fSavefont);
+@@ -238,8 +243,22 @@
+         : SkTypeface(style, false)
+         , fLogFont(lf)
+         , fSerializeAsStream(serializeAsStream)
++        , hFont(nullptr)
+     {
+         SkAutoHDC hdc(fLogFont);
++        init(hdc, style, lf);
++    }
++    LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, HFONT hf, bool serializeAsStream)
++        : SkTypeface(style, false)
++        , fLogFont(lf)
++        , fSerializeAsStream(serializeAsStream)
++        , hFont(hf)
++    {
++        SkAutoHDC hdc(hFont);
++        init(hdc, style, lf);
++    }
++    void init(SkAutoHDC& hdc, const SkFontStyle& style, const LOGFONT& lf)
++    {
+         TEXTMETRIC textMetric;
+         if (0 == GetTextMetrics(hdc, &textMetric)) {
+             call_ensure_accessible(lf);
+@@ -260,6 +279,7 @@
+     }
+ 
+     LOGFONT fLogFont;
++    HFONT hFont;
+     bool fSerializeAsStream;
+     bool fCanBeLCD;
+ 
+@@ -267,6 +287,10 @@
+         return sk_sp<LogFontTypeface>(new LogFontTypeface(get_style(lf), lf, false));
+     }
+ 
++    static sk_sp<LogFontTypeface> Make(const LOGFONT& lf, HFONT hf) {
++        return sk_sp<LogFontTypeface>(new LogFontTypeface(get_style(lf), lf, hf, false));
++    }
++
+     static void EnsureAccessible(const SkTypeface* face) {
+         call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
+     }
+@@ -348,7 +372,7 @@
+  */
+ SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
+     LOGFONT lf = origLF;
+-    make_canonical(&lf);
++//    make_canonical(&lf);
+     sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
+     if (!face) {
+         face = LogFontTypeface::Make(lf);
+@@ -357,12 +381,33 @@
+     return face.release();
+ }
+ 
++static bool FindByLogFontAndHFont(SkTypeface* face, void* ctx) {
++    LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
++    const std::pair<LOGFONT*,HFONT>* data = reinterpret_cast<const std::pair<LOGFONT*,HFONT>*>(ctx);
++    const LOGFONT* lf = data->first;
++    const HFONT hf = data->second;
++
++    return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)) && lface->hFont == hf;
++}
++
++SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF, HFONT hFont) {
++    LOGFONT lf = origLF;
++//    make_canonical(&lf);
++    std::pair<LOGFONT*,HFONT> data = std::make_pair(&lf,hFont);
++    sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(FindByLogFontAndHFont, &data);
++    if (!face) {
++        face = LogFontTypeface::Make(lf,hFont);
++        SkTypefaceCache::Add(face);
++    }
++    return face.release();
++}
++
+ /**
+  *  The created SkTypeface takes ownership of fontMemResource.
+  */
+ sk_sp<SkTypeface> SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
+     LOGFONT lf = origLF;
+-    make_canonical(&lf);
++//    make_canonical(&lf);
+     // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
+     return FontMemResourceTypeface::Make(lf, fontMemResource);
+ }
+@@ -686,7 +731,10 @@
+     LOGFONT lf = typeface->fLogFont;
+     lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
+     lf.lfQuality = compute_quality(fRec);
+-    fFont = CreateFontIndirect(&lf);
++    if(typeface->hFont != nullptr)
++        fFont = typeface->hFont;
++    else
++        fFont = CreateFontIndirect(&lf);
+     if (!fFont) {
+         return;
+     }
+@@ -788,7 +836,9 @@
+         ::DeleteDC(fDDC);
+     }
+     if (fFont) {
+-        ::DeleteObject(fFont);
++        LogFontTypeface* typeface = static_cast<LogFontTypeface*>(this->getTypeface());
++        if(typeface->hFont != fFont)
++            ::DeleteObject(fFont);
+     }
+     if (fSC) {
+         ::ScriptFreeCache(&fSC);
diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 676e743151e7..3d6c680f2af4 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -73,6 +73,9 @@ public:
     virtual bool RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, int nX,
                                              int nY, ControlCacheKey& aControlCacheKey) override;
 
+    virtual bool DrawTextLayout(const GenericSalLayout& layout) override;
+    // TODO This method of text drawing can probably be removed once DrawTextLayout()
+    // is fully usable.
     virtual bool UseTextDraw() const override { return true; }
     virtual void PreDrawText() override;
     virtual void PostDrawText() override;
diff --git a/vcl/inc/win/wingdiimpl.hxx b/vcl/inc/win/wingdiimpl.hxx
index 84884220318f..e81e35201413 100644
--- a/vcl/inc/win/wingdiimpl.hxx
+++ b/vcl/inc/win/wingdiimpl.hxx
@@ -35,6 +35,9 @@ public:
         abort();
     };
 
+    // Implementation for WinSalGraphics::DrawTextLayout().
+    // Returns true if handled, if false, then WinSalGraphics will handle it itself.
+    virtual bool DrawTextLayout(const GenericSalLayout&) { return false; }
     // If true is returned, the following functions are used for text rendering.
     virtual bool UseTextDraw() const { return false; }
     virtual void PreDrawText() {}
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index 84aed4f05b92..b7014ed33b48 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -13,12 +13,17 @@
 #include <vcl/skia/SkiaHelper.hxx>
 #include <skia/utils.hxx>
 #include <skia/zone.hxx>
+#include <win/winlayout.hxx>
 
 #include <SkColorFilter.h>
 #include <SkPixelRef.h>
+#include <SkTypeface_win.h>
+#include <SkFont.h>
 #include <tools/sk_app/win/WindowContextFactory_win.h>
 #include <tools/sk_app/WindowContext.h>
 
+#include <windows.h>
+
 WinSkiaSalGraphicsImpl::WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics,
                                                SalGeometryProvider* mpProvider)
     : SkiaSalGraphicsImpl(rGraphics, mpProvider)
@@ -104,6 +109,56 @@ bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, C
     return true;
 }
 
+bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout)
+{
+    const WinFontInstance& rWinFont = static_cast<const WinFontInstance&>(rLayout.GetFont());
+    float fHScale = rWinFont.getHScale();
+
+    assert(dynamic_cast<const WinFontInstance*>(&rLayout.GetFont()));
+    const WinFontInstance* pWinFont = static_cast<const WinFontInstance*>(&rLayout.GetFont());
+    const HFONT hLayoutFont = pWinFont->GetHFONT();
+    LOGFONT logFont;
+    if (::GetObjectW(hLayoutFont, sizeof(logFont), &logFont) == 0)
+    {
+        assert(false);
+        return false;
+    }
+    // Wrap the font in Skia's SkTypeFace subclass that's been patched
+    // to use it.
+    sk_sp<SkTypeface> typeface(SkCreateTypefaceFromLOGFONT(logFont, hLayoutFont));
+    // lfHeight actually depends on DPI, so it's not really font height as such,
+    // but for LOGFONT-based typefaces Skia simply sets lfHeight back to this value
+    // directly.
+    // This is probably not necessary since we pass also the HFONT itself, but better
+    // forward that information too, in case SkFont uses it somehow.
+    double fontHeight = logFont.lfHeight;
+    if (fontHeight < 0)
+        fontHeight = -fontHeight;
+    SkFont font(typeface, fontHeight, fHScale, 0);
+    // Skia needs to be explicitly told what kind of antialiasing should be used,
+    // get it from system settings. This does not actually matter for the text
+    // rendering itself, since it will use the font passed to Skia in the code above
+    // (and that one uses DEFAULT_QUALITY, so Windows will select the appropriate AA setting),
+    // but Skia internally chooses the format to which the glyphs will be rendered
+    // based on this setting (subpixel AA requires colors, others do not).
+    BOOL set;
+    if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &set, 0) && set)
+    {
+        UINT set2;
+        if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &set2, 0)
+            && set2 == FE_FONTSMOOTHINGCLEARTYPE)
+            font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+        else
+            font.setEdging(SkFont::Edging::kAntiAlias);
+    }
+    assert(dynamic_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl()));
+    SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl());
+    COLORREF color = ::GetTextColor(mWinParent.getHDC());
+    Color salColor(GetRValue(color), GetGValue(color), GetBValue(color));
+    impl->drawGenericLayout(rLayout, salColor, font);
+    return true;
+}
+
 void WinSkiaSalGraphicsImpl::PreDrawText() { preDraw(); }
 
 void WinSkiaSalGraphicsImpl::PostDrawText() { postDraw(); }
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index e13d6930df64..636cac595bf1 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -543,11 +543,13 @@ void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout, HDC hDC, bo
 
 void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
 {
-    HDC hDC = getHDC();
+    WinSalGraphicsImplBase* pImpl = dynamic_cast<WinSalGraphicsImplBase*>(mpImpl.get());
+    if( !mbPrinter && pImpl->DrawTextLayout(rLayout))
+        return; // handled by pImpl
 
+    HDC hDC = getHDC();
     const WinFontInstance* pWinFont = static_cast<const WinFontInstance*>(&rLayout.GetFont());
     const HFONT hLayoutFont = pWinFont->GetHFONT();
-    WinSalGraphicsImplBase* pImpl = dynamic_cast<WinSalGraphicsImplBase*>(mpImpl.get());
     bool bUseClassic = !pImpl->UseTextDraw() || mbPrinter;
 
     // Our DirectWrite renderer is incomplete, skip it for vertical text where glyphs are not


More information about the Libreoffice-commits mailing list