diff options
author | Tor Lillqvist <tml@collabora.com> | 2021-01-17 21:29:10 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2021-01-17 21:40:07 +0100 |
commit | e7ace1d043cc8bdf6c03097932a00cbbdc3cf557 (patch) | |
tree | dc9b8ef965dbe2f0752d9427a20ca606ab0b0f72 | |
parent | 058ad4b900b5e0ee902f3e89ed121c2b5f8c58f1 (diff) |
tdf#138122: Fix vcl for iOS after 1a167625314bf36b735176ed488e6ba9b5e9b675
Make vcl compile again for iOS and make the Collabora Office iOS app
work again when built against a master build of core.
For now, keep the old versions of the functions touched by
1a167625314bf36b735176ed488e6ba9b5e9b675 in vcl/ios/salios.cxx, and
move the modified versions to the new file vcl/osx/salmacos.cxx.
Keep the functions as they were except that ifdefs for MACOSX or IOS
are expanded. Keep the formatting as it was to make comparisons
easier. Thus add the new files to the clang-format exclusion list.
While at it, also move vcl/quartz/salgdiutils.cxx to vcl/osx as it is
compiled only for macOS anyway.
Change-Id: I990ef678f2263031d4a5af8cc547fffe185d17c4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109480
Tested-by: Jenkins
Reviewed-by: Tor Lillqvist <tml@collabora.com>
-rw-r--r-- | solenv/clang-format/excludelist | 4 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 1 | ||||
-rw-r--r-- | vcl/Library_vclplug_osx.mk | 3 | ||||
-rw-r--r-- | vcl/inc/quartz/salgdi.h | 14 | ||||
-rw-r--r-- | vcl/ios/salios.cxx | 443 | ||||
-rw-r--r-- | vcl/osx/salgdiutils.cxx (renamed from vcl/quartz/salgdiutils.cxx) | 0 | ||||
-rw-r--r-- | vcl/osx/salmacos.cxx | 387 | ||||
-rw-r--r-- | vcl/quartz/salbmp.cxx | 58 | ||||
-rw-r--r-- | vcl/quartz/salgdicommon.cxx | 181 | ||||
-rw-r--r-- | vcl/quartz/salvd.cxx | 104 |
10 files changed, 843 insertions, 352 deletions
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index 99a3d5089d75..bef00255118e 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -14779,6 +14779,7 @@ vcl/inc/window.h vcl/inc/wizdlg.hxx vcl/ios/dummies.cxx vcl/ios/iosinst.cxx +vcl/ios/salios.cxx vcl/null/printerinfomanager.cxx vcl/osx/DataFlavorMapping.cxx vcl/osx/DataFlavorMapping.hxx @@ -14804,7 +14805,9 @@ vcl/osx/documentfocuslistener.cxx vcl/osx/documentfocuslistener.hxx vcl/osx/saldata.cxx vcl/osx/salframe.cxx +vcl/osx/salgdiutils.cxx vcl/osx/salinst.cxx +vcl/osx/salmacos.cxx vcl/osx/salmenu.cxx vcl/osx/salnativewidgets.cxx vcl/osx/salobj.cxx @@ -14830,7 +14833,6 @@ vcl/quartz/ctfonts.cxx vcl/quartz/salbmp.cxx vcl/quartz/salgdi.cxx vcl/quartz/salgdicommon.cxx -vcl/quartz/salgdiutils.cxx vcl/quartz/salvd.cxx vcl/quartz/utils.cxx vcl/source/app/IconThemeInfo.cxx diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index d937fceb0a69..51b45594f97f 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -685,6 +685,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/ios/iosinst \ vcl/ios/dummies \ vcl/ios/clipboard \ + vcl/ios/salios \ vcl/ios/iOSTransferable \ vcl/ios/DataFlavorMapping \ vcl/ios/HtmlFmtFlt \ diff --git a/vcl/Library_vclplug_osx.mk b/vcl/Library_vclplug_osx.mk index f0d22298a0c8..9b82bd44c2a6 100644 --- a/vcl/Library_vclplug_osx.mk +++ b/vcl/Library_vclplug_osx.mk @@ -120,7 +120,9 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_osx,\ vcl/osx/documentfocuslistener \ vcl/osx/saldata \ vcl/osx/salframe \ + vcl/osx/salgdiutils \ vcl/osx/salinst \ + vcl/osx/salmacos \ vcl/osx/salmenu \ vcl/osx/salnativewidgets \ vcl/osx/salobj \ @@ -132,7 +134,6 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_osx,\ vcl/quartz/salbmp \ vcl/quartz/salgdi \ vcl/quartz/salgdicommon \ - vcl/quartz/salgdiutils \ vcl/quartz/salvd \ vcl/quartz/utils \ )) diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index eb3e7563c898..69b735787bdc 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -190,16 +190,16 @@ public: bool IsPenVisible() const { return maLineColor.IsVisible(); } bool IsBrushVisible() const { return maFillColor.IsVisible(); } - float GetWindowScaling(); - void SetWindowGraphics( AquaSalFrame* pFrame ); - void SetPrinterGraphics(CGContextRef, sal_Int32 nRealDPIX, sal_Int32 nRealDPIY); void SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRef, int nBitDepth = 0); #ifdef MACOSX void initResolution( NSWindow* ); void copyResolution( AquaSalGraphics& ); void updateResolution(); + float GetWindowScaling(); + void SetWindowGraphics( AquaSalFrame* pFrame ); bool IsWindowGraphics() const { return mbWindow; } + void SetPrinterGraphics(CGContextRef, sal_Int32 nRealDPIX, sal_Int32 nRealDPIY); AquaSalFrame* getGraphicsFrame() const { return mpFrame; } void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; } #endif @@ -300,14 +300,12 @@ public: virtual bool drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency ) override; +#ifdef MACOSX + protected: - virtual void copyScaledArea( tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, - tools::Long nSrcWidth, tools::Long nSrcHeight, SalGraphics* pSrcGraphics ); // native widget rendering methods that require mirroring -#ifdef MACOSX - virtual bool isNativeControlSupported( ControlType nType, ControlPart nPart ) override; virtual bool hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, @@ -319,6 +317,8 @@ protected: const ImplControlValue& aValue, const OUString& aCaption, tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override; + void copyScaledArea( tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, + tools::Long nSrcWidth, tools::Long nSrcHeight, SalGraphics* pSrcGraphics ); #endif public: diff --git a/vcl/ios/salios.cxx b/vcl/ios/salios.cxx new file mode 100644 index 000000000000..625fcb049a09 --- /dev/null +++ b/vcl/ios/salios.cxx @@ -0,0 +1,443 @@ +/* -*- 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 funtions 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 <cstddef> +#include <limits> + +#include <o3tl/make_shared.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <tools/color.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/BitmapAccessMode.hxx> +#include <vcl/BitmapBuffer.hxx> +#include <vcl/BitmapColor.hxx> +#include <vcl/BitmapPalette.hxx> +#include <vcl/ColorMask.hxx> +#include <vcl/Scanline.hxx> + +#include <bitmap/bmpfast.hxx> + +#include <headless/svpframe.hxx> +#include <headless/svpinst.hxx> +#include <headless/svpvd.hxx> + +#include <quartz/salbmp.h> +#include <quartz/salgdi.h> +#include <quartz/salvd.h> +#include <quartz/utils.h> + +#include "saldatabasic.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 AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGraphics ) +{ + + if( !pSrcGraphics ) + { + pSrcGraphics = this; + } + //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 (!maContextHolder.isSet()) + return; + + // accelerate trivial operations + /*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); + const bool bSameGraphics = (this == pSrc); + + 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; + } + + ApplyXorContext(); + pSrc->ApplyXorContext(); + + SAL_WARN_IF (!pSrc->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) && + (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) + && pSrc->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 = maContextHolder; + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + if( pSrcGraphics == this ) + { + aCopyContext.set(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( pSrc->IsFlipped() ) + { + CGContextTranslateCTM( aCopyContext.get(), 0, +mnHeight ); + CGContextScaleCTM( aCopyContext.get(), +1, -1 ); + } + + // TODO: pSrc->size() != this->size() + CGContextDrawLayerAtPoint(aCopyContext.get(), aDstPoint, pSrc->maLayer.get()); + + aCopyContext.restoreState(); + // mark the destination rectangle as updated + RefreshRect( aDstRect ); + } + else + { + std::shared_ptr<SalBitmap> pBitmap = pSrc->getBitmap( rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ); + if( pBitmap ) + { + SalTwoRect aPosAry( rPosAry ); + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + drawBitmap( aPosAry, *pBitmap ); + } + } +} + +void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY, + tools::Long nSrcWidth, tools::Long nSrcHeight, bool /*bWindowInvalidate*/) +{ + SAL_WARN_IF (!maLayer.isSet(), "vcl.quartz", + "AquaSalGraphics::copyArea() for non-layered graphics this=" << this); + + if (!maLayer.isSet()) + return; + + float fScale = 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; + + ApplyXorContext(); + + maContextHolder.saveState(); + + // in XOR mode the drawing context is redirected to the XOR mask + // copyArea() always works on the target context though + CGContextRef xCopyContext = maContextHolder.get(); + + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + xCopyContext = 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(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( IsFlipped() ) + { + CGContextTranslateCTM( xSrcContext, 0, +nScaledSourceHeight ); + CGContextScaleCTM( xSrcContext, +1, -1 ); + aSrcPoint.y = (nScaledSourceY + nScaledSourceHeight) - (mnHeight * fScale); + } + CGContextSetBlendMode(xSrcContext, kCGBlendModeCopy); + + CGContextDrawLayerAtPoint(xSrcContext, aSrcPoint, maLayer.get()); + } + + // draw at new destination + const CGRect aTargetRect = CGRectMake(nScaledTargetX, nScaledTargetY, nScaledSourceWidth, nScaledSourceHeight); + CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy); + CGContextDrawLayerInRect(xCopyContext, aTargetRect, sSourceLayerHolder.get()); + + maContextHolder.restoreState(); + + // cleanup + if (sSourceLayerHolder.get() != maLayer.get()) + { + CGLayerRelease(sSourceLayerHolder.get()); + } + // mark the destination rectangle as updated + RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight ); +} + +void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const & rLayer, CGContextRef xContext, + int nBitmapDepth) +{ + SAL_INFO( "vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext ); + + mbPrinter = false; + mbVirDev = true; + + // set graphics properties + maLayer = rLayer; + maContextHolder.set(xContext); + + mnBitmapDepth = nBitmapDepth; + + mbForeignContext = xContext != NULL; + + // return early if the virdev is being destroyed + if( !xContext ) + return; + + // get new graphics properties + if (!maLayer.isSet()) + { + mnWidth = CGBitmapContextGetWidth( maContextHolder.get() ); + mnHeight = CGBitmapContextGetHeight( maContextHolder.get() ); + } + else + { + const CGSize aSize = CGLayerGetSize(maLayer.get()); + mnWidth = static_cast<int>(aSize.width); + mnHeight = static_cast<int>(aSize.height); + } + + // prepare graphics for drawing + const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; + CGContextSetFillColorSpace( maContextHolder.get(), aCGColorSpace ); + CGContextSetStrokeColorSpace( maContextHolder.get(), aCGColorSpace ); + + // re-enable XorEmulation for the new context + if( mpXorEmulation ) + { + mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); + if( mpXorEmulation->IsEnabled() ) + { + maContextHolder.set(mpXorEmulation->GetMaskContext()); + } + } + + // initialize stack of CGContext states + maContextHolder.saveState(); + SetState(); +} + +/// 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(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(maLayer.get(), xDrawContext, mnBitmapDepth); + } + + return maLayer.isSet(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdiutils.cxx b/vcl/osx/salgdiutils.cxx index 01626d348999..01626d348999 100644 --- a/vcl/quartz/salgdiutils.cxx +++ b/vcl/osx/salgdiutils.cxx diff --git a/vcl/osx/salmacos.cxx b/vcl/osx/salmacos.cxx new file mode 100644 index 000000000000..7d4569d65bca --- /dev/null +++ b/vcl/osx/salmacos.cxx @@ -0,0 +1,387 @@ +/* -*- 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 macOS-specific versions of the functions which were touched in the commit +// to fix tdf#138122. The iOS-specific versions of these functions are kept (for now, when this +// comment is written) as they were before that commit in vcl/isx/salios.cxx. + +#include <sal/config.h> +#include <sal/log.hxx> +#include <osl/diagnose.h> + +#include <cstddef> +#include <limits> + +#include <o3tl/make_shared.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <tools/color.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/BitmapAccessMode.hxx> +#include <vcl/BitmapBuffer.hxx> +#include <vcl/BitmapColor.hxx> +#include <vcl/BitmapPalette.hxx> +#include <vcl/ColorMask.hxx> +#include <vcl/Scanline.hxx> + +#include <bitmap/bmpfast.hxx> + +#include <quartz/salbmp.h> +#include <quartz/salgdi.h> +#include <quartz/salvd.h> +#include <quartz/utils.h> + +#include <osx/saldata.hxx> +#include <osx/salframe.h> +#include <osx/salinst.h> + +// From salbmp.cxx + +bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits, int nX, int nY, int nWidth, int nHeight, bool bFlipped) +{ + + // TODO: Bitmaps from scaled layers are reverted to single precision. This is a workaround only unless bitmaps with precision of + // source layer are implemented. + + 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; + } + + CGSize aLayerSize = CGLayerGetSize(rLayerHolder.get()); + const float fScale = rLayerHolder.getScale(); + aLayerSize.width /= fScale; + aLayerSize.height /= fScale; + + 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 * fScale), static_cast<CGFloat>(-nY * fScale) }; + if (maGraphicContext.isSet()) + { + if( bFlipped ) + { + CGContextTranslateCTM(maGraphicContext.get(), 0, +mnHeight); + CGContextScaleCTM(maGraphicContext.get(), +1, -1); + } + maGraphicContext.saveState(); + CGContextScaleCTM(maGraphicContext.get(), 1 / fScale, 1 / fScale); + CGContextDrawLayerAtPoint(maGraphicContext.get(), aSrcPoint, rLayerHolder.get()); + maGraphicContext.restoreState(); + } + return true; +} + +// From salgdicommon.cxx + +void AquaSalGraphics::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcGraphics) +{ + if (!pSrcGraphics) + pSrcGraphics = this; + AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 || rPosAry.mnDestHeight <= 0) + return; + if (!maContextHolder.isSet()) + return; + + SAL_WARN_IF (!pSrc->maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::copyBits() from non-layered graphics this=" << this); + + // Layered graphics are copied by AquaSalGraphics::copyScaledArea() which is able to consider the layer's scaling. + + if (pSrc->maLayer.isSet()) + copyScaledArea(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, pSrcGraphics); + else + { + ApplyXorContext(); + pSrc->ApplyXorContext(); + std::shared_ptr<SalBitmap> pBitmap = pSrc->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + if (pBitmap) + { + SalTwoRect aPosAry(rPosAry); + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + drawBitmap(aPosAry, *pBitmap); + } + } +} + +void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY, + tools::Long nSrcWidth, tools::Long nSrcHeight, bool) +{ + if (!maContextHolder.isSet()) + return; + + // Functionality is implemented in protected member function AquaSalGraphics::copyScaledArea() which requires an additional + // parameter of type SalGraphics to be used in AquaSalGraphics::copyBits() too. + + copyScaledArea(nDstX, nDstY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, this); +} + +void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY, + tools::Long nSrcWidth, tools::Long nSrcHeight, SalGraphics *pSrcGraphics) +{ + if (!pSrcGraphics) + pSrcGraphics = this; + AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); + + SAL_WARN_IF(!maLayer.isSet(), "vcl.quartz", + "AquaSalGraphics::copyScaledArea() without graphics context or for non-layered graphics this=" << this); + + if (!maContextHolder.isSet() || !maLayer.isSet()) + return; + + // Determine scaled geometry of source and target area assuming source and target area have the same scale + + float fScale = maLayer.getScale(); + CGFloat nScaledSourceX = nSrcX * fScale; + CGFloat nScaledSourceY = nSrcY * fScale; + CGFloat nScaledTargetX = nDstX * fScale; + CGFloat nScaledTargetY = nDstY * fScale; + CGFloat nScaledSourceWidth = nSrcWidth * fScale; + CGFloat nScaledSourceHeight = nSrcHeight * fScale; + + // Apply XOR context and get copy context from current graphics context or XOR context + + ApplyXorContext(); + maContextHolder.saveState(); + CGContextRef xCopyContext = maContextHolder.get(); + if (mpXorEmulation && mpXorEmulation->IsEnabled()) + xCopyContext = mpXorEmulation->GetTargetContext(); + + // Set scale matrix of copy context to consider layer scaling + + CGContextScaleCTM(xCopyContext, 1 / fScale, 1 / fScale); + + // Creating an additional layer is required for drawing with the required scale and extent at the drawing destination + // thereafter. + + CGLayerHolder aSourceLayerHolder(pSrc->maLayer); + const CGSize aSourceSize = CGSizeMake(nScaledSourceWidth, nScaledSourceHeight); + aSourceLayerHolder.set(CGLayerCreateWithContext(xCopyContext, aSourceSize, nullptr)); + const CGContextRef xSourceContext = CGLayerGetContext(aSourceLayerHolder.get()); + CGPoint aSrcPoint = CGPointMake(-nScaledSourceX, -nScaledSourceY); + if (pSrc->IsFlipped()) + { + CGContextTranslateCTM(xSourceContext, 0, nScaledSourceHeight); + CGContextScaleCTM(xSourceContext, 1, -1); + aSrcPoint.y = nScaledSourceY + nScaledSourceHeight - mnHeight * fScale; + } + CGContextSetBlendMode(xSourceContext, kCGBlendModeCopy); + CGContextDrawLayerAtPoint(xSourceContext, aSrcPoint, pSrc->maLayer.get()); + + // Copy source area from additional layer to traget area + + const CGRect aTargetRect = CGRectMake(nScaledTargetX, nScaledTargetY, nScaledSourceWidth, nScaledSourceHeight); + CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy); + CGContextDrawLayerInRect(xCopyContext, aTargetRect, aSourceLayerHolder.get()); + + // Housekeeping on exit + + maContextHolder.restoreState(); + if (aSourceLayerHolder.get() != maLayer.get()) + CGLayerRelease(aSourceLayerHolder.get()); + RefreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight); +} + +void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRef xContext, int nBitmapDepth) +{ + SAL_INFO("vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext); + + // Set member variables + + InvalidateContext(); + mbWindow = false; + mbPrinter = false; + mbVirDev = true; + maLayer = rLayer; + mnBitmapDepth = nBitmapDepth; + + // Get size and scale from layer if set else from bitmap and AquaSalGraphics::GetWindowScaling(), which is used to determine + // scaling for direct graphics output too + + CGSize aSize; + float fScale; + if (maLayer.isSet()) + { + maContextHolder.set(CGLayerGetContext(maLayer.get())); + aSize = CGLayerGetSize(maLayer.get()); + fScale = maLayer.getScale(); + } + else + { + maContextHolder.set(xContext); + if (!xContext) + return; + aSize.width = CGBitmapContextGetWidth(xContext); + aSize.height = CGBitmapContextGetHeight(xContext); + fScale = GetWindowScaling(); + } + mnWidth = aSize.width / fScale; + mnHeight = aSize.height / fScale; + + // Set color space for fill and stroke + + CGColorSpaceRef aColorSpace = GetSalData()->mxRGBSpace; + CGContextSetFillColorSpace(maContextHolder.get(), aColorSpace); + CGContextSetStrokeColorSpace(maContextHolder.get(), aColorSpace); + + // Apply scale matrix to virtual device graphics + + CGContextScaleCTM(maContextHolder.get(), fScale, fScale); + + // Apply XOR emulation if required + + if (mpXorEmulation) + { + mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); + if (mpXorEmulation->IsEnabled()) + maContextHolder.set(mpXorEmulation->GetMaskContext()); + } + + // Housekeeping on exit + + maContextHolder.saveState(); + SetState(); + + SAL_INFO("vcl.quartz", "SetVirDevGraphics() this=" << this << + " (" << mnWidth << "x" << mnHeight << ") fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth); +} + +// 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(nullptr, nullptr); + } + CGLayerRelease(maLayer.get()); + maLayer.set(nullptr); + } + + if (maBitmapContext.isSet()) + { + 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")); + + // Do not delete/resize graphics context if it has been received from outside VCL + + if (mbForeignContext) + return true; + + // Do not delete/resize graphics context if no change of geometry has been requested + + float fScale; + if (maLayer.isSet()) + { + fScale = maLayer.getScale(); + const CGSize aSize = CGLayerGetSize(maLayer.get()); + if ((nDX == aSize.width / fScale) && (nDY == aSize.height / fScale)) + return true; + } + + // Destroy graphics context if change of geometry has been requested + + Destroy(); + + // Prepare new graphics context for initialization, use scaling independent of prior graphics context calculated by + // AquaSalGraphics::GetWindowScaling(), which is used to determine scaling for direct graphics output too + + mnWidth = nDX; + mnHeight = nDY; + fScale = mpGraphics->GetWindowScaling(); + CGColorSpaceRef aColorSpace; + uint32_t nFlags; + if (mnBitmapDepth && (mnBitmapDepth < 16)) + { + mnBitmapDepth = 8; + aColorSpace = GetSalData()->mxGraySpace; + nFlags = kCGImageAlphaNone; + } + else + { + mnBitmapDepth = 32; + aColorSpace = GetSalData()->mxRGBSpace; + + nFlags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + } + + // Allocate buffer for virtual device graphics as bitmap context to store graphics with highest required (scaled) resolution + + size_t nScaledWidth = mnWidth * fScale; + size_t nScaledHeight = mnHeight * fScale; + size_t nBytesPerRow = mnBitmapDepth * nScaledWidth / 8; + maBitmapContext.set(CGBitmapContextCreate(nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, aColorSpace, nFlags)); + + SAL_INFO("vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << + " fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth); + + CGSize aLayerSize = { static_cast<CGFloat>(nScaledWidth), static_cast<CGFloat>(nScaledHeight) }; + maLayer.set(CGLayerCreateWithContext(maBitmapContext.get(), aLayerSize, nullptr)); + maLayer.setScale(fScale); + mpGraphics->SetVirDevGraphics(maLayer, CGLayerGetContext(maLayer.get()), mnBitmapDepth); + + SAL_WARN_IF(!maBitmapContext.isSet(), "vcl.quartz", "No context"); + + return maLayer.isSet(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx index cf1f26648b7f..a1570dd04ffb 100644 --- a/vcl/quartz/salbmp.cxx +++ b/vcl/quartz/salbmp.cxx @@ -69,64 +69,6 @@ QuartzSalBitmap::~QuartzSalBitmap() doDestroy(); } -bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits, int nX, int nY, int nWidth, int nHeight, bool bFlipped) -{ - - // TODO: Bitmaps from scaled layers are reverted to single precision. This is a workaround only unless bitmaps with precision of - // source layer are implemented. - - 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; - } - - CGSize aLayerSize = CGLayerGetSize(rLayerHolder.get()); - const float fScale = rLayerHolder.getScale(); - aLayerSize.width /= fScale; - aLayerSize.height /= fScale; - - 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 * fScale), static_cast<CGFloat>(-nY * fScale) }; - if (maGraphicContext.isSet()) - { - if( bFlipped ) - { - CGContextTranslateCTM(maGraphicContext.get(), 0, +mnHeight); - CGContextScaleCTM(maGraphicContext.get(), +1, -1); - } - maGraphicContext.saveState(); - CGContextScaleCTM(maGraphicContext.get(), 1 / fScale, 1 / fScale); - CGContextDrawLayerAtPoint(maGraphicContext.get(), aSrcPoint, rLayerHolder.get()); - maGraphicContext.restoreState(); - } - return true; -} - bool QuartzSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette ) { if( !isValidBitCount( nBits ) ) diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index 0597fe3d021d..33ffc43741a1 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -267,117 +267,6 @@ void AquaSalGraphics::ApplyXorContext() } } -void AquaSalGraphics::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcGraphics) -{ - if (!pSrcGraphics) - pSrcGraphics = this; - AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); - if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 || rPosAry.mnDestHeight <= 0) - return; - if (!maContextHolder.isSet()) - return; - - SAL_WARN_IF (!pSrc->maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::copyBits() from non-layered graphics this=" << this); - - // Layered graphics are copied by AquaSalGraphics::copyScaledArea() which is able to consider the layer's scaling. - - if (pSrc->maLayer.isSet()) - copyScaledArea(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY, - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, pSrcGraphics); - else - { - ApplyXorContext(); - pSrc->ApplyXorContext(); - std::shared_ptr<SalBitmap> pBitmap = pSrc->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY, - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); - if (pBitmap) - { - SalTwoRect aPosAry(rPosAry); - aPosAry.mnSrcX = 0; - aPosAry.mnSrcY = 0; - drawBitmap(aPosAry, *pBitmap); - } - } -} - -void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY, - tools::Long nSrcWidth, tools::Long nSrcHeight, bool) -{ - if (!maContextHolder.isSet()) - return; - - // Functionality is implemented in protected member function AquaSalGraphics::copyScaledArea() which requires an additional - // parameter of type SalGraphics to be used in AquaSalGraphics::copyBits() too. - - copyScaledArea(nDstX, nDstY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, this); -} - -void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY, - tools::Long nSrcWidth, tools::Long nSrcHeight, SalGraphics *pSrcGraphics) -{ - if (!pSrcGraphics) - pSrcGraphics = this; - AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics); - - SAL_WARN_IF(!maLayer.isSet(), "vcl.quartz", - "AquaSalGraphics::copyScaledArea() without graphics context or for non-layered graphics this=" << this); - - if (!maContextHolder.isSet() || !maLayer.isSet()) - return; - - // Determine scaled geometry of source and target area assuming source and target area have the same scale - - float fScale = maLayer.getScale(); - CGFloat nScaledSourceX = nSrcX * fScale; - CGFloat nScaledSourceY = nSrcY * fScale; - CGFloat nScaledTargetX = nDstX * fScale; - CGFloat nScaledTargetY = nDstY * fScale; - CGFloat nScaledSourceWidth = nSrcWidth * fScale; - CGFloat nScaledSourceHeight = nSrcHeight * fScale; - - // Apply XOR context and get copy context from current graphics context or XOR context - - ApplyXorContext(); - maContextHolder.saveState(); - CGContextRef xCopyContext = maContextHolder.get(); - if (mpXorEmulation && mpXorEmulation->IsEnabled()) - xCopyContext = mpXorEmulation->GetTargetContext(); - - // Set scale matrix of copy context to consider layer scaling - - CGContextScaleCTM(xCopyContext, 1 / fScale, 1 / fScale); - - // Creating an additional layer is required for drawing with the required scale and extent at the drawing destination - // thereafter. - - CGLayerHolder aSourceLayerHolder(pSrc->maLayer); - const CGSize aSourceSize = CGSizeMake(nScaledSourceWidth, nScaledSourceHeight); - aSourceLayerHolder.set(CGLayerCreateWithContext(xCopyContext, aSourceSize, nullptr)); - const CGContextRef xSourceContext = CGLayerGetContext(aSourceLayerHolder.get()); - CGPoint aSrcPoint = CGPointMake(-nScaledSourceX, -nScaledSourceY); - if (pSrc->IsFlipped()) - { - CGContextTranslateCTM(xSourceContext, 0, nScaledSourceHeight); - CGContextScaleCTM(xSourceContext, 1, -1); - aSrcPoint.y = nScaledSourceY + nScaledSourceHeight - mnHeight * fScale; - } - CGContextSetBlendMode(xSourceContext, kCGBlendModeCopy); - CGContextDrawLayerAtPoint(xSourceContext, aSrcPoint, pSrc->maLayer.get()); - - // Copy source area from additional layer to traget area - - const CGRect aTargetRect = CGRectMake(nScaledTargetX, nScaledTargetY, nScaledSourceWidth, nScaledSourceHeight); - CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy); - CGContextDrawLayerInRect(xCopyContext, aTargetRect, aSourceLayerHolder.get()); - - // Housekeeping on exit - - maContextHolder.restoreState(); - if (aSourceLayerHolder.get() != maLayer.get()) - CGLayerRelease(aSourceLayerHolder.get()); - RefreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight); -} - #ifndef IOS void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics ) @@ -1826,74 +1715,4 @@ bool XorEmulation::UpdateTarget() return true; } -void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRef xContext, int nBitmapDepth) -{ - SAL_INFO("vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext); - - // Set member variables - - InvalidateContext(); - mbWindow = false; - mbPrinter = false; - mbVirDev = true; - maLayer = rLayer; - mnBitmapDepth = nBitmapDepth; - -#ifdef IOS - - mbForeignContext = xContext != NULL; - -#endif - - // Get size and scale from layer if set else from bitmap and AquaSalGraphics::GetWindowScaling(), which is used to determine - // scaling for direct graphics output too - - CGSize aSize; - float fScale; - if (maLayer.isSet()) - { - maContextHolder.set(CGLayerGetContext(maLayer.get())); - aSize = CGLayerGetSize(maLayer.get()); - fScale = maLayer.getScale(); - } - else - { - maContextHolder.set(xContext); - if (!xContext) - return; - aSize.width = CGBitmapContextGetWidth(xContext); - aSize.height = CGBitmapContextGetHeight(xContext); - fScale = GetWindowScaling(); - } - mnWidth = aSize.width / fScale; - mnHeight = aSize.height / fScale; - - // Set color space for fill and stroke - - CGColorSpaceRef aColorSpace = GetSalData()->mxRGBSpace; - CGContextSetFillColorSpace(maContextHolder.get(), aColorSpace); - CGContextSetStrokeColorSpace(maContextHolder.get(), aColorSpace); - - // Apply scale matrix to virtual device graphics - - CGContextScaleCTM(maContextHolder.get(), fScale, fScale); - - // Apply XOR emulation if required - - if (mpXorEmulation) - { - mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); - if (mpXorEmulation->IsEnabled()) - maContextHolder.set(mpXorEmulation->GetMaskContext()); - } - - // Housekeeping on exit - - maContextHolder.saveState(); - SetState(); - - SAL_INFO("vcl.quartz", "SetVirDevGraphics() this=" << this << - " (" << mnWidth << "x" << mnHeight << ") fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salvd.cxx b/vcl/quartz/salvd.cxx index 5d7facd3ef38..9f6bfdd930aa 100644 --- a/vcl/quartz/salvd.cxx +++ b/vcl/quartz/salvd.cxx @@ -161,34 +161,6 @@ AquaSalVirtualDevice::~AquaSalVirtualDevice() Destroy(); } -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(nullptr, nullptr); - } - CGLayerRelease(maLayer.get()); - maLayer.set(nullptr); - } - - if (maBitmapContext.isSet()) - { - CGContextRelease(maBitmapContext.get()); - maBitmapContext.set(nullptr); - } -} - SalGraphics* AquaSalVirtualDevice::AcquireGraphics() { if( mbGraphicsUsed || !mpGraphics ) @@ -204,80 +176,4 @@ void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* ) mbGraphicsUsed = false; } -bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY) -{ - SAL_INFO("vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << - " (" << nDX << "x" << nDY << ") mbForeignContext=" << (mbForeignContext ? "YES" : "NO")); - - // Do not delete/resize graphics context if it has been received from outside VCL - - if (mbForeignContext) - return true; - - // Do not delete/resize graphics context if no change of geometry has been requested - - float fScale; - if (maLayer.isSet()) - { - fScale = maLayer.getScale(); - const CGSize aSize = CGLayerGetSize(maLayer.get()); - if ((nDX == aSize.width / fScale) && (nDY == aSize.height / fScale)) - return true; - } - - // Destroy graphics context if change of geometry has been requested - - Destroy(); - - // Prepare new graphics context for initialization, use scaling independent of prior graphics context calculated by - // AquaSalGraphics::GetWindowScaling(), which is used to determine scaling for direct graphics output too - - mnWidth = nDX; - mnHeight = nDY; - fScale = mpGraphics->GetWindowScaling(); - CGColorSpaceRef aColorSpace; - uint32_t nFlags; - if (mnBitmapDepth && (mnBitmapDepth < 16)) - { - mnBitmapDepth = 8; - aColorSpace = GetSalData()->mxGraySpace; - nFlags = kCGImageAlphaNone; - } - else - { - mnBitmapDepth = 32; - aColorSpace = GetSalData()->mxRGBSpace; - -#ifdef MACOSX - - nFlags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; - -#else - - nFlags = kCGImageAlphaNoneSkipFirst | kCGImageByteOrder32Little; - -#endif - - } - - // Allocate buffer for virtual device graphics as bitmap context to store graphics with highest required (scaled) resolution - - size_t nScaledWidth = mnWidth * fScale; - size_t nScaledHeight = mnHeight * fScale; - size_t nBytesPerRow = mnBitmapDepth * nScaledWidth / 8; - maBitmapContext.set(CGBitmapContextCreate(nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, aColorSpace, nFlags)); - - SAL_INFO("vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << - " fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth); - - CGSize aLayerSize = { static_cast<CGFloat>(nScaledWidth), static_cast<CGFloat>(nScaledHeight) }; - maLayer.set(CGLayerCreateWithContext(maBitmapContext.get(), aLayerSize, nullptr)); - maLayer.setScale(fScale); - mpGraphics->SetVirDevGraphics(maLayer, CGLayerGetContext(maLayer.get()), mnBitmapDepth); - - SAL_WARN_IF(!maBitmapContext.isSet(), "vcl.quartz", "No context"); - - return maLayer.isSet(); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |