summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Luby <plubius@neooffice.org>2022-12-10 14:16:39 -0500
committerCaolán McNamara <caolanm@redhat.com>2022-12-11 20:02:53 +0000
commit9eb732a32023e74c44ac8c3b5af9f5424273bb6c (patch)
tree3b40f9d61aae45470f07c489f7089cbfcb704ab1
parentd7f969a133d4eb8258b5d90ed88532cfcdbc9b28 (diff)
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 <caolanm@redhat.com>
-rw-r--r--vcl/inc/quartz/salbmp.h6
-rw-r--r--vcl/osx/salinst.cxx6
-rw-r--r--vcl/quartz/AquaGraphicsBackend.cxx139
-rw-r--r--vcl/quartz/salbmp.cxx60
4 files changed, 210 insertions, 1 deletions
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*/ )
{