vcl/inc/quartz/salbmp.h            |    6 +
 vcl/osx/salinst.cxx                |    6 +
 vcl/quartz/AquaGraphicsBackend.cxx |  139 +++++++++++++++++++++++++++++++++++++
 vcl/quartz/salbmp.cxx              |   60 +++++++++++++++
 4 files changed, 210 insertions(+), 1 deletion(-)

New commits:
commit 9eb732a32023e74c44ac8c3b5af9f5424273bb6c
Author:     Patrick Luby <plub...@neooffice.org>
AuthorDate: Sat Dec 10 14:16:39 2022 -0500
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Sun Dec 11 20:02:53 2022 +0000

    Related: tdf#146842 Convert SkiaSalBitmap to QuartzSalBitmap
    
    Commit de3f13e2175564316eb5a62dee65e9ff8f31b460 disabled Skia for printing.
    However, since all SalBitmaps created are either all QuartzSalBitmaps or all
    SkiaSalBitmaps, a crash occurs whenever a SkiaSalBitmap is passed to a
    printer's SalGraphics instance which is now always non-Skia.
    
    Change-Id: I7c1b0e1a9993e21db18ba5695a106cb10cc4088a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143939
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/inc/quartz/salbmp.h b/vcl/inc/quartz/salbmp.h
index 8a9e94d043cc..459a2b528f99 100644
--- a/vcl/inc/quartz/salbmp.h
+++ b/vcl/inc/quartz/salbmp.h
@@ -30,6 +30,9 @@
 #include <salinst.hxx>
 #include <salvd.hxx>
 #include <salbmp.hxx>
+#if HAVE_FEATURE_SKIA
+#include <skia/salbmp.hxx>
+#endif
 
 #include <memory>
 
@@ -61,6 +64,9 @@ public:
     bool            Create( const SalBitmap& rSalBmp ) override;
     bool            Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) 
override;
     bool            Create( const SalBitmap& rSalBmp, vcl::PixelFormat 
eNewPixelFormat) override;
+#if HAVE_FEATURE_SKIA
+    bool            Create( const SkiaSalBitmap& rSkiaSalBmp, const 
SalTwoRect& rPosAry );
+#endif
     virtual bool    Create( const css::uno::Reference< 
css::rendering::XBitmapCanvas >& rBitmapCanvas,
                             Size& rSize,
                             bool bMask = false ) override;
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index e7f202ae7ae5..22a024bc265d 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -524,7 +524,11 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* 
pEvent )
 bool AquaSalInstance::RunInMainYield( bool bHandleAllCurrentEvents )
 {
     OSX_SALDATA_RUNINMAIN_UNION( DoYield( false, bHandleAllCurrentEvents), 
boolean )
-    assert( false && "Don't call this from the main thread!" );
+
+    // PrinterController::removeTransparencies() calls this frequently on the
+    // main thread so reduce the severity from an assert so that printing still
+    // works in a debug builds
+    SAL_WARN_IF( true, "vcl", "Don't call this from the main thread!" );
     return false;
 
 }
diff --git a/vcl/quartz/AquaGraphicsBackend.cxx 
b/vcl/quartz/AquaGraphicsBackend.cxx
index 987ce5b784a5..7482986dd58a 100644
--- a/vcl/quartz/AquaGraphicsBackend.cxx
+++ b/vcl/quartz/AquaGraphicsBackend.cxx
@@ -44,6 +44,11 @@
 #include <svdata.hxx>
 #endif
 
+#if HAVE_FEATURE_SKIA
+#include <vcl/skia/SkiaHelper.hxx>
+#include <skia/salbmp.hxx>
+#endif
+
 using namespace vcl;
 
 namespace
@@ -187,6 +192,48 @@ void drawPattern50(void*, CGContextRef rContext)
     CGContextAddRects(rContext, aRects, 2);
     CGContextFillPath(rContext);
 }
+
+#if HAVE_FEATURE_SKIA
+
+// Related: tdf#146842 Convert SkiaSalBitmap to QuartzSalBitmap
+// Commit de3f13e2175564316eb5a62dee65e9ff8f31b460 disabled Skia for printing.
+// However, since all SalBitmaps created are either all QuartzSalBitmaps or all
+// SkiaSalBitmaps, a crash occurs whenever a SkiaSalBitmap is passed to a
+// printer's SalGraphics instance which is now always non-Skia.
+QuartzSalBitmap* checkAndConvertToQuartzSalBitmap(const SalTwoRect& rPosAry,
+                                                  const SalBitmap& rSalBitmap,
+                                                  SalTwoRect* 
pAdjustedSrcPosAry)
+{
+    QuartzSalBitmap* pRet = nullptr;
+
+    if (SkiaHelper::isVCLSkiaEnabled() && dynamic_cast<const 
SkiaSalBitmap*>(&rSalBitmap))
+    {
+        const SkiaSalBitmap& rSkiaBitmap = static_cast<const 
SkiaSalBitmap&>(rSalBitmap);
+
+        SalTwoRect aSrcPosAry(rPosAry);
+        aSrcPosAry.mnDestX = 0;
+        aSrcPosAry.mnDestY = 0;
+
+        pRet = new QuartzSalBitmap;
+        if (pRet)
+        {
+            // Ignore any failures as returning a nullptr will lead to a crash
+            pRet->Create(rSkiaBitmap, aSrcPosAry);
+
+            if (pAdjustedSrcPosAry)
+            {
+                pAdjustedSrcPosAry->mnSrcX = 0;
+                pAdjustedSrcPosAry->mnSrcY = 0;
+                pAdjustedSrcPosAry->mnSrcWidth = aSrcPosAry.mnDestWidth;
+                pAdjustedSrcPosAry->mnSrcHeight = aSrcPosAry.mnDestHeight;
+            }
+        }
+    }
+
+    return pRet;
+}
+
+#endif
 }
 
 AquaGraphicsBackend::AquaGraphicsBackend(AquaSharedAttributes& rShared)
@@ -904,6 +951,21 @@ void AquaGraphicsBackend::drawBitmap(const SalTwoRect& 
rPosAry, const SalBitmap&
     if (!mrShared.checkContext())
         return;
 
+#if HAVE_FEATURE_SKIA
+    if (mrShared.mbPrinter)
+    {
+        SAL_INFO("vcl.print", "Printing with Skia bitmaps: 
AquaGraphicsBackend::drawBitmap");
+        SalTwoRect aDestPosAry(rPosAry);
+        std::unique_ptr<QuartzSalBitmap> pSalBitmap(
+            checkAndConvertToQuartzSalBitmap(rPosAry, rSalBitmap, 
&aDestPosAry));
+        if (pSalBitmap)
+        {
+            drawBitmap(aDestPosAry, *pSalBitmap);
+            return;
+        }
+    }
+#endif
+
     const QuartzSalBitmap& rBitmap = static_cast<const 
QuartzSalBitmap&>(rSalBitmap);
     CGImageRef xImage = rBitmap.CreateCroppedImage(
         static_cast<int>(rPosAry.mnSrcX), static_cast<int>(rPosAry.mnSrcY),
@@ -925,6 +987,31 @@ void AquaGraphicsBackend::drawBitmap(const SalTwoRect& 
rPosAry, const SalBitmap&
     if (!mrShared.checkContext())
         return;
 
+#if HAVE_FEATURE_SKIA
+    if (mrShared.mbPrinter)
+    {
+        SAL_INFO(
+            "vcl.print",
+            "Printing with Skia bitmaps: 
AquaGraphicsBackend::drawBitmapWithTranspraentBitmap");
+        SalTwoRect aDestPosAry(rPosAry);
+        std::unique_ptr<QuartzSalBitmap> pSalBitmap(
+            checkAndConvertToQuartzSalBitmap(rPosAry, rSalBitmap, 
&aDestPosAry));
+        if (pSalBitmap)
+        {
+            drawBitmap(aDestPosAry, *pSalBitmap, rTransparentBitmap);
+            return;
+        }
+
+        pSalBitmap.reset(
+            checkAndConvertToQuartzSalBitmap(rPosAry, rTransparentBitmap, 
&aDestPosAry));
+        if (pSalBitmap)
+        {
+            drawBitmap(aDestPosAry, rSalBitmap, *pSalBitmap);
+            return;
+        }
+    }
+#endif
+
     const QuartzSalBitmap& rBitmap = static_cast<const 
QuartzSalBitmap&>(rSalBitmap);
     const QuartzSalBitmap& rMask = static_cast<const 
QuartzSalBitmap&>(rTransparentBitmap);
 
@@ -946,6 +1033,21 @@ void AquaGraphicsBackend::drawMask(const SalTwoRect& 
rPosAry, const SalBitmap& r
     if (!mrShared.checkContext())
         return;
 
+#if HAVE_FEATURE_SKIA
+    if (mrShared.mbPrinter)
+    {
+        SAL_INFO("vcl.print", "Printing with Skia bitmaps: 
AquaGraphicsBackend::drawMask");
+        SalTwoRect aDestPosAry(rPosAry);
+        std::unique_ptr<QuartzSalBitmap> pSalBitmap(
+            checkAndConvertToQuartzSalBitmap(rPosAry, rSalBitmap, 
&aDestPosAry));
+        if (pSalBitmap)
+        {
+            drawMask(aDestPosAry, *pSalBitmap, nMaskColor);
+            return;
+        }
+    }
+#endif
+
     const QuartzSalBitmap& rBitmap = static_cast<const 
QuartzSalBitmap&>(rSalBitmap);
     CGImageRef xImage = rBitmap.CreateColorMask(rPosAry.mnSrcX, 
rPosAry.mnSrcY, rPosAry.mnSrcWidth,
                                                 rPosAry.mnSrcHeight, 
nMaskColor);
@@ -1224,6 +1326,25 @@ bool AquaGraphicsBackend::drawAlphaBitmap(const 
SalTwoRect& rTR, const SalBitmap
     if (rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0)
         return false;
 
+#if HAVE_FEATURE_SKIA
+    if (!mrShared.checkContext())
+        return false;
+
+    if (mrShared.mbPrinter)
+    {
+        SAL_INFO("vcl.print", "Printing with Skia bitmaps: 
AquaGraphicsBackend::drawAlphaBitmap");
+        SalTwoRect aDestPosAry(rTR);
+        std::unique_ptr<QuartzSalBitmap> pSalBitmap(
+            checkAndConvertToQuartzSalBitmap(rTR, rSrcBitmap, &aDestPosAry));
+        if (pSalBitmap)
+            return drawAlphaBitmap(aDestPosAry, *pSalBitmap, rAlphaBmp);
+
+        pSalBitmap.reset(checkAndConvertToQuartzSalBitmap(rTR, rAlphaBmp, 
&aDestPosAry));
+        if (pSalBitmap)
+            return drawAlphaBitmap(aDestPosAry, rSrcBitmap, *pSalBitmap);
+    }
+#endif
+
     const QuartzSalBitmap& rSrcSalBmp = static_cast<const 
QuartzSalBitmap&>(rSrcBitmap);
     const QuartzSalBitmap& rMaskSalBmp = static_cast<const 
QuartzSalBitmap&>(rAlphaBmp);
     CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask(rMaskSalBmp, 
rTR.mnSrcX, rTR.mnSrcY,
@@ -1256,6 +1377,24 @@ bool AquaGraphicsBackend::drawTransformedBitmap(const 
basegfx::B2DPoint& rNull,
     if (fAlpha != 1.0)
         return false;
 
+#if HAVE_FEATURE_SKIA
+    if (mrShared.mbPrinter)
+    {
+        SAL_INFO("vcl.print",
+                 "Printing with Skia bitmaps: 
AquaGraphicsBackend::drawTransformedBitmap");
+        const Size aSize = rSrcBitmap.GetSize();
+        SalTwoRect aTR(0, 0, aSize.Width(), aSize.Height(), 0, 0, 
aSize.Width(), aSize.Height());
+        std::unique_ptr<QuartzSalBitmap> pSalBitmap(
+            checkAndConvertToQuartzSalBitmap(aTR, rSrcBitmap, nullptr));
+        if (pSalBitmap)
+            return drawTransformedBitmap(rNull, rX, rY, *pSalBitmap, 
pAlphaBmp, fAlpha);
+
+        pSalBitmap.reset(checkAndConvertToQuartzSalBitmap(aTR, *pAlphaBmp, 
nullptr));
+        if (pSalBitmap)
+            return drawTransformedBitmap(rNull, rX, rY, rSrcBitmap, 
pSalBitmap.get(), fAlpha);
+    }
+#endif
+
     // get the Quartz image
     CGImageRef xImage = nullptr;
     const Size aSize = rSrcBitmap.GetSize();
diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx
index cdc405ad362c..cd191482f5aa 100644
--- a/vcl/quartz/salbmp.cxx
+++ b/vcl/quartz/salbmp.cxx
@@ -115,6 +115,66 @@ bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp, 
vcl::PixelFormat eNewPix
     return false;
 }
 
+#if HAVE_FEATURE_SKIA
+
+bool QuartzSalBitmap::Create( const SkiaSalBitmap& rSalBmp, const SalTwoRect& 
rPosAry )
+{
+    bool bRet = false;
+
+    // Ugly but necessary to acquire the bitmap buffer because all of the
+    // SalBitmap instances that callers pass are already const. At least we
+    // only need to read, not write to the bitmap paramter.
+    SkiaSalBitmap& rSkiaSalBmp = const_cast<SkiaSalBitmap&>( rSalBmp );
+
+    BitmapBuffer *pSrcBuffer = rSkiaSalBmp.AcquireBuffer( 
BitmapAccessMode::Read );
+    if ( !pSrcBuffer )
+        return bRet;
+
+    if ( !pSrcBuffer->mpBits )
+    {
+        rSkiaSalBmp.ReleaseBuffer( pSrcBuffer, BitmapAccessMode::Read );
+        return bRet;
+    }
+
+    // Create only a 1 pixel buffer as it will always be discarded
+    mnBits = 32;
+    mnWidth = 1;
+    mnHeight = 1;
+    if( AllocateUserData() )
+    {
+        BitmapBuffer *pDestBuffer = AcquireBuffer( BitmapAccessMode::Read );
+        if ( pDestBuffer )
+        {
+            std::unique_ptr<BitmapBuffer> pConvertedBuffer = 
StretchAndConvert( *pSrcBuffer, rPosAry, pDestBuffer->mnFormat, 
pDestBuffer->maPalette, &pDestBuffer->maColorMask );
+            bool bUseDestBuffer = ( pConvertedBuffer &&
+                 pConvertedBuffer->mpBits &&
+                 pConvertedBuffer->mnFormat == pDestBuffer->mnFormat &&
+                 pConvertedBuffer->mnWidth == rPosAry.mnDestWidth &&
+                 pConvertedBuffer->mnHeight == rPosAry.mnDestHeight );
+
+            ReleaseBuffer( pDestBuffer, BitmapAccessMode::Read );
+
+            if ( bUseDestBuffer )
+            {
+                // Surprisingly, BitmapBuffer does not delete the bits so
+                // discard our 1 pixel buffer and take ownership of the bits
+                DestroyContext();
+                m_pUserBuffer.reset( pConvertedBuffer->mpBits );
+                mnWidth = pConvertedBuffer->mnWidth;
+                mnHeight = pConvertedBuffer->mnHeight;
+                mnBytesPerRow = pConvertedBuffer->mnScanlineSize;
+                bRet = true;
+            }
+        }
+    }
+
+    rSkiaSalBmp.ReleaseBuffer( pSrcBuffer, BitmapAccessMode::Read );
+
+    return bRet;
+}
+
+#endif
+
 bool QuartzSalBitmap::Create( const css::uno::Reference< 
css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/,
                               Size& /*rSize*/, bool /*bMask*/ )
 {

Reply via email to