summaryrefslogtreecommitdiffstats
path: root/vcl/ios/salios.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/ios/salios.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/ios/salios.cxx')
-rw-r--r--vcl/ios/salios.cxx584
1 files changed, 584 insertions, 0 deletions
diff --git a/vcl/ios/salios.cxx b/vcl/ios/salios.cxx
new file mode 100644
index 000000000..52e94b109
--- /dev/null
+++ b/vcl/ios/salios.cxx
@@ -0,0 +1,584 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// This file contains the iOS-specific versions of the functions which were touched in the commit to
+// fix tdf#138122. The functions are here (for now) as they were before that commit. The
+// macOS-specific versions of these functions are in vcl/osx/salmacos.cxx.
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <vcl/bitmap.hxx>
+
+#include <quartz/salbmp.h>
+#include <quartz/salgdi.h>
+#include <quartz/salvd.h>
+#include <quartz/utils.h>
+
+#include <svdata.hxx>
+
+// From salbmp.cxx
+
+bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits, int nX, int nY, int nWidth, int nHeight, bool bFlipped)
+{
+ SAL_WARN_IF(!rLayerHolder.isSet(), "vcl", "QuartzSalBitmap::Create() from non-layered context");
+
+ // sanitize input parameters
+ if( nX < 0 ) {
+ nWidth += nX;
+ nX = 0;
+ }
+
+ if( nY < 0 ) {
+ nHeight += nY;
+ nY = 0;
+ }
+
+ const CGSize aLayerSize = CGLayerGetSize(rLayerHolder.get());
+
+ if( nWidth >= static_cast<int>(aLayerSize.width) - nX )
+ nWidth = static_cast<int>(aLayerSize.width) - nX;
+
+ if( nHeight >= static_cast<int>(aLayerSize.height) - nY )
+ nHeight = static_cast<int>(aLayerSize.height) - nY;
+
+ if( (nWidth < 0) || (nHeight < 0) )
+ nWidth = nHeight = 0;
+
+ // initialize properties
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ mnBits = nBitmapBits ? nBitmapBits : 32;
+
+ // initialize drawing context
+ CreateContext();
+
+ // copy layer content into the bitmap buffer
+ const CGPoint aSrcPoint = { static_cast<CGFloat>(-nX), static_cast<CGFloat>(-nY) };
+ if (maGraphicContext.isSet()) // remove warning
+ {
+ if( bFlipped )
+ {
+ CGContextTranslateCTM( maGraphicContext.get(), 0, +mnHeight );
+
+ CGContextScaleCTM( maGraphicContext.get(), +1, -1 );
+ }
+
+ CGContextDrawLayerAtPoint(maGraphicContext.get(), aSrcPoint, rLayerHolder.get());
+ }
+ return true;
+}
+
+// From salgdicommon.cxx
+
+void AquaGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics *pSrcGraphics)
+{
+ //from unix salgdi2.cxx
+ //[FIXME] find a better way to prevent calc from crashing when width and height are negative
+ if( rPosAry.mnSrcWidth <= 0 ||
+ rPosAry.mnSrcHeight <= 0 ||
+ rPosAry.mnDestWidth <= 0 ||
+ rPosAry.mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ // If called from idle layout, maContextHolder.get() is NULL, no idea what to do
+ if (!mrShared.maContextHolder.isSet())
+ return;
+
+ AquaSharedAttributes* pSrcShared = nullptr;
+
+ if (pSrcGraphics)
+ {
+ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ pSrcShared = &pSrc->getAquaGraphicsBackend()->GetShared();
+ }
+ else
+ pSrcShared = &mrShared;
+
+ // accelerate trivial operations
+ const bool bSameGraphics = (pSrcShared == &mrShared);
+
+ if( bSameGraphics &&
+ (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
+ (rPosAry.mnSrcHeight == rPosAry.mnDestHeight))
+ {
+ // short circuit if there is nothing to do
+ if( (rPosAry.mnSrcX == rPosAry.mnDestX) &&
+ (rPosAry.mnSrcY == rPosAry.mnDestY))
+ {
+ return;
+ }
+ // use copyArea() if source and destination context are identical
+ copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY,
+ rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, false/*bWindowInvalidate*/ );
+ return;
+ }
+
+ mrShared.applyXorContext();
+ if (!bSameGraphics)
+ pSrcShared->applyXorContext();
+
+ SAL_WARN_IF (!pSrcShared->maLayer.isSet(), "vcl.quartz",
+ "AquaSalGraphics::copyBits() from non-layered graphics this=" << this);
+
+ const CGPoint aDstPoint = CGPointMake(+rPosAry.mnDestX - rPosAry.mnSrcX, rPosAry.mnDestY - rPosAry.mnSrcY);
+ if ((rPosAry.mnSrcWidth == rPosAry.mnDestWidth &&
+ rPosAry.mnSrcHeight == rPosAry.mnDestHeight) &&
+ (!mrShared.mnBitmapDepth || (aDstPoint.x + pSrcShared->mnWidth) <= mrShared.mnWidth)
+ && pSrcShared->maLayer.isSet()) // workaround for a Quartz crash
+ {
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // if source and target are identical then copyBits() paints onto the target context though
+ CGContextHolder aCopyContext = mrShared.maContextHolder;
+ if (mrShared.mpXorEmulation && mrShared.mpXorEmulation->IsEnabled())
+ {
+ if (bSameGraphics)
+ {
+ aCopyContext.set(mrShared.mpXorEmulation->GetTargetContext());
+ }
+ }
+ aCopyContext.saveState();
+
+ const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+ CGContextClipToRect(aCopyContext.get(), aDstRect);
+
+ // draw at new destination
+ // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down
+ if (pSrcShared->isFlipped())
+ {
+ CGContextTranslateCTM(aCopyContext.get(), 0, +mrShared.mnHeight);
+ CGContextScaleCTM(aCopyContext.get(), +1, -1);
+ }
+
+ // TODO: pSrc->size() != this->size()
+ CGContextDrawLayerAtPoint(aCopyContext.get(), aDstPoint, pSrcShared->maLayer.get());
+
+ aCopyContext.restoreState();
+ // mark the destination rectangle as updated
+ refreshRect(aDstRect);
+ }
+ else
+ {
+ std::shared_ptr<SalBitmap> pBitmap;
+ if (pSrcGraphics)
+ pBitmap = pSrcGraphics->GetImpl()->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
+ else
+ pBitmap = getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
+
+ if (pBitmap)
+ {
+ SalTwoRect aPosAry( rPosAry );
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ drawBitmap(aPosAry, *pBitmap);
+ }
+ }
+}
+
+void AquaGraphicsBackend::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
+ tools::Long nSrcWidth, tools::Long nSrcHeight, bool /*bWindowInvalidate*/)
+{
+ SAL_WARN_IF (!mrShared.maLayer.isSet(), "vcl.quartz",
+ "AquaSalGraphics::copyArea() for non-layered graphics this=" << this);
+
+ if (!mrShared.maLayer.isSet())
+ return;
+
+ float fScale = mrShared.maLayer.getScale();
+
+ tools::Long nScaledSourceX = nSrcX * fScale;
+ tools::Long nScaledSourceY = nSrcY * fScale;
+
+ tools::Long nScaledTargetX = nDstX * fScale;
+ tools::Long nScaledTargetY = nDstY * fScale;
+
+ tools::Long nScaledSourceWidth = nSrcWidth * fScale;
+ tools::Long nScaledSourceHeight = nSrcHeight * fScale;
+
+ mrShared.applyXorContext();
+
+ mrShared.maContextHolder.saveState();
+
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // copyArea() always works on the target context though
+ CGContextRef xCopyContext = mrShared.maContextHolder.get();
+
+ if (mrShared.mpXorEmulation && mrShared.mpXorEmulation->IsEnabled())
+ {
+ xCopyContext = mrShared.mpXorEmulation->GetTargetContext();
+ }
+
+ // If we have a scaled layer, we need to revert the scaling or else
+ // it will interfere with the coordinate calculation
+ CGContextScaleCTM(xCopyContext, 1.0 / fScale, 1.0 / fScale);
+
+ // drawing a layer onto its own context causes trouble on OSX => copy it first
+ // TODO: is it possible to get rid of this unneeded copy more often?
+ // e.g. on OSX>=10.5 only this situation causes problems:
+ // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth
+
+ CGLayerHolder sSourceLayerHolder(mrShared.maLayer);
+ {
+ const CGSize aSrcSize = CGSizeMake(nScaledSourceWidth, nScaledSourceHeight);
+ sSourceLayerHolder.set(CGLayerCreateWithContext(xCopyContext, aSrcSize, nullptr));
+
+ const CGContextRef xSrcContext = CGLayerGetContext(sSourceLayerHolder.get());
+
+ CGPoint aSrcPoint = CGPointMake(-nScaledSourceX, -nScaledSourceY);
+ if (mrShared.isFlipped())
+ {
+ CGContextTranslateCTM(xSrcContext, 0, +nScaledSourceHeight);
+ CGContextScaleCTM(xSrcContext, +1, -1);
+ aSrcPoint.y = (nScaledSourceY + nScaledSourceHeight) - (mrShared.mnHeight * fScale);
+ }
+ CGContextSetBlendMode(xSrcContext, kCGBlendModeCopy);
+
+ CGContextDrawLayerAtPoint(xSrcContext, aSrcPoint, mrShared.maLayer.get());
+ }
+
+ // draw at new destination
+ const CGRect aTargetRect = CGRectMake(nScaledTargetX, nScaledTargetY, nScaledSourceWidth, nScaledSourceHeight);
+ CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy);
+ CGContextDrawLayerInRect(xCopyContext, aTargetRect, sSourceLayerHolder.get());
+
+ mrShared.maContextHolder.restoreState();
+
+ // cleanup
+ if (sSourceLayerHolder.get() != mrShared.maLayer.get())
+ {
+ CGLayerRelease(sSourceLayerHolder.get());
+ }
+
+ // mark the destination rectangle as updated
+ mrShared.refreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight);
+}
+
+void AquaSalGraphics::SetVirDevGraphics(SalVirtualDevice* pVirDev, CGLayerHolder const & rLayer, CGContextRef xContext,
+ int nBitmapDepth)
+{
+ SAL_INFO( "vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext );
+
+ maShared.mbPrinter = false;
+ maShared.mbVirDev = true;
+
+ // set graphics properties
+ maShared.maLayer = rLayer;
+ maShared.maContextHolder.set(xContext);
+
+ maShared.mnBitmapDepth = nBitmapDepth;
+
+ maShared.mbForeignContext = xContext != NULL;
+
+ mpBackend->UpdateGeometryProvider(pVirDev);
+
+ // return early if the virdev is being destroyed
+ if (!xContext)
+ return;
+
+ // get new graphics properties
+ if (!maShared.maLayer.isSet())
+ {
+ maShared.mnWidth = CGBitmapContextGetWidth(maShared.maContextHolder.get());
+ maShared.mnHeight = CGBitmapContextGetHeight(maShared.maContextHolder.get());
+ }
+ else
+ {
+ const CGSize aSize = CGLayerGetSize(maShared.maLayer.get());
+ maShared.mnWidth = static_cast<int>(aSize.width);
+ maShared.mnHeight = static_cast<int>(aSize.height);
+ }
+
+ // prepare graphics for drawing
+ const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGContextSetFillColorSpace(maShared.maContextHolder.get(), aCGColorSpace);
+ CGContextSetStrokeColorSpace(maShared.maContextHolder.get(), aCGColorSpace);
+
+ // re-enable XorEmulation for the new context
+ if (maShared.mpXorEmulation)
+ {
+ maShared.mpXorEmulation->SetTarget(maShared.mnWidth, maShared.mnHeight, maShared.mnBitmapDepth, maShared.maContextHolder.get(), maShared.maLayer.get());
+ if (maShared.mpXorEmulation->IsEnabled())
+ {
+ maShared.maContextHolder.set(maShared.mpXorEmulation->GetMaskContext());
+ }
+ }
+
+ // initialize stack of CGContext states
+ maShared.maContextHolder.saveState();
+ maShared.setState();
+}
+
+void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
+ CGContextRef xTargetContext, CGLayerRef xTargetLayer )
+{
+ SAL_INFO( "vcl.quartz", "XorEmulation::SetTarget() this=" << this <<
+ " (" << nWidth << "x" << nHeight << ") depth=" << nTargetDepth <<
+ " context=" << xTargetContext << " layer=" << xTargetLayer );
+
+ // prepare to replace old mask+temp context
+ if( m_xMaskContext )
+ {
+ // cleanup the mask context
+ CGContextRelease( m_xMaskContext );
+ delete[] m_pMaskBuffer;
+ m_xMaskContext = nullptr;
+ m_pMaskBuffer = nullptr;
+
+ // cleanup the temp context if needed
+ if( m_xTempContext )
+ {
+ CGContextRelease( m_xTempContext );
+ delete[] m_pTempBuffer;
+ m_xTempContext = nullptr;
+ m_pTempBuffer = nullptr;
+ }
+ }
+
+ // return early if there is nothing more to do
+ if( !xTargetContext )
+ {
+ return;
+ }
+ // retarget drawing operations to the XOR mask
+ m_xTargetLayer = xTargetLayer;
+ m_xTargetContext = xTargetContext;
+
+ // prepare creation of matching CGBitmaps
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+ int nBitDepth = nTargetDepth;
+ if( !nBitDepth )
+ {
+ nBitDepth = 32;
+ }
+ int nBytesPerRow = 4;
+ const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
+ if( nBitDepth <= 8 )
+ {
+ aCGColorSpace = GetSalData()->mxGraySpace;
+ aCGBmpInfo = kCGImageAlphaNone;
+ nBytesPerRow = 1;
+ }
+ nBytesPerRow *= nWidth;
+ m_nBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong);
+
+ // create a XorMask context
+ m_pMaskBuffer = new sal_uLong[ m_nBufferLongs ];
+ m_xMaskContext = CGBitmapContextCreate( m_pMaskBuffer,
+ nWidth, nHeight,
+ nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ SAL_WARN_IF( !m_xMaskContext, "vcl.quartz", "mask context creation failed" );
+
+ // reset the XOR mask to black
+ memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
+
+ // a bitmap context will be needed for manual XORing
+ // create one unless the target context is a bitmap context
+ if( nTargetDepth )
+ {
+ m_pTempBuffer = static_cast<sal_uLong*>(CGBitmapContextGetData( m_xTargetContext ));
+ }
+ if( !m_pTempBuffer )
+ {
+ // create a bitmap context matching to the target context
+ m_pTempBuffer = new sal_uLong[ m_nBufferLongs ];
+ m_xTempContext = CGBitmapContextCreate( m_pTempBuffer,
+ nWidth, nHeight,
+ nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ SAL_WARN_IF( !m_xTempContext, "vcl.quartz", "temp context creation failed" );
+ }
+
+ // initialize XOR mask context for drawing
+ CGContextSetFillColorSpace( m_xMaskContext, aCGColorSpace );
+ CGContextSetStrokeColorSpace( m_xMaskContext, aCGColorSpace );
+ CGContextSetShouldAntialias( m_xMaskContext, false );
+
+ // improve the XorMask's XOR emulation a little
+ // NOTE: currently only enabled for monochrome contexts
+ if( aCGColorSpace == GetSalData()->mxGraySpace )
+ {
+ CGContextSetBlendMode( m_xMaskContext, kCGBlendModeDifference );
+ }
+ // initialize the transformation matrix to the drawing target
+ const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
+ CGContextConcatCTM( m_xMaskContext, aCTM );
+ if( m_xTempContext )
+ {
+ CGContextConcatCTM( m_xTempContext, aCTM );
+ }
+ // initialize the default XorMask graphics state
+ CGContextSaveGState( m_xMaskContext );
+}
+
+bool XorEmulation::UpdateTarget()
+{
+ SAL_INFO( "vcl.quartz", "XorEmulation::UpdateTarget() this=" << this );
+
+ if( !IsEnabled() )
+ {
+ return false;
+ }
+ // update the temp bitmap buffer if needed
+ if( m_xTempContext )
+ {
+ SAL_WARN_IF( m_xTargetContext == nullptr, "vcl.quartz", "Target layer is NULL");
+ CGContextDrawLayerAtPoint( m_xTempContext, CGPointZero, m_xTargetLayer );
+ }
+ // do a manual XOR with the XorMask
+ // this approach suffices for simple color manipulations
+ // and also the complex-clipping-XOR-trick used in metafiles
+ const sal_uLong* pSrc = m_pMaskBuffer;
+ sal_uLong* pDst = m_pTempBuffer;
+ for( int i = m_nBufferLongs; --i >= 0;)
+ {
+ *(pDst++) ^= *(pSrc++);
+ }
+ // write back the XOR results to the target context
+ if( m_xTempContext )
+ {
+ CGImageRef xXorImage = CGBitmapContextCreateImage( m_xTempContext );
+ const int nWidth = static_cast<int>(CGImageGetWidth( xXorImage ));
+ const int nHeight = static_cast<int>(CGImageGetHeight( xXorImage ));
+ // TODO: update minimal changerect
+ const CGRect aFullRect = CGRectMake(0, 0, nWidth, nHeight);
+ CGContextDrawImage( m_xTargetContext, aFullRect, xXorImage );
+ CGImageRelease( xXorImage );
+ }
+
+ // reset the XorMask to black again
+ // TODO: not needed for last update
+ memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
+
+ // TODO: return FALSE if target was not changed
+ return true;
+}
+
+/// From salvd.cxx
+
+void AquaSalVirtualDevice::Destroy()
+{
+ SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::Destroy() this=" << this << " mbForeignContext=" << mbForeignContext );
+
+ if( mbForeignContext )
+ {
+ // Do not delete mxContext that we have received from outside VCL
+ maLayer.set(nullptr);
+ return;
+ }
+
+ if (maLayer.isSet())
+ {
+ if( mpGraphics )
+ {
+ mpGraphics->SetVirDevGraphics(this, nullptr, nullptr);
+ }
+ CGLayerRelease(maLayer.get());
+ maLayer.set(nullptr);
+ }
+
+ if (maBitmapContext.isSet())
+ {
+ void* pRawData = CGBitmapContextGetData(maBitmapContext.get());
+ std::free(pRawData);
+ CGContextRelease(maBitmapContext.get());
+ maBitmapContext.set(nullptr);
+ }
+}
+
+bool AquaSalVirtualDevice::SetSize( tools::Long nDX, tools::Long nDY )
+{
+ SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this <<
+ " (" << nDX << "x" << nDY << ") mbForeignContext=" << (mbForeignContext ? "YES" : "NO"));
+
+ if( mbForeignContext )
+ {
+ // Do not delete/resize mxContext that we have received from outside VCL
+ return true;
+ }
+
+ if (maLayer.isSet())
+ {
+ const CGSize aSize = CGLayerGetSize(maLayer.get());
+ if( (nDX == aSize.width) && (nDY == aSize.height) )
+ {
+ // Yay, we do not have to do anything :)
+ return true;
+ }
+ }
+
+ Destroy();
+
+ mnWidth = nDX;
+ mnHeight = nDY;
+
+ // create a CGLayer matching to the intended virdev usage
+ CGContextHolder xCGContextHolder;
+ if( mnBitmapDepth && (mnBitmapDepth < 16) )
+ {
+ mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it?
+ const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8;
+
+ void* pRawData = std::malloc( nBytesPerRow * nDY );
+ maBitmapContext.set(CGBitmapContextCreate( pRawData, nDX, nDY,
+ mnBitmapDepth, nBytesPerRow,
+ GetSalData()->mxGraySpace, kCGImageAlphaNone));
+ xCGContextHolder = maBitmapContext;
+ }
+ else
+ {
+ if (!xCGContextHolder.isSet())
+ {
+ // assert(Application::IsBitmapRendering());
+ mnBitmapDepth = 32;
+
+ const int nBytesPerRow = (mnBitmapDepth * nDX) / 8;
+ void* pRawData = std::malloc( nBytesPerRow * nDY );
+ const int nFlags = kCGImageAlphaNoneSkipFirst | kCGImageByteOrder32Little;
+ maBitmapContext.set(CGBitmapContextCreate(pRawData, nDX, nDY, 8, nBytesPerRow,
+ GetSalData()->mxRGBSpace, nFlags));
+ xCGContextHolder = maBitmapContext;
+ }
+ }
+
+ SAL_WARN_IF(!xCGContextHolder.isSet(), "vcl.quartz", "No context");
+
+ const CGSize aNewSize = { static_cast<CGFloat>(nDX), static_cast<CGFloat>(nDY) };
+ maLayer.set(CGLayerCreateWithContext(xCGContextHolder.get(), aNewSize, nullptr));
+
+ if (maLayer.isSet() && mpGraphics)
+ {
+ // get the matching Quartz context
+ CGContextRef xDrawContext = CGLayerGetContext( maLayer.get() );
+
+ // Here we pass the CGLayerRef that the CGLayerHolder maLayer holds as the first parameter
+ // to SetVirDevGraphics(). That parameter is of type CGLayerHolder, so what we actually pass
+ // is an implicitly constructed *separate* CGLayerHolder. Is that what we want? No idea.
+ // Possibly we could pass just maLayer as such? But doing that does not fix tdf#138122.
+ mpGraphics->SetVirDevGraphics(this, maLayer.get(), xDrawContext, mnBitmapDepth);
+ }
+
+ return maLayer.isSet();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */