vcl/Library_vclplug_osx.mk   |    1 
 vcl/inc/quartz/salgdi.h      |   14 +++++-
 vcl/inc/skia/osx/bitmap.hxx  |   26 ++++++++++++
 vcl/inc/skia/osx/gdiimpl.hxx |    5 ++
 vcl/osx/salinst.cxx          |    6 ++
 vcl/quartz/salgdi.cxx        |   38 ++++++++++--------
 vcl/skia/osx/bitmap.cxx      |   88 +++++++++++++++++++++++++++++++++++++++++++
 vcl/skia/osx/gdiimpl.cxx     |   51 ++++++++++++++++++++++++
 8 files changed, 209 insertions(+), 20 deletions(-)

New commits:
commit ab9c627bc8f16dd679a19b0946863cebab7b03bc
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Tue Aug 17 17:05:55 2021 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Aug 23 15:00:45 2021 +0200

    add CreateCGImage() variant for Mac/Skia
    
    Needed at least for 'recent documents' icons in the Mac menubar.
    
    Change-Id: I5a22cf64ff5c5aba2c70ca2556fd0b66c425bafd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120811
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/Library_vclplug_osx.mk b/vcl/Library_vclplug_osx.mk
index 3e0e0ff481be..ddc3a3608f1b 100644
--- a/vcl/Library_vclplug_osx.mk
+++ b/vcl/Library_vclplug_osx.mk
@@ -142,6 +142,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_osx,\
     vcl/quartz/utils \
     vcl/quartz/AquaGraphicsBackend \
     $(if $(filter SKIA,$(BUILD_TYPE)), \
+        vcl/skia/osx/bitmap \
         vcl/skia/osx/gdiimpl \
         vcl/skia/osx/rastercontext \
         ) \
diff --git a/vcl/inc/skia/osx/bitmap.hxx b/vcl/inc/skia/osx/bitmap.hxx
new file mode 100644
index 000000000000..0c0b1ee09be3
--- /dev/null
+++ b/vcl/inc/skia/osx/bitmap.hxx
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX
+#define INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX
+
+#include <vcl/dllapi.h>
+
+#include <osx/osxvcltypes.h>
+
+class Image;
+
+namespace SkiaHelper
+{
+VCL_PLUGIN_PUBLIC CGImageRef createCGImage(const Image& rImage);
+};
+
+#endif // INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index 08fae66b4ad3..dbdb8038b493 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -78,6 +78,7 @@
 #include <vcl/skia/SkiaHelper.hxx>
 #include <skia/salbmp.hxx>
 #include <skia/osx/gdiimpl.hxx>
+#include <skia/osx/bitmap.hxx>
 #endif
 
 extern "C" {
@@ -918,6 +919,11 @@ OUString AquaSalInstance::getOSVersion()
 
 CGImageRef CreateCGImage( const Image& rImage )
 {
+#if HAVE_FEATURE_SKIA
+    if (SkiaHelper::isVCLSkiaEnabled())
+        return SkiaHelper::createCGImage( rImage );
+#endif
+
     BitmapEx aBmpEx( rImage.GetBitmapEx() );
     Bitmap aBmp( aBmpEx.GetBitmap() );
 
diff --git a/vcl/skia/osx/bitmap.cxx b/vcl/skia/osx/bitmap.cxx
new file mode 100644
index 000000000000..77e34697aa50
--- /dev/null
+++ b/vcl/skia/osx/bitmap.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Some of this code is based on Skia source code, covered by the following
+ * license notice (see readlicense_oo for the full license):
+ *
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ */
+
+#include <skia/osx/bitmap.hxx>
+
+#include <vcl/bitmapex.hxx>
+#include <vcl/image.hxx>
+
+#include <skia/salbmp.hxx>
+#include <osx/saldata.hxx>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+
+using namespace SkiaHelper;
+
+namespace SkiaHelper
+{
+CGImageRef createCGImage(const Image& rImage)
+{
+    BitmapEx bitmapEx(rImage.GetBitmapEx());
+    Bitmap bitmap(bitmapEx.GetBitmap());
+
+    if (bitmap.IsEmpty() || !bitmap.ImplGetSalBitmap())
+        return nullptr;
+
+    assert(dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get()) != 
nullptr);
+    SkiaSalBitmap* skiaBitmap = 
static_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+
+    SkBitmap targetBitmap;
+    if (!targetBitmap.tryAllocPixels(
+            SkImageInfo::Make(bitmap.GetSizePixel().getWidth(), 
bitmap.GetSizePixel().getHeight(),
+                              kRGBA_8888_SkColorType, kPremul_SkAlphaType)))
+        return nullptr;
+    SkPaint paint;
+    paint.setBlendMode(SkBlendMode::kSrc); // set as is
+    SkMatrix matrix; // The image is needed upside-down.
+    matrix.preTranslate(0, targetBitmap.height());
+    matrix.setConcat(matrix, SkMatrix::Scale(1, -1));
+
+    if (!bitmapEx.IsAlpha())
+    {
+        SkCanvas canvas(targetBitmap);
+        canvas.concat(matrix);
+        canvas.drawImage(skiaBitmap->GetSkImage(), 0, 0, SkSamplingOptions(), 
&paint);
+    }
+    else
+    {
+        AlphaMask alpha(bitmapEx.GetAlpha());
+        Bitmap alphaBitmap(alpha.GetBitmap());
+        
assert(dynamic_cast<SkiaSalBitmap*>(alphaBitmap.ImplGetSalBitmap().get()) != 
nullptr);
+        SkiaSalBitmap* skiaAlpha
+            = 
static_cast<SkiaSalBitmap*>(alphaBitmap.ImplGetSalBitmap().get());
+        paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut,
+                                         
skiaBitmap->GetSkShader(SkSamplingOptions()),
+                                         
skiaAlpha->GetAlphaSkShader(SkSamplingOptions())));
+        SkCanvas canvas(targetBitmap);
+        canvas.concat(matrix);
+        canvas.drawPaint(paint);
+    }
+
+    CGContextRef context = CGBitmapContextCreate(
+        targetBitmap.getAddr32(0, 0), targetBitmap.width(), 
targetBitmap.height(), 8,
+        targetBitmap.rowBytes(), GetSalData()->mxRGBSpace, 
kCGImageAlphaPremultipliedLast);
+    if (!context)
+        return nullptr;
+    CGImageRef screenImage = CGBitmapContextCreateImage(context);
+    CFRelease(context);
+    return screenImage;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 55422ec895d3014ba0507757870ebdec9ac1a2a9
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Tue Aug 17 13:10:36 2021 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Aug 23 15:00:30 2021 +0200

    implement text rendering on Mac using Skia
    
    There may be still small problems (CJK needs checking), but this is
    already usable.
    
    Change-Id: Ic9381c22ca55d9e6320152ffebeae740fd90f796
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120810
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 6cedf6f09b29..80b79a6ec720 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -123,6 +123,8 @@ public:
     void    AnnounceFonts( PhysicalFontCollection& ) const;
     CoreTextFontFace* GetFontDataFromId( sal_IntPtr nFontId ) const;
 
+    CTFontCollectionRef fontCollection() { return mpCTFontCollection; }
+
 private:
     CTFontCollectionRef mpCTFontCollection;
     CFArrayRef mpCTFontArray;
@@ -170,6 +172,10 @@ struct AquaSharedAttributes
     int mnXorMode; // 0: off 1: on 2: invert only
     int mnBitmapDepth;  // zero unless bitmap
 
+    Color maTextColor;
+    /// allows text to be rendered without antialiasing
+    bool mbNonAntialiasedText;
+
     std::unique_ptr<XorEmulation> mpXorEmulation;
 
     AquaSharedAttributes()
@@ -188,6 +194,8 @@ struct AquaSharedAttributes
         , mnHeight(0)
         , mnXorMode(0)
         , mnBitmapDepth(0)
+        , maTextColor( COL_BLACK )
+        , mbNonAntialiasedText( false )
     {}
 
     void unsetClipPath()
@@ -287,6 +295,7 @@ public:
                                    const tools::Rectangle &rControlRegion,
                                    ControlState nState,
                                    const ImplControlValue &aValue) = 0;
+    virtual void drawTextLayout(const GenericSalLayout& layout) = 0;
 protected:
     static bool performDrawNativeControl(ControlType nType,
                                          ControlPart nPart,
@@ -433,6 +442,8 @@ public:
                                    ControlState nState,
                                    const ImplControlValue &aValue) override;
 
+    virtual void drawTextLayout(const GenericSalLayout& layout) override;
+
     bool supportsOperation(OutDevSupportType eType) const override;
 };
 
@@ -447,9 +458,6 @@ class AquaSalGraphics : public SalGraphicsAutoDelegateToImpl
 
     // Device Font settings
     rtl::Reference<CoreTextStyle>           mpTextStyle[MAX_FALLBACK];
-    RGBAColor                               maTextColor;
-    /// allows text to be rendered without antialiasing
-    bool                                    mbNonAntialiasedText;
 
 public:
                             AquaSalGraphics();
diff --git a/vcl/inc/skia/osx/gdiimpl.hxx b/vcl/inc/skia/osx/gdiimpl.hxx
index e42126cfae46..cc291bd38764 100644
--- a/vcl/inc/skia/osx/gdiimpl.hxx
+++ b/vcl/inc/skia/osx/gdiimpl.hxx
@@ -17,6 +17,8 @@
 #include <skia/gdiimpl.hxx>
 #include <skia/utils.hxx>
 
+#include <SkFontMgr.h>
+
 class VCL_PLUGIN_PUBLIC AquaSkiaSalGraphicsImpl final : public 
SkiaSalGraphicsImpl,
                                                         public 
AquaGraphicsBackendBase
 {
@@ -38,11 +40,14 @@ public:
                                    const tools::Rectangle& rControlRegion, 
ControlState nState,
                                    const ImplControlValue& aValue) override;
 
+    virtual void drawTextLayout(const GenericSalLayout& layout) override;
+
 private:
     virtual void createWindowContext(bool forceRaster = false) override;
     virtual void performFlush() override;
     void flushToScreen(const SkIRect& rect);
     friend std::unique_ptr<sk_app::WindowContext> 
createVulkanWindowContext(bool);
+    static inline sk_sp<SkFontMgr> fontManager;
 };
 
 #endif // INCLUDED_VCL_INC_SKIA_OSX_GDIIMPL_HXX
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index 1fa3d425a6d4..53b10ab9533c 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -194,8 +194,6 @@ bool 
CoreTextFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilit
 AquaSalGraphics::AquaSalGraphics()
     : mnRealDPIX( 0 )
     , mnRealDPIY( 0 )
-    , maTextColor( COL_BLACK )
-    , mbNonAntialiasedText( false )
 {
     SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this 
);
 
@@ -250,8 +248,8 @@ SalGraphicsImpl* AquaSalGraphics::GetImpl() const
 
 void AquaSalGraphics::SetTextColor( Color nColor )
 {
-    maTextColor = RGBAColor( nColor );
-    // SAL_ DEBUG(std::hex << nColor << std::dec << "={" << 
maTextColor.GetRed() << ", " << maTextColor.GetGreen() << ", " << 
maTextColor.GetBlue() << ", " << maTextColor.GetAlpha() << "}");
+    maShared.maTextColor = nColor;
+    // SAL_ DEBUG(std::hex << nColor << std::dec << "={" << 
maShared.maTextColor.GetRed() << ", " << maShared.maTextColor.GetGreen() << ", 
" << maShared.maTextColor.GetBlue() << ", " << maShared.maTextColor.GetAlpha() 
<< "}");
 }
 
 void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int 
nFallbackLevel)
@@ -361,9 +359,14 @@ bool AquaSalGraphics::AddTempDevFont( 
PhysicalFontCollection*,
 }
 
 void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
+{
+    mpBackend->drawTextLayout(rLayout);
+}
+
+void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout)
 {
 #ifdef IOS
-    if (!maShared.checkContext())
+    if (!mrShared.checkContext())
     {
         SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout() without 
context");
         return;
@@ -437,20 +440,21 @@ void AquaSalGraphics::DrawTextLayout(const 
GenericSalLayout& rLayout)
     std::cerr << "]\n";
 #endif
 
-    maShared.maContextHolder.saveState();
+    mrShared.maContextHolder.saveState();
+    RGBAColor textColor( mrShared.maTextColor );
 
     // The view is vertically flipped (no idea why), flip it back.
-    CGContextScaleCTM(maShared.maContextHolder.get(), 1.0, -1.0);
-    CGContextSetShouldAntialias(maShared.maContextHolder.get(), 
!mbNonAntialiasedText);
-    CGContextSetFillColor(maShared.maContextHolder.get(), 
maTextColor.AsArray());
+    CGContextScaleCTM(mrShared.maContextHolder.get(), 1.0, -1.0);
+    CGContextSetShouldAntialias(mrShared.maContextHolder.get(), 
!mrShared.mbNonAntialiasedText);
+    CGContextSetFillColor(mrShared.maContextHolder.get(), textColor.AsArray());
 
     if (rStyle.mbFauxBold)
     {
 
         float fSize = rFontSelect.mnHeight / 23.0f;
-        CGContextSetStrokeColor(maShared.maContextHolder.get(), 
maTextColor.AsArray());
-        CGContextSetLineWidth(maShared.maContextHolder.get(), fSize);
-        CGContextSetTextDrawingMode(maShared.maContextHolder.get(), 
kCGTextFillStroke);
+        CGContextSetStrokeColor(mrShared.maContextHolder.get(), 
textColor.AsArray());
+        CGContextSetLineWidth(mrShared.maContextHolder.get(), fSize);
+        CGContextSetTextDrawingMode(mrShared.maContextHolder.get(), 
kCGTextFillStroke);
     }
 
     auto aIt = aGlyphOrientation.cbegin();
@@ -463,18 +467,18 @@ void AquaSalGraphics::DrawTextLayout(const 
GenericSalLayout& rLayout)
         size_t nStartIndex = std::distance(aGlyphOrientation.cbegin(), aIt);
         size_t nLen = std::distance(aIt, aNext);
 
-        maShared.maContextHolder.saveState();
+        mrShared.maContextHolder.saveState();
         if (rStyle.mfFontRotation && !bUprightGlyph)
         {
-            CGContextRotateCTM(maShared.maContextHolder.get(), 
rStyle.mfFontRotation);
+            CGContextRotateCTM(mrShared.maContextHolder.get(), 
rStyle.mfFontRotation);
         }
-        CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], 
&aGlyphPos[nStartIndex], nLen, maShared.maContextHolder.get());
-        maShared.maContextHolder.restoreState();
+        CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], 
&aGlyphPos[nStartIndex], nLen, mrShared.maContextHolder.get());
+        mrShared.maContextHolder.restoreState();
 
         aIt = aNext;
     }
 
-    maShared.maContextHolder.restoreState();
+    mrShared.maContextHolder.restoreState();
 }
 
 void AquaSalGraphics::SetFont(LogicalFontInstance* pReqFont, int 
nFallbackLevel)
diff --git a/vcl/skia/osx/gdiimpl.cxx b/vcl/skia/osx/gdiimpl.cxx
index c5e8911d339e..8a879e2f7788 100644
--- a/vcl/skia/osx/gdiimpl.cxx
+++ b/vcl/skia/osx/gdiimpl.cxx
@@ -23,7 +23,12 @@
 
 #include <skia/osx/rastercontext.hxx>
 
+#include <quartz/ctfonts.hxx>
+
 #include <SkCanvas.h>
+#include <SkFont.h>
+#include <SkFontMgr_mac_ct.h>
+#include <SkTypeface_mac.h>
 
 using namespace SkiaHelper;
 
@@ -173,6 +178,52 @@ bool 
AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n
     return bOK;
 }
 
+void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout)
+{
+    const CoreTextStyle& rStyle = *static_cast<const 
CoreTextStyle*>(&rLayout.GetFont());
+    const FontSelectPattern& rFontSelect = rStyle.GetFontSelectPattern();
+    int nHeight = rFontSelect.mnHeight;
+    int nWidth = rFontSelect.mnWidth ? rFontSelect.mnWidth : nHeight;
+    if (nWidth == 0 || nHeight == 0)
+    {
+        SAL_WARN("vcl.skia", "DrawTextLayout(): rFontSelect.mnHeight is 
zero!?");
+        return;
+    }
+
+    if (!fontManager)
+    {
+        SystemFontList* fontList = GetCoretextFontList();
+        if (fontList == nullptr)
+        {
+            SAL_WARN("vcl.skia", "DrawTextLayout(): No coretext font list");
+            fontManager = SkFontMgr_New_CoreText(nullptr);
+        }
+        else
+        {
+            fontManager = SkFontMgr_New_CoreText(fontList->fontCollection());
+        }
+    }
+
+    CTFontRef pFont
+        = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), 
kCTFontAttributeName));
+    sk_sp<SkTypeface> typeface = SkMakeTypefaceFromCTFont(pFont);
+    SkFont font(typeface);
+    font.setSize(nHeight);
+    //    font.setScaleX(rStyle.mfFontStretch); TODO
+    if (rStyle.mbFauxBold)
+        font.setEmbolden(true);
+    font.setEdging(!mrShared.mbNonAntialiasedText ? SkFont::Edging::kAntiAlias
+                                                  : SkFont::Edging::kAlias);
+
+    // Vertical font, use width as "height".
+    SkFont verticalFont(font);
+    verticalFont.setSize(nHeight);
+    //    verticalFont.setSize(nWidth); TODO
+    //    verticalFont.setScaleX(1.0 * nHeight / nWidth);
+
+    drawGenericLayout(rLayout, mrShared.maTextColor, font, verticalFont);
+}
+
 std::unique_ptr<sk_app::WindowContext> createVulkanWindowContext(bool 
/*temporary*/)
 {
     return nullptr;

Reply via email to