summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/Library_vclplug_osx.mk1
-rw-r--r--vcl/inc/quartz/salgdi.h445
-rw-r--r--vcl/ios/dummies.cxx5
-rw-r--r--vcl/ios/salios.cxx142
-rw-r--r--vcl/osx/salgdiutils.cxx101
-rw-r--r--vcl/osx/salmacos.cxx130
-rw-r--r--vcl/osx/salnativewidgets.cxx88
-rw-r--r--vcl/quartz/AquaGraphicsBackend.cxx1355
-rw-r--r--vcl/quartz/salgdi.cxx106
-rw-r--r--vcl/quartz/salgdicommon.cxx1298
10 files changed, 1906 insertions, 1765 deletions
diff --git a/vcl/Library_vclplug_osx.mk b/vcl/Library_vclplug_osx.mk
index c80d3bc8d7f3..4b2b4a61b3f4 100644
--- a/vcl/Library_vclplug_osx.mk
+++ b/vcl/Library_vclplug_osx.mk
@@ -137,6 +137,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_osx,\
vcl/quartz/salgdicommon \
vcl/quartz/salvd \
vcl/quartz/utils \
+ vcl/quartz/AquaGraphicsBackend \
))
$(eval $(call gb_Library_use_system_darwin_frameworks,vclplug_osx,\
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 80e6c66d1a00..e7559c5b9e7d 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -130,177 +130,326 @@ private:
std::unordered_map<sal_IntPtr, rtl::Reference<CoreTextFontFace>> maFontContainer;
};
-class AquaSalGraphics : public SalGraphics
+namespace sal::aqua
{
+float getWindowScaling();
+}
+
+struct AquaSharedAttributes
+{
+ /// path representing current clip region
+ CGMutablePathRef mxClipPath;
+
+ /// Drawing colors
+ /// pen color RGBA
+ RGBAColor maLineColor;
+
+ /// brush color RGBA
+ RGBAColor maFillColor;
+
+ // Graphics types
+#ifdef MACOSX
+ AquaSalFrame* mpFrame;
+ /// is this a window graphics
+ bool mbWindow;
+#else // IOS
+ // mirror AquaSalVirtualDevice::mbForeignContext for SvpSalGraphics objects related to such
+ bool mbForeignContext;
+#endif
+ /// is this a printer graphics
+ bool mbPrinter;
+ /// is this a virtual device graphics
+ bool mbVirDev;
+
CGLayerHolder maLayer; // Quartz graphics layer
CGContextHolder maContextHolder; // Quartz drawing context
CGContextHolder maBGContextHolder; // Quartz drawing context for CGLayer
CGContextHolder maCSContextHolder; // Quartz drawing context considering the color space
+ int mnWidth;
+ int mnHeight;
+ int mnXorMode; // 0: off 1: on 2: invert only
+ int mnBitmapDepth; // zero unless bitmap
std::unique_ptr<XorEmulation> mpXorEmulation;
- int mnXorMode; // 0: off 1: on 2: invert only
- int mnWidth;
- int mnHeight;
- int mnBitmapDepth; // zero unless bitmap
- /// device resolution of this graphics
- sal_Int32 mnRealDPIX;
- sal_Int32 mnRealDPIY;
- /// path representing current clip region
- CGMutablePathRef mxClipPath;
+ AquaSharedAttributes()
+ : mxClipPath(nullptr)
+ , maLineColor(COL_WHITE)
+ , maFillColor(COL_BLACK)
+#ifdef MACOSX
+ , mpFrame(nullptr)
+ , mbWindow(false)
+#else
+ , mbForeignContext(false)
+#endif
+ , mbPrinter(false)
+ , mbVirDev(false)
+ , mnWidth(0)
+ , mnHeight(0)
+ , mnXorMode(0)
+ , mnBitmapDepth(0)
+ {}
+
+ void unsetClipPath()
+ {
+ if (mxClipPath)
+ {
+ CGPathRelease(mxClipPath);
+ mxClipPath = nullptr;
+ }
+ }
+
+ void unsetState()
+ {
+ unsetClipPath();
+ }
+
+ bool checkContext();
+ void setState();
+
+ bool isPenVisible() const
+ {
+ return maLineColor.IsVisible();
+ }
+ bool isBrushVisible() const
+ {
+ return maFillColor.IsVisible();
+ }
+
+ void refreshRect(float lX, float lY, float lWidth, float lHeight)
+ {
+#ifdef MACOSX
+ if (!mbWindow) // view only on Window graphics
+ return;
+
+ if (mpFrame)
+ {
+ // update a little more around the designated rectangle
+ // this helps with antialiased rendering
+ // Rounding down x and width can accumulate a rounding error of up to 2
+ // The decrementing of x, the rounding error and the antialiasing border
+ // require that the width and the height need to be increased by four
+ const tools::Rectangle aVclRect(
+ Point(tools::Long(lX - 1), tools::Long(lY - 1)),
+ Size(tools::Long(lWidth + 4), tools::Long(lHeight + 4)));
+
+ mpFrame->maInvalidRect.Union(aVclRect);
+ }
+#else
+ (void) lX;
+ (void) lY;
+ (void) lWidth;
+ (void) lHeight;
+ return;
+#endif
+ }
+
+ // apply the XOR mask to the target context if active and dirty
+ void applyXorContext()
+ {
+ if (!mpXorEmulation)
+ return;
+ if (mpXorEmulation->UpdateTarget())
+ {
+ refreshRect(0, 0, mnWidth, mnHeight); // TODO: refresh minimal changerect
+ }
+ }
- /// Drawing colors
- /// pen color RGBA
- RGBAColor maLineColor;
- /// brush color RGBA
- RGBAColor maFillColor;
+ // differences between VCL, Quartz and kHiThemeOrientation coordinate systems
+ // make some graphics seem to be vertically-mirrored from a VCL perspective
+ bool isFlipped() const
+ {
+ #ifdef MACOSX
+ return mbWindow;
+ #else
+ return false;
+ #endif
+ }
+};
- // Device Font settings
- rtl::Reference<CoreTextStyle> mpTextStyle[MAX_FALLBACK];
- RGBAColor maTextColor;
- /// allows text to be rendered without antialiasing
- bool mbNonAntialiasedText;
+class AquaGraphicsBackend final : public SalGraphicsImpl
+{
+private:
+ AquaSharedAttributes& mrShared;
+
+ void drawPixelImpl( tools::Long nX, tools::Long nY, const RGBAColor& rColor); // helper to draw single pixels
#ifdef MACOSX
- AquaSalFrame* mpFrame;
+ void refreshRect(const NSRect& rRect)
+ {
+ mrShared.refreshRect(rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height);
+ }
+#else
+ void refreshRect(const CGRect& /*rRect*/)
+ {}
#endif
- // Graphics types
+ void pattern50Fill();
- /// is this a printer graphics
- bool mbPrinter;
- /// is this a virtual device graphics
- bool mbVirDev;
#ifdef MACOSX
- /// is this a window graphics
- bool mbWindow;
+protected:
+ void copyScaledArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY,
+ tools::Long nSrcWidth, tools::Long nSrcHeight, AquaSharedAttributes* pSrcShared);
+#endif
-#else // IOS
+public:
+ AquaGraphicsBackend(AquaSharedAttributes & rShared);
+ ~AquaGraphicsBackend() override;
- // mirror AquaSalVirtualDevice::mbForeignContext for SvpSalGraphics objects related to such
- bool mbForeignContext;
+ void Init() override;
-#endif
+ void freeResources() override;
+
+ OUString getRenderBackendName() const override
+ {
+ return "aqua";
+ }
+
+ bool setClipRegion(vcl::Region const& rRegion) override;
+ void ResetClipRegion() override;
+
+ sal_uInt16 GetBitCount() const override;
+
+ tools::Long GetGraphicsWidth() const override;
+
+ void SetLineColor() override;
+ void SetLineColor(Color nColor) override;
+ void SetFillColor() override;
+ void SetFillColor(Color nColor) override;
+ void SetXORMode(bool bSet, bool bInvertOnly) override;
+ void SetROPLineColor(SalROPColor nROPColor) override;
+ void SetROPFillColor(SalROPColor nROPColor) override;
+
+ void drawPixel(tools::Long nX, tools::Long nY) override;
+ void drawPixel(tools::Long nX, tools::Long nY, Color nColor) override;
+
+ void drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2) override;
+ void drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) override;
+ void drawPolyLine(sal_uInt32 nPoints, const Point* pPointArray) override;
+ void drawPolygon(sal_uInt32 nPoints, const Point* pPointArray) override;
+ void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints,
+ const Point** pPointArray) override;
+
+ bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
+ const basegfx::B2DPolyPolygon&, double fTransparency) override;
+
+ bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, const basegfx::B2DPolygon&,
+ double fTransparency, double fLineWidth, const std::vector<double>* pStroke,
+ basegfx::B2DLineJoin, css::drawing::LineCap, double fMiterMinimumAngle,
+ bool bPixelSnapHairline) override;
+
+ bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPointArray,
+ const PolyFlags* pFlagArray) override;
+
+ bool drawPolygonBezier(sal_uInt32 nPoints, const Point* pPointArray,
+ const PolyFlags* pFlagArray) override;
+
+ bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints,
+ const Point* const* pPointArray,
+ const PolyFlags* const* pFlagArray) override;
+
+ void copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY,
+ tools::Long nSrcWidth, tools::Long nSrcHeight, bool bWindowInvalidate) override;
+
+ void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override;
+
+ void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override;
+
+ void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
+ const SalBitmap& rMaskBitmap) override;
+
+ void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
+ Color nMaskColor) override;
+
+ std::shared_ptr<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight) override;
+
+ Color getPixel(tools::Long nX, tools::Long nY) override;
+
+ void invert(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
+ SalInvert nFlags) override;
+
+ void invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags) override;
+
+ bool drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
+ void* pPtr, sal_uInt32 nSize) override;
+
+ bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override;
+
+ bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap,
+ const SalBitmap& rMaskBitmap, const SalBitmap& rAlphaBitmap) override;
+
+ bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap) override;
+
+ bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
+ const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
+ const SalBitmap* pAlphaBitmap, double fAlpha) override;
+
+ bool hasFastDrawTransformedBitmap() const override;
+
+ bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
+ sal_uInt8 nTransparency) override;
+
+ bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override;
+ bool implDrawGradient(basegfx::B2DPolyPolygon const& rPolyPolygon,
+ SalGradient const& rGradient) override;
+
+ bool supportsOperation(OutDevSupportType eType) const override;
+};
+
+class AquaSalGraphics : public SalGraphicsAutoDelegateToImpl
+{
+ AquaSharedAttributes maShared;
+ std::unique_ptr<AquaGraphicsBackend> mpBackend;
+
+ /// device resolution of this graphics
+ sal_Int32 mnRealDPIX;
+ sal_Int32 mnRealDPIY;
+
+ // Device Font settings
+ rtl::Reference<CoreTextStyle> mpTextStyle[MAX_FALLBACK];
+ RGBAColor maTextColor;
+ /// allows text to be rendered without antialiasing
+ bool mbNonAntialiasedText;
public:
AquaSalGraphics();
virtual ~AquaSalGraphics() override;
- bool IsPenVisible() const { return maLineColor.IsVisible(); }
- bool IsBrushVisible() const { return maFillColor.IsVisible(); }
-
void SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRef, int nBitDepth = 0);
#ifdef MACOSX
void initResolution( NSWindow* );
void copyResolution( AquaSalGraphics& );
void updateResolution();
- static float GetWindowScaling();
void SetWindowGraphics( AquaSalFrame* pFrame );
- bool IsWindowGraphics() const { return mbWindow; }
+ bool IsWindowGraphics() const { return maShared.mbWindow; }
void SetPrinterGraphics(CGContextRef, sal_Int32 nRealDPIX, sal_Int32 nRealDPIY);
- AquaSalFrame* getGraphicsFrame() const { return mpFrame; }
- void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; }
+ AquaSalFrame* getGraphicsFrame() const { return maShared.mpFrame; }
+ void setGraphicsFrame( AquaSalFrame* pFrame ) { maShared.mpFrame = pFrame; }
#endif
- void ImplDrawPixel( tools::Long nX, tools::Long nY, const RGBAColor& ); // helper to draw single pixels
-
- bool CheckContext();
-
#ifdef MACOSX
void UpdateWindow( NSRect& ); // delivered in NSView coordinates
- void RefreshRect( const NSRect& );
+ void RefreshRect(const NSRect& rRect)
+ {
+ maShared.refreshRect(rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height);
+ }
#else
void RefreshRect( const CGRect& ) {}
#endif
- void RefreshRect(float lX, float lY, float lWidth, float lHeight);
- void SetState();
void UnsetState();
// InvalidateContext does an UnsetState and sets mrContext to 0
void InvalidateContext();
- virtual SalGraphicsImpl* GetImpl() const override;
+ AquaGraphicsBackend* getAquaGraphicsBackend() const
+ {
+ return mpBackend.get();
+ }
- virtual bool setClipRegion( const vcl::Region& ) override;
-
- // draw --> LineColor and FillColor and RasterOp and ClipRegion
- virtual void drawPixel( tools::Long nX, tools::Long nY ) override;
- virtual void drawPixel( tools::Long nX, tools::Long nY, Color nColor ) override;
- virtual void drawLine(
- tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 ) override;
- virtual void drawRect(
- tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override;
- virtual void drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry ) override;
- virtual void drawPolygon( sal_uInt32 nPoints, const Point* pPtAry ) override;
- virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, const Point** pPtAry ) override;
- virtual bool drawPolyPolygon(
- const basegfx::B2DHomMatrix& rObjectToDevice,
- const basegfx::B2DPolyPolygon&,
- double fTransparency) override;
- virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry ) override;
- virtual bool drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry ) override;
- virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const Point* const* pPtAry, const PolyFlags* const* pFlgAry ) override;
- virtual bool drawPolyLine(
- const basegfx::B2DHomMatrix& rObjectToDevice,
- const basegfx::B2DPolygon&,
- double fTransparency,
- double rLineWidth,
- const std::vector< double >* pStroke, // MM01
- basegfx::B2DLineJoin,
- css::drawing::LineCap eLineCap,
- double fMiterMinimumAngle,
- bool bPixelSnapHairline) override;
- virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; };
-
- // CopyArea --> No RasterOp, but ClipRegion
- virtual void copyArea( tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, tools::Long nSrcWidth,
- tools::Long nSrcHeight, bool bWindowInvalidate ) override;
-
- // CopyBits and DrawBitmap --> RasterOp and ClipRegion
- // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
- virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) override;
- virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) override;
- virtual void drawBitmap( const SalTwoRect& rPosAry,
- const SalBitmap& rSalBitmap,
- const SalBitmap& rTransparentBitmap ) override;
- virtual void drawMask( const SalTwoRect& rPosAry,
- const SalBitmap& rSalBitmap,
- Color nMaskColor ) override;
-
- virtual std::shared_ptr<SalBitmap> getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override;
- virtual Color getPixel( tools::Long nX, tools::Long nY ) override;
-
- // invert --> ClipRegion (only Windows or VirDevs)
- virtual void invert( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, SalInvert nFlags) override;
- virtual void invert( sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags ) override;
-
- virtual bool drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize ) override;
-
- virtual bool blendBitmap( const SalTwoRect&,
- const SalBitmap& rBitmap ) override;
-
- virtual bool blendAlphaBitmap( const SalTwoRect&,
- const SalBitmap& rSrcBitmap,
- const SalBitmap& rMaskBitmap,
- const SalBitmap& rAlphaBitmap ) override;
-
- virtual bool drawAlphaBitmap( const SalTwoRect&,
- const SalBitmap& rSourceBitmap,
- const SalBitmap& rAlphaBitmap ) override;
-
- bool drawTransformedBitmap(
- const basegfx::B2DPoint& rNull,
- const basegfx::B2DPoint& rX,
- const basegfx::B2DPoint& rY,
- const SalBitmap& rSourceBitmap,
- const SalBitmap* pAlphaBitmap,
- double fAlpha) override;
-
- virtual bool hasFastDrawTransformedBitmap() const override;
-
- virtual bool drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth,
- tools::Long nHeight, sal_uInt8 nTransparency ) override;
+ virtual SalGraphicsImpl* GetImpl() const override;
#ifdef MACOSX
@@ -318,37 +467,11 @@ protected:
virtual bool getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState,
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:
// get device resolution
virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override;
- // get the depth of the device
- virtual sal_uInt16 GetBitCount() const override;
- // get the width of the device
- virtual tools::Long GetGraphicsWidth() const override;
-
- // set the clip region to empty
- virtual void ResetClipRegion() override;
-
- // set the line color to transparent (= don't draw lines)
- virtual void SetLineColor() override;
- // set the line color to a specific color
- virtual void SetLineColor( Color nColor ) override;
- // set the fill color to transparent (= don't fill)
- virtual void SetFillColor() override;
- // set the fill color to a specific color, shapes will be
- // filled accordingly
- virtual void SetFillColor( Color nColor ) override;
- // enable/disable XOR drawing
- virtual void SetXORMode( bool bSet, bool bInvertOnly ) override;
- // set line color for raster operations
- virtual void SetROPLineColor( SalROPColor nROPColor ) override;
- // set fill color for raster operations
- virtual void SetROPFillColor( SalROPColor nROPColor ) override;
// set the text color to a specific color
virtual void SetTextColor( Color nColor ) override;
// set the font
@@ -401,19 +524,11 @@ public:
virtual std::unique_ptr<GenericSalLayout>
GetTextLayout(int nFallbackLevel) override;
virtual void DrawTextLayout( const GenericSalLayout& ) override;
- virtual bool supportsOperation( OutDevSupportType ) const override;
- virtual OUString getRenderBackendName() const override { return "aqua"; }
virtual SystemGraphicsData
GetGraphicsData() const override;
private:
- // differences between VCL, Quartz and kHiThemeOrientation coordinate systems
- // make some graphics seem to be vertically-mirrored from a VCL perspective
- bool IsFlipped() const;
-
- void ApplyXorContext();
- void Pattern50Fill();
UInt32 getState( ControlState nState );
UInt32 getTrackState( ControlState nState );
static bool GetRawFontData( const PhysicalFontFace* pFontData,
@@ -421,16 +536,6 @@ private:
bool* pJustCFF );
};
-// --- some trivial inlines
-
-#ifdef MACOSX
-
-inline void AquaSalGraphics::RefreshRect( const NSRect& rRect )
-{
- RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
-}
-
-#endif
#endif // INCLUDED_VCL_INC_QUARTZ_SALGDI_H
diff --git a/vcl/ios/dummies.cxx b/vcl/ios/dummies.cxx
index d62609dc95bf..135a534243fd 100644
--- a/vcl/ios/dummies.cxx
+++ b/vcl/ios/dummies.cxx
@@ -110,11 +110,6 @@ void SalGenericInstance::jobEndedPrinterUpdate()
{
}
-bool AquaSalGraphics::drawEPS( long, long, long, long, void*, sal_uInt32 )
-{
- return false;
-}
-
using namespace psp;
GenericUnixSalData::GenericUnixSalData(GenericUnixSalDataType const t, SalInstance *const pInstance)
diff --git a/vcl/ios/salios.cxx b/vcl/ios/salios.cxx
index fc925b61cdf3..ac11faff3072 100644
--- a/vcl/ios/salios.cxx
+++ b/vcl/ios/salios.cxx
@@ -88,13 +88,8 @@ bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits
// From salgdicommon.cxx
-void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGraphics )
+void AquaGraphicsBackend::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 ||
@@ -106,12 +101,21 @@ void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGrap
}
// If called from idle layout, maContextHolder.get() is NULL, no idea what to do
- if (!maContextHolder.isSet())
+ if (!mrShared.maContextHolder.isSet())
return;
+ AquaSharedAttributes* pSrcShared = nullptr;
+
+ if (pSrcGraphics)
+ {
+ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ pSrcShared = &pSrc->getAquaGraphicsBackend()->mrShared;
+ }
+ else
+ pSrcShared = &mrShared;
+
// accelerate trivial operations
- /*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
- const bool bSameGraphics = (this == pSrc);
+ const bool bSameGraphics = (pSrcShared == &mrShared);
if( bSameGraphics &&
(rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
@@ -129,26 +133,27 @@ void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGrap
return;
}
- ApplyXorContext();
- pSrc->ApplyXorContext();
+ mrShared.applyXorContext();
+ if (!bSameGraphics)
+ pSrcShared->applyXorContext();
- SAL_WARN_IF (!pSrc->maLayer.isSet(), "vcl.quartz",
+ 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) &&
- (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth)
- && pSrc->maLayer.isSet()) // workaround for a Quartz crash
+ (!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 = maContextHolder;
- if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ CGContextHolder aCopyContext = mrShared.maContextHolder;
+ if (mrShared.mpXorEmulation && mrShared.mpXorEmulation->IsEnabled())
{
- if( pSrcGraphics == this )
+ if (bSameGraphics)
{
- aCopyContext.set(mpXorEmulation->GetTargetContext());
+ aCopyContext.set(mrShared.mpXorEmulation->GetTargetContext());
}
}
aCopyContext.saveState();
@@ -158,43 +163,47 @@ void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGrap
// draw at new destination
// NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down
- if( pSrc->IsFlipped() )
+ if (pSrcShared->isFlipped())
{
- CGContextTranslateCTM( aCopyContext.get(), 0, +mnHeight );
- CGContextScaleCTM( aCopyContext.get(), +1, -1 );
+ CGContextTranslateCTM(aCopyContext.get(), 0, +mrShared.mnHeight);
+ CGContextScaleCTM(aCopyContext.get(), +1, -1);
}
// TODO: pSrc->size() != this->size()
- CGContextDrawLayerAtPoint(aCopyContext.get(), aDstPoint, pSrc->maLayer.get());
+ CGContextDrawLayerAtPoint(aCopyContext.get(), aDstPoint, pSrcShared->maLayer.get());
aCopyContext.restoreState();
// mark the destination rectangle as updated
- RefreshRect( aDstRect );
+ refreshRect(aDstRect);
}
else
{
- std::shared_ptr<SalBitmap> pBitmap = pSrc->getBitmap( rPosAry.mnSrcX, rPosAry.mnSrcY,
- rPosAry.mnSrcWidth, rPosAry.mnSrcHeight );
- if( pBitmap )
+ 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 );
+ drawBitmap(aPosAry, *pBitmap);
}
}
}
-void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
+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 (!maLayer.isSet(), "vcl.quartz",
+ SAL_WARN_IF (!mrShared.maLayer.isSet(), "vcl.quartz",
"AquaSalGraphics::copyArea() for non-layered graphics this=" << this);
- if (!maLayer.isSet())
+ if (!mrShared.maLayer.isSet())
return;
- float fScale = maLayer.getScale();
+ float fScale = mrShared.maLayer.getScale();
tools::Long nScaledSourceX = nSrcX * fScale;
tools::Long nScaledSourceY = nSrcY * fScale;
@@ -205,17 +214,17 @@ void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long
tools::Long nScaledSourceWidth = nSrcWidth * fScale;
tools::Long nScaledSourceHeight = nSrcHeight * fScale;
- ApplyXorContext();
+ mrShared.applyXorContext();
- maContextHolder.saveState();
+ 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 = maContextHolder.get();
+ CGContextRef xCopyContext = mrShared.maContextHolder.get();
- if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ if (mrShared.mpXorEmulation && mrShared.mpXorEmulation->IsEnabled())
{
- xCopyContext = mpXorEmulation->GetTargetContext();
+ xCopyContext = mrShared.mpXorEmulation->GetTargetContext();
}
// If we have a scaled layer, we need to revert the scaling or else
@@ -227,7 +236,7 @@ void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long
// e.g. on OSX>=10.5 only this situation causes problems:
// mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth
- CGLayerHolder sSourceLayerHolder(maLayer);
+ CGLayerHolder sSourceLayerHolder(mrShared.maLayer);
{
const CGSize aSrcSize = CGSizeMake(nScaledSourceWidth, nScaledSourceHeight);
sSourceLayerHolder.set(CGLayerCreateWithContext(xCopyContext, aSrcSize, nullptr));
@@ -235,15 +244,15 @@ void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long
const CGContextRef xSrcContext = CGLayerGetContext(sSourceLayerHolder.get());
CGPoint aSrcPoint = CGPointMake(-nScaledSourceX, -nScaledSourceY);
- if( IsFlipped() )
+ if (mrShared.isFlipped())
{
- CGContextTranslateCTM( xSrcContext, 0, +nScaledSourceHeight );
- CGContextScaleCTM( xSrcContext, +1, -1 );
- aSrcPoint.y = (nScaledSourceY + nScaledSourceHeight) - (mnHeight * fScale);
+ CGContextTranslateCTM(xSrcContext, 0, +nScaledSourceHeight);
+ CGContextScaleCTM(xSrcContext, +1, -1);
+ aSrcPoint.y = (nScaledSourceY + nScaledSourceHeight) - (mrShared.mnHeight * fScale);
}
CGContextSetBlendMode(xSrcContext, kCGBlendModeCopy);
- CGContextDrawLayerAtPoint(xSrcContext, aSrcPoint, maLayer.get());
+ CGContextDrawLayerAtPoint(xSrcContext, aSrcPoint, mrShared.maLayer.get());
}
// draw at new destination
@@ -251,15 +260,16 @@ void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long
CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy);
CGContextDrawLayerInRect(xCopyContext, aTargetRect, sSourceLayerHolder.get());
- maContextHolder.restoreState();
+ mrShared.maContextHolder.restoreState();
// cleanup
- if (sSourceLayerHolder.get() != maLayer.get())
+ if (sSourceLayerHolder.get() != mrShared.maLayer.get())
{
CGLayerRelease(sSourceLayerHolder.get());
}
+
// mark the destination rectangle as updated
- RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight );
+ mrShared.refreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight);
}
void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const & rLayer, CGContextRef xContext,
@@ -267,52 +277,52 @@ void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const & rLayer, CGContextR
{
SAL_INFO( "vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext );
- mbPrinter = false;
- mbVirDev = true;
+ maShared.mbPrinter = false;
+ maShared.mbVirDev = true;
// set graphics properties
- maLayer = rLayer;
- maContextHolder.set(xContext);
+ maShared.maLayer = rLayer;
+ maShared.maContextHolder.set(xContext);
- mnBitmapDepth = nBitmapDepth;
+ maShared.mnBitmapDepth = nBitmapDepth;
- mbForeignContext = xContext != NULL;
+ maShared.mbForeignContext = xContext != NULL;
// return early if the virdev is being destroyed
- if( !xContext )
+ if (!xContext)
return;
// get new graphics properties
- if (!maLayer.isSet())
+ if (!maShared.maLayer.isSet())
{
- mnWidth = CGBitmapContextGetWidth( maContextHolder.get() );
- mnHeight = CGBitmapContextGetHeight( maContextHolder.get() );
+ maShared.mnWidth = CGBitmapContextGetWidth(maShared.maContextHolder.get());
+ maShared.mnHeight = CGBitmapContextGetHeight(maShared.maContextHolder.get());
}
else
{
- const CGSize aSize = CGLayerGetSize(maLayer.get());
- mnWidth = static_cast<int>(aSize.width);
- mnHeight = static_cast<int>(aSize.height);
+ 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( maContextHolder.get(), aCGColorSpace );
- CGContextSetStrokeColorSpace( maContextHolder.get(), aCGColorSpace );
+ CGContextSetFillColorSpace(maShared.maContextHolder.get(), aCGColorSpace);
+ CGContextSetStrokeColorSpace(maShared.maContextHolder.get(), aCGColorSpace);
// re-enable XorEmulation for the new context
- if( mpXorEmulation )
+ if (maShared.mpXorEmulation)
{
- mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
- if( mpXorEmulation->IsEnabled() )
+ maShared.mpXorEmulation->SetTarget(maShared.mnWidth, maShared.mnHeight, maShared.mnBitmapDepth, maShared.maContextHolder.get(), maShared.maLayer.get());
+ if (maShared.mpXorEmulation->IsEnabled())
{
- maContextHolder.set(mpXorEmulation->GetMaskContext());
+ maShared.maContextHolder.set(maShared.mpXorEmulation->GetMaskContext());
}
}
// initialize stack of CGContext states
- maContextHolder.saveState();
- SetState();
+ maShared.maContextHolder.saveState();
+ maShared.setState();
}
/// From salvd.cxx
diff --git a/vcl/osx/salgdiutils.cxx b/vcl/osx/salgdiutils.cxx
index f3ddd946f699..81210c8e876c 100644
--- a/vcl/osx/salgdiutils.cxx
+++ b/vcl/osx/salgdiutils.cxx
@@ -46,7 +46,9 @@
static bool bWindowScaling = false;
static float fWindowScale = 1.0f;
-float AquaSalGraphics::GetWindowScaling()
+namespace sal::aqua
+{
+float getWindowScaling()
{
if (!bWindowScaling)
{
@@ -65,38 +67,35 @@ float AquaSalGraphics::GetWindowScaling()
}
return fWindowScale;
}
+} // end aqua
void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
{
- mpFrame = pFrame;
- mbWindow = true;
- mbPrinter = false;
- mbVirDev = false;
+ maShared.mpFrame = pFrame;
+ maShared.mbWindow = true;
+ maShared.mbPrinter = false;
+ maShared.mbVirDev = false;
}
void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, sal_Int32 nDPIX, sal_Int32 nDPIY )
{
- mbWindow = false;
- mbPrinter = true;
- mbVirDev = false;
+ maShared.mbWindow = false;
+ maShared.mbPrinter = true;
+ maShared.mbVirDev = false;
- maContextHolder.set(xContext);
+ maShared.maContextHolder.set(xContext);
mnRealDPIX = nDPIX;
mnRealDPIY = nDPIY;
// a previously set clip path is now invalid
- if( mxClipPath )
- {
- CGPathRelease( mxClipPath );
- mxClipPath = nullptr;
- }
+ maShared.unsetClipPath();
- if (maContextHolder.isSet())
+ if (maShared.maContextHolder.isSet())
{
- CGContextSetFillColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace );
- CGContextSetStrokeColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace );
- CGContextSaveGState( maContextHolder.get() );
- SetState();
+ CGContextSetFillColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
+ CGContextSetStrokeColorSpace( maShared.maContextHolder.get(), GetSalData()->mxRGBSpace );
+ CGContextSaveGState( maShared.maContextHolder.get() );
+ maShared.setState();
}
}
@@ -104,50 +103,46 @@ void AquaSalGraphics::InvalidateContext()
{
UnsetState();
- CGContextRelease(maContextHolder.get());
- CGContextRelease(maBGContextHolder.get());
- CGContextRelease(maCSContextHolder.get());
+ CGContextRelease(maShared.maContextHolder.get());
+ CGContextRelease(maShared.maBGContextHolder.get());
+ CGContextRelease(maShared.maCSContextHolder.get());
- maContextHolder.set(nullptr);
- maCSContextHolder.set(nullptr);
- maBGContextHolder.set(nullptr);
+ maShared.maContextHolder.set(nullptr);
+ maShared.maCSContextHolder.set(nullptr);
+ maShared.maBGContextHolder.set(nullptr);
}
void AquaSalGraphics::UnsetState()
{
- if (maBGContextHolder.isSet())
- {
- CGContextRelease(maBGContextHolder.get());
- maBGContextHolder.set(nullptr);
- }
- if (maCSContextHolder.isSet())
+ if (maShared.maBGContextHolder.isSet())
{
- CGContextRelease(maCSContextHolder.get());
- maBGContextHolder.set(nullptr);
+ CGContextRelease(maShared.maBGContextHolder.get());
+ maShared.maBGContextHolder.set(nullptr);
}
- if (maContextHolder.isSet())
+ if (maShared.maCSContextHolder.isSet())
{
- maContextHolder.restoreState();
- maContextHolder.set(nullptr);
+ CGContextRelease(maShared.maCSContextHolder.get());
+ maShared.maBGContextHolder.set(nullptr);
}
- if( mxClipPath )
+ if (maShared.maContextHolder.isSet())
{
- CGPathRelease( mxClipPath );
- mxClipPath = nullptr;
+ maShared.maContextHolder.restoreState();
+ maShared.maContextHolder.set(nullptr);
}
+ maShared.unsetState();
}
/**
* (re-)create the off-screen maLayer we render everything to if
* necessary: eg. not initialized yet, or it has an incorrect size.
*/
-bool AquaSalGraphics::CheckContext()
+bool AquaSharedAttributes::checkContext()
{
if (mbWindow && mpFrame && (mpFrame->getNSWindow() || Application::IsBitmapRendering()))
{
const unsigned int nWidth = mpFrame->maGeometry.nWidth;
const unsigned int nHeight = mpFrame->maGeometry.nHeight;
- const float fScale = GetWindowScaling();
+ const float fScale = sal::aqua::getWindowScaling();
CGLayerRef rReleaseLayer = nullptr;
// check if a new drawing context is needed (e.g. after a resize)
@@ -218,7 +213,7 @@ bool AquaSalGraphics::CheckContext()
// apply a scale matrix so everything is auto-magically scaled
CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
maContextHolder.saveState();
- SetState();
+ setState();
// re-enable XOR emulation for the new context
if (mpXorEmulation)
@@ -239,19 +234,19 @@ bool AquaSalGraphics::CheckContext()
*/
void AquaSalGraphics::UpdateWindow( NSRect& )
{
- if( !mpFrame )
+ if (!maShared.mpFrame)
{
return;
}
NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
- if (maLayer.isSet() && pContext != nullptr)
+ if (maShared.maLayer.isSet() && pContext != nullptr)
{
CGContextHolder rCGContextHolder([pContext CGContext]);
rCGContextHolder.saveState();
- CGMutablePathRef rClip = mpFrame->getClipPath();
+ CGMutablePathRef rClip = maShared.mpFrame->getClipPath();
if (rClip)
{
CGContextBeginPath(rCGContextHolder.get());
@@ -259,16 +254,16 @@ void AquaSalGraphics::UpdateWindow( NSRect& )
CGContextClip(rCGContextHolder.get());
}
- ApplyXorContext();
+ maShared.applyXorContext();
- const CGSize aSize = maLayer.getSizePoints();
+ const CGSize aSize = maShared.maLayer.getSizePoints();
const CGRect aRect = CGRectMake(0, 0, aSize.width, aSize.height);
- const CGRect aRectPoints = { CGPointZero, maLayer.getSizePixels() };
- CGContextSetBlendMode(maCSContextHolder.get(), kCGBlendModeCopy);
- CGContextDrawLayerInRect(maCSContextHolder.get(), aRectPoints, maLayer.get());
+ const CGRect aRectPoints = { CGPointZero, maShared.maLayer.getSizePixels() };
+ CGContextSetBlendMode(maShared.maCSContextHolder.get(), kCGBlendModeCopy);
+ CGContextDrawLayerInRect(maShared.maCSContextHolder.get(), aRectPoints, maShared.maLayer.get());
- CGImageRef img = CGBitmapContextCreateImage(maCSContextHolder.get());
- CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[mpFrame->getNSWindow() colorSpace] CGColorSpace]);
+ CGImageRef img = CGBitmapContextCreateImage(maShared.maCSContextHolder.get());
+ CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[maShared.mpFrame->getNSWindow() colorSpace] CGColorSpace]);
CGContextSetBlendMode(rCGContextHolder.get(), kCGBlendModeCopy);
CGContextDrawImage(rCGContextHolder.get(), aRect, displayColorSpaceImage);
@@ -279,7 +274,7 @@ void AquaSalGraphics::UpdateWindow( NSRect& )
}
else
{
- SAL_WARN_IF( !mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics" );
+ SAL_WARN_IF(!maShared.mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics");
}
}
diff --git a/vcl/osx/salmacos.cxx b/vcl/osx/salmacos.cxx
index f6403dea2725..fa2520f056a6 100644
--- a/vcl/osx/salmacos.cxx
+++ b/vcl/osx/salmacos.cxx
@@ -96,29 +96,36 @@ bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits
// From salgdicommon.cxx
-void AquaSalGraphics::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcGraphics)
+void AquaGraphicsBackend::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcGraphics)
{
- if (!pSrcGraphics)
- pSrcGraphics = this;
- AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ AquaSharedAttributes* pSrcShared = nullptr;
+
+ if (pSrcGraphics)
+ {
+ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ pSrcShared = &pSrc->getAquaGraphicsBackend()->mrShared;
+ }
+ else
+ pSrcShared = &mrShared;
+
if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 || rPosAry.mnDestHeight <= 0)
return;
- if (!maContextHolder.isSet())
+ if (!mrShared.maContextHolder.isSet())
return;
- SAL_WARN_IF (!pSrc->maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::copyBits() from non-layered graphics this=" << this);
+ SAL_WARN_IF (!pSrcShared->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())
+ if (pSrcShared->maLayer.isSet())
copyScaledArea(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY,
- rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, pSrcGraphics);
+ rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, pSrcShared);
else
{
- ApplyXorContext();
- pSrc->ApplyXorContext();
- std::shared_ptr<SalBitmap> pBitmap = pSrc->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY,
- rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
+ mrShared.applyXorContext();
+ pSrcShared->applyXorContext();
+ std::shared_ptr<SalBitmap> pBitmap = pSrcGraphics->GetImpl()->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY,
+ rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
if (pBitmap)
{
SalTwoRect aPosAry(rPosAry);
@@ -129,34 +136,30 @@ void AquaSalGraphics::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcGraph
}
}
-void AquaSalGraphics::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
+void AquaGraphicsBackend::copyArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
tools::Long nSrcWidth, tools::Long nSrcHeight, bool)
{
- if (!maContextHolder.isSet())
+ if (!mrShared.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);
+ copyScaledArea(nDstX, nDstY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, &mrShared);
}
-void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
- tools::Long nSrcWidth, tools::Long nSrcHeight, SalGraphics *pSrcGraphics)
+void AquaGraphicsBackend::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools::Long nSrcX, tools::Long nSrcY,
+ tools::Long nSrcWidth, tools::Long nSrcHeight, AquaSharedAttributes* pSrcShared)
{
- if (!pSrcGraphics)
- pSrcGraphics = this;
- AquaSalGraphics *pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
-
- SAL_WARN_IF(!maLayer.isSet(), "vcl.quartz",
+ SAL_WARN_IF(!mrShared.maLayer.isSet(), "vcl.quartz",
"AquaSalGraphics::copyScaledArea() without graphics context or for non-layered graphics this=" << this);
- if (!maContextHolder.isSet() || !maLayer.isSet())
+ if (!mrShared.maContextHolder.isSet() || !mrShared.maLayer.isSet())
return;
// Determine scaled geometry of source and target area assuming source and target area have the same scale
- float fScale = maLayer.getScale();
+ float fScale = mrShared.maLayer.getScale();
CGFloat nScaledSourceX = nSrcX * fScale;
CGFloat nScaledSourceY = nSrcY * fScale;
CGFloat nScaledTargetX = nDstX * fScale;
@@ -166,11 +169,11 @@ void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools:
// 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();
+ mrShared.applyXorContext();
+ mrShared.maContextHolder.saveState();
+ CGContextRef xCopyContext = mrShared.maContextHolder.get();
+ if (mrShared.mpXorEmulation && mrShared.mpXorEmulation->IsEnabled())
+ xCopyContext = mrShared.mpXorEmulation->GetTargetContext();
// Set scale matrix of copy context to consider layer scaling
@@ -179,19 +182,19 @@ void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools:
// Creating an additional layer is required for drawing with the required scale and extent at the drawing destination
// thereafter.
- CGLayerHolder aSourceLayerHolder(pSrc->maLayer);
+ CGLayerHolder aSourceLayerHolder(pSrcShared->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())
+ if (pSrcShared->isFlipped())
{
CGContextTranslateCTM(xSourceContext, 0, nScaledSourceHeight);
CGContextScaleCTM(xSourceContext, 1, -1);
- aSrcPoint.y = nScaledSourceY + nScaledSourceHeight - mnHeight * fScale;
+ aSrcPoint.y = nScaledSourceY + nScaledSourceHeight - mrShared.mnHeight * fScale;
}
CGContextSetBlendMode(xSourceContext, kCGBlendModeCopy);
- CGContextDrawLayerAtPoint(xSourceContext, aSrcPoint, pSrc->maLayer.get());
+ CGContextDrawLayerAtPoint(xSourceContext, aSrcPoint, pSrcShared->maLayer.get());
// Copy source area from additional layer to target area
@@ -201,10 +204,11 @@ void AquaSalGraphics::copyScaledArea(tools::Long nDstX, tools::Long nDstY,tools:
// Housekeeping on exit
- maContextHolder.restoreState();
- if (aSourceLayerHolder.get() != maLayer.get())
+ mrShared.maContextHolder.restoreState();
+ if (aSourceLayerHolder.get() != mrShared.maLayer.get())
CGLayerRelease(aSourceLayerHolder.get());
- RefreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight);
+
+ mrShared.refreshRect(nDstX, nDstY, nSrcWidth, nSrcHeight);
}
void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRef xContext, int nBitmapDepth)
@@ -214,61 +218,61 @@ void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const &rLayer, CGContextRe
// Set member variables
InvalidateContext();
- mbWindow = false;
- mbPrinter = false;
- mbVirDev = true;
- maLayer = rLayer;
- mnBitmapDepth = nBitmapDepth;
+ maShared.mbWindow = false;
+ maShared.mbPrinter = false;
+ maShared.mbVirDev = true;
+ maShared.maLayer = rLayer;
+ maShared.mnBitmapDepth = nBitmapDepth;
- // Get size and scale from layer if set else from bitmap and AquaSalGraphics::GetWindowScaling(), which is used to determine
+ // Get size and scale from layer if set else from bitmap and sal::aqua::getWindowScaling(), which is used to determine
// scaling for direct graphics output too
CGSize aSize;
float fScale;
- if (maLayer.isSet())
+ if (maShared.maLayer.isSet())
{
- maContextHolder.set(CGLayerGetContext(maLayer.get()));
- aSize = CGLayerGetSize(maLayer.get());
- fScale = maLayer.getScale();
+ maShared.maContextHolder.set(CGLayerGetContext(maShared.maLayer.get()));
+ aSize = CGLayerGetSize(maShared.maLayer.get());
+ fScale = maShared.maLayer.getScale();
}
else
{
- maContextHolder.set(xContext);
+ maShared.maContextHolder.set(xContext);
if (!xContext)
return;
aSize.width = CGBitmapContextGetWidth(xContext);
aSize.height = CGBitmapContextGetHeight(xContext);
- fScale = GetWindowScaling();
+ fScale = sal::aqua::getWindowScaling();
}
- mnWidth = aSize.width / fScale;
- mnHeight = aSize.height / fScale;
+ maShared.mnWidth = aSize.width / fScale;
+ maShared.mnHeight = aSize.height / fScale;
// Set color space for fill and stroke
CGColorSpaceRef aColorSpace = GetSalData()->mxRGBSpace;
- CGContextSetFillColorSpace(maContextHolder.get(), aColorSpace);
- CGContextSetStrokeColorSpace(maContextHolder.get(), aColorSpace);
+ CGContextSetFillColorSpace(maShared.maContextHolder.get(), aColorSpace);
+ CGContextSetStrokeColorSpace(maShared.maContextHolder.get(), aColorSpace);
// Apply scale matrix to virtual device graphics
- CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
+ CGContextScaleCTM(maShared.maContextHolder.get(), fScale, fScale);
// Apply XOR emulation if required
- if (mpXorEmulation)
+ if (maShared.mpXorEmulation)
{
- mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
- if (mpXorEmulation->IsEnabled())
- maContextHolder.set(mpXorEmulation->GetMaskContext());
+ 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());
}
// Housekeeping on exit
- maContextHolder.saveState();
- SetState();
+ maShared.maContextHolder.saveState();
+ maShared.setState();
SAL_INFO("vcl.quartz", "SetVirDevGraphics() this=" << this <<
- " (" << mnWidth << "x" << mnHeight << ") fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth);
+ " (" << maShared.mnWidth << "x" << maShared.mnHeight << ") fScale=" << fScale << " mnBitmapDepth=" << maShared.mnBitmapDepth);
}
// From salvd.cxx
@@ -277,7 +281,7 @@ void AquaSalVirtualDevice::Destroy()
{
SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::Destroy() this=" << this << " mbForeignContext=" << mbForeignContext );
- if( mbForeignContext )
+ if (mbForeignContext)
{
// Do not delete mxContext that we have received from outside VCL
maLayer.set(nullptr);
@@ -327,11 +331,11 @@ bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY)
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
+ // sal::aqua::getWindowScaling(), which is used to determine scaling for direct graphics output too
mnWidth = nDX;
mnHeight = nDY;
- fScale = AquaSalGraphics::GetWindowScaling();
+ fScale = sal::aqua::getWindowScaling();
CGColorSpaceRef aColorSpace;
uint32_t nFlags;
if (mnBitmapDepth && (mnBitmapDepth < 16))
diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx
index bc132ee88d16..589feec62208 100644
--- a/vcl/osx/salnativewidgets.cxx
+++ b/vcl/osx/salnativewidgets.cxx
@@ -232,8 +232,8 @@ UInt32 AquaSalGraphics::getState(ControlState nState)
// there are non key windows which are children of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs.
// To handle these windows correctly, parent frame's key window state is considered here additionally.
- const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]
- || mpFrame->mpParent == nullptr || [mpFrame->mpParent->getNSWindow() isKeyWindow];
+ const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow]
+ || maShared.mpFrame->mpParent == nullptr || [maShared.mpFrame->mpParent->getNSWindow() isKeyWindow];
if (!(nState & ControlState::ENABLED) || !bDrawActive)
{
return kThemeStateInactive;
@@ -245,7 +245,7 @@ UInt32 AquaSalGraphics::getState(ControlState nState)
UInt32 AquaSalGraphics::getTrackState(ControlState nState)
{
- const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
+ const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow];
if (!(nState & ControlState::ENABLED) || !bDrawActive)
return kThemeTrackInactive;
return kThemeTrackActive;
@@ -260,9 +260,9 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
const Color&)
{
bool bOK = false;
- if (!CheckContext())
+ if (!maShared.checkContext())
return false;
- maContextHolder.saveState();
+ maShared.maContextHolder.saveState();
tools::Rectangle buttonRect = rControlRegion;
HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
switch (nType)
@@ -274,15 +274,15 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aMenuItemDrawInfo.version = 0;
aMenuItemDrawInfo.state = kThemeMenuActive;
aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
- HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
#else
if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
{
- const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
+ const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow];
CGFloat unifiedHeight = rControlRegion.GetHeight();
CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(),
rControlRegion.GetWidth(), rControlRegion.GetHeight());
- CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(),
+ CUIDraw([NSWindow coreUIRenderer], drawRect, maShared.maContextHolder.get(),
reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
@"kCUIWidgetWindowFrame",
@"widget",
@@ -305,7 +305,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aMenuItemDrawInfo.version = 0;
aMenuItemDrawInfo.state = kThemeMenuActive;
aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
- HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
}
#endif
bOK = true;
@@ -322,8 +322,8 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.size.width += 2;
rc.size.height += 2;
- HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
- CGContextFillRect(maContextHolder.get(), rc);
+ HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
+ CGContextFillRect(maShared.maContextHolder.get(), rc);
bOK = true;
}
break;
@@ -335,8 +335,8 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive;
rc.size.width += 2;
rc.size.height += 2;
- HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
- CGContextFillRect(maContextHolder.get(), rc);
+ HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
+ CGContextFillRect(maShared.maContextHolder.get(), rc);
bOK = true;
}
break;
@@ -369,11 +369,11 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
// repaints the background of the pull down menu
- HIThemeDrawMenuBackground(&rc, &aMenuInfo,maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawMenuBackground(&rc, &aMenuInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
// repaints the item either blue (selected) and/or grey (active only)
- HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc);
+ HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, &rc);
bOK = true;
}
else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
@@ -397,7 +397,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed;
UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode;
CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
- HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
if (cfString)
CFRelease(cfString);
bOK = true;
@@ -449,7 +449,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
if (nState & ControlState::FOCUSED)
aPushInfo.adornment |= kThemeAdornmentFocus;
- HIThemeDrawButton(&rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aPushInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK = true;
}
break;
@@ -485,7 +485,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.size.height = RADIO_BUTTON_SMALL_SIZE;
rc.origin.x += FOCUS_RING_WIDTH;
rc.origin.y += FOCUS_RING_WIDTH;
- HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK = true;
}
break;
@@ -511,7 +511,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
default:
break;
}
- HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK = true;
}
break;
@@ -538,7 +538,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aTrackInfo.enableState = kThemeTrackActive;
aTrackInfo.filler1 = 0;
aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent() * 10.0);
- HIThemeDrawTrack(&aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawTrack(&aTrackInfo, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
break;
@@ -562,7 +562,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aSlideInfo.thumbDir = kThemeThumbUpward;
aSlideInfo.pressState = 0;
aTrackDraw.trackInfo.slider = aSlideInfo;
- HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawTrack(&aTrackDraw, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
}
@@ -597,7 +597,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
if (pScrollbarVal->mnThumbState & ControlState::PRESSED)
aScrollInfo.pressState = kThemeThumbPressed;
aTrackDraw.trackInfo.scrollbar = aScrollInfo;
- HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawTrack(&aTrackDraw, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
}
@@ -617,7 +617,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.origin.y -= TAB_HEIGHT / 2;
rc.size.height += TAB_HEIGHT / 2;
rc.size.width -= 2;
- HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
break;
@@ -661,7 +661,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast)
aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
}
- HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK=true;
}
break;
@@ -683,10 +683,10 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
// fill a white background, because HIThemeDrawFrame only draws the border
- CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
- HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ CGContextFillRect(maShared.maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
if (nState & ControlState::FOCUSED)
- HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawFocusRect(&rc, true, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
break;
@@ -705,7 +705,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.size.height = COMBOBOX_HEIGHT;
rc.origin.x += FOCUS_RING_WIDTH;
rc.origin.y += FOCUS_RING_WIDTH;
- HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aComboInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK = true;
}
break;
@@ -726,7 +726,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.size.height = LISTBOX_HEIGHT;
rc.origin.x += FOCUS_RING_WIDTH;
rc.origin.y += FOCUS_RING_WIDTH;
- HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aListInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
bOK = true;
break;
case ControlPart::ListboxWindow:
@@ -735,7 +735,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aTextDrawInfo.kind = kHIThemeFrameListBox;
aTextDrawInfo.state = kThemeStateActive;
aTextDrawInfo.isFocused = false;
- HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
break;
default:
@@ -760,10 +760,10 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
// fill a white background, because HIThemeDrawFrame only draws the border
- CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
- HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ CGContextFillRect(maShared.maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
if (nState & ControlState::FOCUSED)
- HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawFocusRect(&rc, true, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
// buttons
@@ -808,7 +808,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
rc.origin.y -= 1;
rc.size.width = SPIN_BUTTON_WIDTH;
rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT;
- HIThemeDrawButton(&rc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
+ HIThemeDrawButton(&rc, &aSpinInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
}
bOK = true;
}
@@ -824,14 +824,14 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
// strange effects start to happen when HIThemeDrawFrame meets the border of the window.
// These can be avoided by clipping to the boundary of the frame (see issue 84756)
- if (rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight - 3)
+ if (rc.origin.y + rc.size.height >= maShared.mpFrame->maGeometry.nHeight - 3)
{
CGMutablePathRef rPath = CGPathCreateMutable();
CGPathAddRect(rPath, nullptr,
- CGRectMake(0, 0, mpFrame->maGeometry.nWidth - 1, mpFrame->maGeometry.nHeight - 1));
- CGContextBeginPath(maContextHolder.get());
- CGContextAddPath(maContextHolder.get(), rPath);
- CGContextClip(maContextHolder.get());
+ CGRectMake(0, 0, maShared.mpFrame->maGeometry.nWidth - 1, maShared.mpFrame->maGeometry.nHeight - 1));
+ CGContextBeginPath(maShared.maContextHolder.get());
+ CGContextAddPath(maShared.maContextHolder.get(), rPath);
+ CGContextClip(maShared.maContextHolder.get());
CGPathRelease(rPath);
}
HIThemeFrameDrawInfo aTextDrawInfo;
@@ -839,7 +839,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
aTextDrawInfo.kind = kHIThemeFrameListBox;
aTextDrawInfo.state = kThemeStateActive;
aTextDrawInfo.isFocused = false;
- HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
bOK = true;
}
}
@@ -854,7 +854,7 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
default:
break;
}
- maContextHolder.restoreState();
+ maShared.maContextHolder.restoreState();
// in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
// faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
@@ -864,15 +864,15 @@ bool AquaSalGraphics::drawNativeControl(ControlType nType,
if (nType == ControlType::WindowBackground)
{
CGRect aRect = {{0, 0}, {0, 0}};
- if (mxClipPath)
- aRect = CGPathGetBoundingBox(mxClipPath);
+ if (maShared.mxClipPath)
+ aRect = CGPathGetBoundingBox(maShared.mxClipPath);
if (aRect.size.width != 0 && aRect.size.height != 0)
buttonRect.Intersection(tools::Rectangle(Point(static_cast<tools::Long>(aRect.origin.x),
static_cast<tools::Long>(aRect.origin.y)),
Size(static_cast<tools::Long>(aRect.size.width),
static_cast<tools::Long>(aRect.size.height))));
}
- RefreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
+ maShared.refreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
return bOK;
}
diff --git a/vcl/quartz/AquaGraphicsBackend.cxx b/vcl/quartz/AquaGraphicsBackend.cxx
new file mode 100644
index 000000000000..0aa6042f7eb4
--- /dev/null
+++ b/vcl/quartz/AquaGraphicsBackend.cxx
@@ -0,0 +1,1355 @@
+/* -*- 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 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cassert>
+#include <cstring>
+#include <numeric>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <osl/endian.h>
+#include <osl/file.hxx>
+#include <sal/types.h>
+#include <tools/long.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <fontsubset.hxx>
+#include <quartz/salbmp.h>
+#ifdef MACOSX
+#include <quartz/salgdi.h>
+#endif
+#include <quartz/utils.h>
+#ifdef IOS
+#include "saldatabasic.hxx"
+#endif
+#include <sft.hxx>
+
+using namespace vcl;
+
+namespace
+{
+const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5);
+
+static void AddPolygonToPath(CGMutablePathRef xPath, const basegfx::B2DPolygon& rPolygon,
+ bool bClosePath, bool bPixelSnap, bool bLineDraw)
+{
+ // short circuit if there is nothing to do
+ const int nPointCount = rPolygon.count();
+ if (nPointCount <= 0)
+ {
+ return;
+ }
+
+ const bool bHasCurves = rPolygon.areControlPointsUsed();
+ for (int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++)
+ {
+ int nClosedIdx = nPointIdx;
+ if (nPointIdx >= nPointCount)
+ {
+ // prepare to close last curve segment if needed
+ if (bClosePath && (nPointIdx == nPointCount))
+ {
+ nClosedIdx = 0;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ basegfx::B2DPoint aPoint = rPolygon.getB2DPoint(nClosedIdx);
+
+ if (bPixelSnap)
+ {
+ // snap device coordinates to full pixels
+ aPoint.setX(basegfx::fround(aPoint.getX()));
+ aPoint.setY(basegfx::fround(aPoint.getY()));
+ }
+
+ if (bLineDraw)
+ {
+ aPoint += aHalfPointOfs;
+ }
+ if (!nPointIdx)
+ {
+ // first point => just move there
+ CGPathMoveToPoint(xPath, nullptr, aPoint.getX(), aPoint.getY());
+ continue;
+ }
+
+ bool bPendingCurve = false;
+ if (bHasCurves)
+ {
+ bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx);
+ bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx);
+ }
+
+ if (!bPendingCurve) // line segment
+ {
+ CGPathAddLineToPoint(xPath, nullptr, aPoint.getX(), aPoint.getY());
+ }
+ else // cubic bezier segment
+ {
+ basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint(nPrevIdx);
+ basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint(nClosedIdx);
+ if (bLineDraw)
+ {
+ aCP1 += aHalfPointOfs;
+ aCP2 += aHalfPointOfs;
+ }
+ CGPathAddCurveToPoint(xPath, nullptr, aCP1.getX(), aCP1.getY(), aCP2.getX(),
+ aCP2.getY(), aPoint.getX(), aPoint.getY());
+ }
+ }
+
+ if (bClosePath)
+ {
+ CGPathCloseSubpath(xPath);
+ }
+}
+
+static void alignLinePoint(const Point* i_pIn, float& o_fX, float& o_fY)
+{
+ o_fX = static_cast<float>(i_pIn->getX()) + 0.5;
+ o_fY = static_cast<float>(i_pIn->getY()) + 0.5;
+}
+
+static void getBoundRect(sal_uInt32 nPoints, const Point* pPtAry, tools::Long& rX, tools::Long& rY,
+ tools::Long& rWidth, tools::Long& rHeight)
+{
+ tools::Long nX1 = pPtAry->getX();
+ tools::Long nX2 = nX1;
+ tools::Long nY1 = pPtAry->getY();
+ tools::Long nY2 = nY1;
+
+ for (sal_uInt32 n = 1; n < nPoints; n++)
+ {
+ if (pPtAry[n].getX() < nX1)
+ {
+ nX1 = pPtAry[n].getX();
+ }
+ else if (pPtAry[n].getX() > nX2)
+ {
+ nX2 = pPtAry[n].getX();
+ }
+ if (pPtAry[n].getY() < nY1)
+ {
+ nY1 = pPtAry[n].getY();
+ }
+ else if (pPtAry[n].getY() > nY2)
+ {
+ nY2 = pPtAry[n].getY();
+ }
+ }
+ rX = nX1;
+ rY = nY1;
+ rWidth = nX2 - nX1 + 1;
+ rHeight = nY2 - nY1 + 1;
+}
+
+static Color ImplGetROPColor(SalROPColor nROPColor)
+{
+ Color nColor;
+ if (nROPColor == SalROPColor::N0)
+ {
+ nColor = Color(0, 0, 0);
+ }
+ else
+ {
+ nColor = Color(255, 255, 255);
+ }
+ return nColor;
+}
+
+static void drawPattern50(void*, CGContextRef rContext)
+{
+ static const CGRect aRects[2] = { { { 0, 0 }, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } };
+ CGContextAddRects(rContext, aRects, 2);
+ CGContextFillPath(rContext);
+}
+}
+
+AquaGraphicsBackend::AquaGraphicsBackend(AquaSharedAttributes& rShared)
+ : mrShared(rShared)
+{
+}
+
+AquaGraphicsBackend::~AquaGraphicsBackend() {}
+
+void AquaGraphicsBackend::Init() {}
+void AquaGraphicsBackend::freeResources() {}
+
+bool AquaGraphicsBackend::setClipRegion(vcl::Region const& rRegion)
+{
+ // release old clip path
+ mrShared.unsetClipPath();
+ mrShared.mxClipPath = CGPathCreateMutable();
+
+ // set current path, either as polypolgon or sequence of rectangles
+ RectangleVector aRectangles;
+ rRegion.GetRegionRectangles(aRectangles);
+
+ for (const auto& rRect : aRectangles)
+ {
+ const tools::Long nW(rRect.Right() - rRect.Left() + 1); // uses +1 logic in original
+
+ if (nW)
+ {
+ const tools::Long nH(rRect.Bottom() - rRect.Top() + 1); // uses +1 logic in original
+
+ if (nH)
+ {
+ const CGRect aRect = CGRectMake(rRect.Left(), rRect.Top(), nW, nH);
+ CGPathAddRect(mrShared.mxClipPath, nullptr, aRect);
+ }
+ }
+ }
+ // set the current path as clip region
+ if (mrShared.checkContext())
+ mrShared.setState();
+
+ return true;
+}
+
+void AquaGraphicsBackend::ResetClipRegion()
+{
+ // release old path and indicate no clipping
+ mrShared.unsetClipPath();
+
+ if (mrShared.checkContext())
+ {
+ mrShared.setState();
+ }
+}
+
+sal_uInt16 AquaGraphicsBackend::GetBitCount() const
+{
+ sal_uInt16 nBits = mrShared.mnBitmapDepth ? mrShared.mnBitmapDepth : 32; //24;
+ return nBits;
+}
+
+tools::Long AquaGraphicsBackend::GetGraphicsWidth() const
+{
+ tools::Long width = 0;
+ if (mrShared.maContextHolder.isSet()
+ && (
+#ifndef IOS
+ mrShared.mbWindow ||
+#endif
+ mrShared.mbVirDev))
+ {
+ width = mrShared.mnWidth;
+ }
+
+#ifndef IOS
+ if (width == 0)
+ {
+ if (mrShared.mbWindow && mrShared.mpFrame)
+ {
+ width = mrShared.mpFrame->maGeometry.nWidth;
+ }
+ }
+#endif
+ return width;
+}
+
+void AquaGraphicsBackend::SetLineColor()
+{
+ mrShared.maLineColor.SetAlpha(0.0); // transparent
+ if (mrShared.checkContext())
+ {
+ CGContextSetRGBStrokeColor(mrShared.maContextHolder.get(), mrShared.maLineColor.GetRed(),
+ mrShared.maLineColor.GetGreen(), mrShared.maLineColor.GetBlue(),
+ mrShared.maLineColor.GetAlpha());
+ }
+}
+
+void AquaGraphicsBackend::SetLineColor(Color nColor)
+{
+ mrShared.maLineColor = RGBAColor(nColor);
+ if (mrShared.checkContext())
+ {
+ CGContextSetRGBStrokeColor(mrShared.maContextHolder.get(), mrShared.maLineColor.GetRed(),
+ mrShared.maLineColor.GetGreen(), mrShared.maLineColor.GetBlue(),
+ mrShared.maLineColor.GetAlpha());
+ }
+}
+
+void AquaGraphicsBackend::SetFillColor()
+{
+ mrShared.maFillColor.SetAlpha(0.0); // transparent
+ if (mrShared.checkContext())
+ {
+ CGContextSetRGBFillColor(mrShared.maContextHolder.get(), mrShared.maFillColor.GetRed(),
+ mrShared.maFillColor.GetGreen(), mrShared.maFillColor.GetBlue(),
+ mrShared.maFillColor.GetAlpha());
+ }
+}
+
+void AquaGraphicsBackend::SetFillColor(Color nColor)
+{
+ mrShared.maFillColor = RGBAColor(nColor);
+ if (mrShared.checkContext())
+ {
+ CGContextSetRGBFillColor(mrShared.maContextHolder.get(), mrShared.maFillColor.GetRed(),
+ mrShared.maFillColor.GetGreen(), mrShared.maFillColor.GetBlue(),
+ mrShared.maFillColor.GetAlpha());
+ }
+}
+
+void AquaGraphicsBackend::SetXORMode(bool bSet, bool bInvertOnly)
+{
+ // return early if XOR mode remains unchanged
+ if (mrShared.mbPrinter)
+ {
+ return;
+ }
+ if (!bSet && mrShared.mnXorMode == 2)
+ {
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeNormal);
+ mrShared.mnXorMode = 0;
+ return;
+ }
+ else if (bSet && bInvertOnly && mrShared.mnXorMode == 0)
+ {
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ mrShared.mnXorMode = 2;
+ return;
+ }
+
+ if (!mrShared.mpXorEmulation && !bSet)
+ {
+ return;
+ }
+ if (mrShared.mpXorEmulation && bSet == mrShared.mpXorEmulation->IsEnabled())
+ {
+ return;
+ }
+ if (!mrShared.checkContext())
+ {
+ return;
+ }
+ // prepare XOR emulation
+ if (!mrShared.mpXorEmulation)
+ {
+ mrShared.mpXorEmulation = std::make_unique<XorEmulation>();
+ mrShared.mpXorEmulation->SetTarget(mrShared.mnWidth, mrShared.mnHeight,
+ mrShared.mnBitmapDepth, mrShared.maContextHolder.get(),
+ mrShared.maLayer.get());
+ }
+
+ // change the XOR mode
+ if (bSet)
+ {
+ mrShared.mpXorEmulation->Enable();
+ mrShared.maContextHolder.set(mrShared.mpXorEmulation->GetMaskContext());
+ mrShared.mnXorMode = 1;
+ }
+ else
+ {
+ mrShared.mpXorEmulation->UpdateTarget();
+ mrShared.mpXorEmulation->Disable();
+ mrShared.maContextHolder.set(mrShared.mpXorEmulation->GetTargetContext());
+ mrShared.mnXorMode = 0;
+ }
+}
+
+void AquaGraphicsBackend::SetROPFillColor(SalROPColor nROPColor)
+{
+ if (!mrShared.mbPrinter)
+ {
+ SetFillColor(ImplGetROPColor(nROPColor));
+ }
+}
+
+void AquaGraphicsBackend::SetROPLineColor(SalROPColor nROPColor)
+{
+ if (!mrShared.mbPrinter)
+ {
+ SetLineColor(ImplGetROPColor(nROPColor));
+ }
+}
+
+void AquaGraphicsBackend::drawPixelImpl(tools::Long nX, tools::Long nY, const RGBAColor& rColor)
+{
+ if (!mrShared.checkContext())
+ return;
+
+ // overwrite the fill color
+ CGContextSetFillColor(mrShared.maContextHolder.get(), rColor.AsArray());
+ // draw 1x1 rect, there is no pixel drawing in Quartz
+ const CGRect aDstRect = CGRectMake(nX, nY, 1, 1);
+ CGContextFillRect(mrShared.maContextHolder.get(), aDstRect);
+
+ refreshRect(aDstRect);
+
+ // reset the fill color
+ CGContextSetFillColor(mrShared.maContextHolder.get(), mrShared.maFillColor.AsArray());
+}
+
+void AquaGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY)
+{
+ // draw pixel with current line color
+ drawPixelImpl(nX, nY, mrShared.maLineColor);
+}
+
+void AquaGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color nColor)
+{
+ const RGBAColor aPixelColor(nColor);
+ drawPixelImpl(nX, nY, aPixelColor);
+}
+
+void AquaGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2,
+ tools::Long nY2)
+{
+ if (nX1 == nX2 && nY1 == nY2)
+ {
+ // #i109453# platform independent code expects at least one pixel to be drawn
+ drawPixel(nX1, nY1);
+ return;
+ }
+
+ if (!mrShared.checkContext())
+ return;
+
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), float(nX1) + 0.5, float(nY1) + 0.5);
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), float(nX2) + 0.5, float(nY2) + 0.5);
+ CGContextDrawPath(mrShared.maContextHolder.get(), kCGPathStroke);
+
+ tools::Rectangle aRefreshRect(nX1, nY1, nX2, nY2);
+ (void)aRefreshRect;
+ // Is a call to RefreshRect( aRefreshRect ) missing here?
+}
+
+void AquaGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight)
+{
+ if (!mrShared.checkContext())
+ return;
+
+ CGRect aRect = CGRectMake(nX, nY, nWidth, nHeight);
+ if (mrShared.isPenVisible())
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ aRect.size.width -= 1;
+ aRect.size.height -= 1;
+ }
+
+ if (mrShared.isBrushVisible())
+ {
+ CGContextFillRect(mrShared.maContextHolder.get(), aRect);
+ }
+ if (mrShared.isPenVisible())
+ {
+ CGContextStrokeRect(mrShared.maContextHolder.get(), aRect);
+ }
+ mrShared.refreshRect(nX, nY, nWidth, nHeight);
+}
+
+void AquaGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPointArray)
+{
+ if (nPoints < 1)
+ return;
+
+ if (!mrShared.checkContext())
+ return;
+
+ tools::Long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect(nPoints, pPointArray, nX, nY, nWidth, nHeight);
+
+ float fX, fY;
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ alignLinePoint(pPointArray, fX, fY);
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), fX, fY);
+ pPointArray++;
+
+ for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPointArray++)
+ {
+ alignLinePoint(pPointArray, fX, fY);
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), fX, fY);
+ }
+ CGContextStrokePath(mrShared.maContextHolder.get());
+
+ mrShared.refreshRect(nX, nY, nWidth, nHeight);
+}
+
+void AquaGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPointArray)
+{
+ if (nPoints <= 1)
+ return;
+
+ if (!mrShared.checkContext())
+ return;
+
+ tools::Long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect(nPoints, pPointArray, nX, nY, nWidth, nHeight);
+
+ CGPathDrawingMode eMode;
+ if (mrShared.isBrushVisible() && mrShared.isPenVisible())
+ {
+ eMode = kCGPathEOFillStroke;
+ }
+ else if (mrShared.isPenVisible())
+ {
+ eMode = kCGPathStroke;
+ }
+ else if (mrShared.isBrushVisible())
+ {
+ eMode = kCGPathEOFill;
+ }
+ else
+ {
+ SAL_WARN("vcl.quartz", "Neither pen nor brush visible");
+ return;
+ }
+
+ CGContextBeginPath(mrShared.maContextHolder.get());
+
+ if (mrShared.isPenVisible())
+ {
+ float fX, fY;
+ alignLinePoint(pPointArray, fX, fY);
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), fX, fY);
+ pPointArray++;
+ for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPointArray++)
+ {
+ alignLinePoint(pPointArray, fX, fY);
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), fX, fY);
+ }
+ }
+ else
+ {
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), pPointArray->getX(),
+ pPointArray->getY());
+ pPointArray++;
+ for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPointArray++)
+ {
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), pPointArray->getX(),
+ pPointArray->getY());
+ }
+ }
+
+ CGContextClosePath(mrShared.maContextHolder.get());
+ CGContextDrawPath(mrShared.maContextHolder.get(), eMode);
+
+ mrShared.refreshRect(nX, nY, nWidth, nHeight);
+}
+
+void AquaGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints,
+ const Point** ppPtAry)
+{
+ if (nPolyCount <= 0)
+ return;
+
+ if (!mrShared.checkContext())
+ return;
+
+ // find bound rect
+ tools::Long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0;
+
+ getBoundRect(pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight);
+
+ for (sal_uInt32 n = 1; n < nPolyCount; n++)
+ {
+ tools::Long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight;
+ getBoundRect(pPoints[n], ppPtAry[n], nX, nY, nW, nH);
+ if (nX < leftX)
+ {
+ maxWidth += leftX - nX;
+ leftX = nX;
+ }
+ if (nY < topY)
+ {
+ maxHeight += topY - nY;
+ topY = nY;
+ }
+ if (nX + nW > leftX + maxWidth)
+ {
+ maxWidth = nX + nW - leftX;
+ }
+ if (nY + nH > topY + maxHeight)
+ {
+ maxHeight = nY + nH - topY;
+ }
+ }
+
+ // prepare drawing mode
+ CGPathDrawingMode eMode;
+ if (mrShared.isBrushVisible() && mrShared.isPenVisible())
+ {
+ eMode = kCGPathEOFillStroke;
+ }
+ else if (mrShared.isPenVisible())
+ {
+ eMode = kCGPathStroke;
+ }
+ else if (mrShared.isBrushVisible())
+ {
+ eMode = kCGPathEOFill;
+ }
+ else
+ {
+ SAL_WARN("vcl.quartz", "Neither pen nor brush visible");
+ return;
+ }
+
+ // convert to CGPath
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ if (mrShared.isPenVisible())
+ {
+ for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++)
+ {
+ const sal_uInt32 nPoints = pPoints[nPoly];
+ if (nPoints > 1)
+ {
+ const Point* pPtAry = ppPtAry[nPoly];
+ float fX, fY;
+
+ alignLinePoint(pPtAry, fX, fY);
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), fX, fY);
+ pPtAry++;
+
+ for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++)
+ {
+ alignLinePoint(pPtAry, fX, fY);
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), fX, fY);
+ }
+ CGContextClosePath(mrShared.maContextHolder.get());
+ }
+ }
+ }
+ else
+ {
+ for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++)
+ {
+ const sal_uInt32 nPoints = pPoints[nPoly];
+ if (nPoints > 1)
+ {
+ const Point* pPtAry = ppPtAry[nPoly];
+ CGContextMoveToPoint(mrShared.maContextHolder.get(), pPtAry->getX(),
+ pPtAry->getY());
+ pPtAry++;
+ for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++)
+ {
+ CGContextAddLineToPoint(mrShared.maContextHolder.get(), pPtAry->getX(),
+ pPtAry->getY());
+ }
+ CGContextClosePath(mrShared.maContextHolder.get());
+ }
+ }
+ }
+
+ CGContextDrawPath(mrShared.maContextHolder.get(), eMode);
+
+ mrShared.refreshRect(leftX, topY, maxWidth, maxHeight);
+}
+
+bool AquaGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ double fTransparency)
+{
+#ifdef IOS
+ if (!mrShared.maContextHolder.isSet())
+ return true;
+#endif
+
+ // short circuit if there is nothing to do
+ if (rPolyPolygon.count() == 0)
+ return true;
+
+ // ignore invisible polygons
+ if ((fTransparency >= 1.0) || (fTransparency < 0))
+ return true;
+
+ // Fallback: Transform to DeviceCoordinates
+ basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+ aPolyPolygon.transform(rObjectToDevice);
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+ // tdf#120252 Use the correct, already transformed PolyPolygon (as long as
+ // the transformation is not used here...)
+ for (auto const& rPolygon : aPolyPolygon)
+ {
+ AddPolygonToPath(xPath, rPolygon, true, !getAntiAlias(), mrShared.isPenVisible());
+ }
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox(xPath);
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if (aRefreshRect.size.width > 0.125 || aRefreshRect.size.height > 0.125)
+ {
+ // prepare drawing mode
+ CGPathDrawingMode eMode;
+ if (mrShared.isBrushVisible() && mrShared.isPenVisible())
+ {
+ eMode = kCGPathEOFillStroke;
+ }
+ else if (mrShared.isPenVisible())
+ {
+ eMode = kCGPathStroke;
+ }
+ else if (mrShared.isBrushVisible())
+ {
+ eMode = kCGPathEOFill;
+ }
+ else
+ {
+ SAL_WARN("vcl.quartz", "Neither pen nor brush visible");
+ CGPathRelease(xPath);
+ return true;
+ }
+
+ // use the path to prepare the graphics context
+ mrShared.maContextHolder.saveState();
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ CGContextAddPath(mrShared.maContextHolder.get(), xPath);
+
+ // draw path with antialiased polygon
+ CGContextSetShouldAntialias(mrShared.maContextHolder.get(), getAntiAlias());
+ CGContextSetAlpha(mrShared.maContextHolder.get(), 1.0 - fTransparency);
+ CGContextDrawPath(mrShared.maContextHolder.get(), eMode);
+ mrShared.maContextHolder.restoreState();
+
+ // mark modified rectangle as updated
+ refreshRect(aRefreshRect);
+ }
+
+ CGPathRelease(xPath);
+
+ return true;
+}
+
+bool AquaGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
+ const basegfx::B2DPolygon& rPolyLine, double fTransparency,
+ double fLineWidth,
+ const std::vector<double>* pStroke, // MM01
+ basegfx::B2DLineJoin eLineJoin,
+ css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
+ bool bPixelSnapHairline)
+{
+ // MM01 check done for simple reasons
+ if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
+ {
+ return true;
+ }
+
+#ifdef IOS
+ if (!mrShared.checkContext())
+ return false;
+#endif
+
+ // tdf#124848 get correct LineWidth in discrete coordinates,
+ if (fLineWidth == 0) // hairline
+ fLineWidth = 1.0;
+ else // Adjust line width for object-to-device scale.
+ fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
+
+ // #i101491# Aqua does not support B2DLineJoin::NONE; return false to use
+ // the fallback (own geometry preparation)
+ // #i104886# linejoin-mode and thus the above only applies to "fat" lines
+ if ((basegfx::B2DLineJoin::NONE == eLineJoin) && (fLineWidth > 1.3))
+ return false;
+
+ // MM01 need to do line dashing as fallback stuff here now
+ const double fDotDashLength(
+ nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+ const bool bStrokeUsed(0.0 != fDotDashLength);
+ assert(!bStrokeUsed || (bStrokeUsed && pStroke));
+ basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+ if (bStrokeUsed)
+ {
+ // apply LineStyle
+ basegfx::utils::applyLineDashing(rPolyLine, // source
+ *pStroke, // pattern
+ &aPolyPolygonLine, // target for lines
+ nullptr, // target for gaps
+ fDotDashLength); // full length if available
+ }
+ else
+ {
+ // no line dashing, just copy
+ aPolyPolygonLine.append(rPolyLine);
+ }
+
+ // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
+ aPolyPolygonLine.transform(rObjectToDevice);
+ if (bPixelSnapHairline)
+ {
+ aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
+ }
+
+ // setup line attributes
+ CGLineJoin aCGLineJoin = kCGLineJoinMiter;
+ switch (eLineJoin)
+ {
+ case basegfx::B2DLineJoin::NONE:
+ aCGLineJoin = /*TODO?*/ kCGLineJoinMiter;
+ break;
+ case basegfx::B2DLineJoin::Bevel:
+ aCGLineJoin = kCGLineJoinBevel;
+ break;
+ case basegfx::B2DLineJoin::Miter:
+ aCGLineJoin = kCGLineJoinMiter;
+ break;
+ case basegfx::B2DLineJoin::Round:
+ aCGLineJoin = kCGLineJoinRound;
+ break;
+ }
+ // convert miter minimum angle to miter limit
+ CGFloat fCGMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0);
+ // setup cap attribute
+ CGLineCap aCGLineCap(kCGLineCapButt);
+
+ switch (eLineCap)
+ {
+ default: // css::drawing::LineCap_BUTT:
+ {
+ aCGLineCap = kCGLineCapButt;
+ break;
+ }
+ case css::drawing::LineCap_ROUND:
+ {
+ aCGLineCap = kCGLineCapRound;
+ break;
+ }
+ case css::drawing::LineCap_SQUARE:
+ {
+ aCGLineCap = kCGLineCapSquare;
+ break;
+ }
+ }
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+
+ // MM01 todo - I assume that this is OKAY to be done in one run for quartz
+ // but this NEEDS to be checked/verified
+ for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+ {
+ const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+ AddPolygonToPath(xPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true);
+ }
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox(xPath);
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if ((aRefreshRect.size.width > 0.125) || (aRefreshRect.size.height > 0.125))
+ {
+ // use the path to prepare the graphics context
+ mrShared.maContextHolder.saveState();
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ CGContextAddPath(mrShared.maContextHolder.get(), xPath);
+ // draw path with antialiased line
+ CGContextSetShouldAntialias(mrShared.maContextHolder.get(), getAntiAlias());
+ CGContextSetAlpha(mrShared.maContextHolder.get(), 1.0 - fTransparency);
+ CGContextSetLineJoin(mrShared.maContextHolder.get(), aCGLineJoin);
+ CGContextSetLineCap(mrShared.maContextHolder.get(), aCGLineCap);
+ CGContextSetLineWidth(mrShared.maContextHolder.get(), fLineWidth);
+ CGContextSetMiterLimit(mrShared.maContextHolder.get(), fCGMiterLimit);
+ CGContextDrawPath(mrShared.maContextHolder.get(), kCGPathStroke);
+ mrShared.maContextHolder.restoreState();
+
+ // mark modified rectangle as updated
+ refreshRect(aRefreshRect);
+ }
+
+ CGPathRelease(xPath);
+
+ return true;
+}
+
+bool AquaGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPointArray*/,
+ const PolyFlags* /*pFlagArray*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPointArray*/,
+ const PolyFlags* /*pFlagArray*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/,
+ const Point* const* /*pPointArray*/,
+ const PolyFlags* const* /*pFlagArray*/)
+{
+ return false;
+}
+
+void AquaGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
+{
+ if (!mrShared.checkContext())
+ return;
+
+ const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateCroppedImage(
+ static_cast<int>(rPosAry.mnSrcX), static_cast<int>(rPosAry.mnSrcY),
+ static_cast<int>(rPosAry.mnSrcWidth), static_cast<int>(rPosAry.mnSrcHeight));
+ if (!xImage)
+ return;
+
+ const CGRect aDstRect
+ = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+ CGContextDrawImage(mrShared.maContextHolder.get(), aDstRect, xImage);
+
+ CGImageRelease(xImage);
+ refreshRect(aDstRect);
+}
+
+void AquaGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap)
+{
+ if (!mrShared.checkContext())
+ return;
+
+ const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
+ const QuartzSalBitmap& rMask = static_cast<const QuartzSalBitmap&>(rTransparentBitmap);
+
+ CGImageRef xMaskedImage(rBitmap.CreateWithMask(rMask, rPosAry.mnSrcX, rPosAry.mnSrcY,
+ rPosAry.mnSrcWidth, rPosAry.mnSrcHeight));
+ if (!xMaskedImage)
+ return;
+
+ const CGRect aDstRect
+ = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+ CGContextDrawImage(mrShared.maContextHolder.get(), aDstRect, xMaskedImage);
+ CGImageRelease(xMaskedImage);
+ refreshRect(aDstRect);
+}
+
+void AquaGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
+ Color nMaskColor)
+{
+ if (!mrShared.checkContext())
+ return;
+
+ const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateColorMask(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth,
+ rPosAry.mnSrcHeight, nMaskColor);
+ if (!xImage)
+ return;
+
+ const CGRect aDstRect
+ = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+ CGContextDrawImage(mrShared.maContextHolder.get(), aDstRect, xImage);
+ CGImageRelease(xImage);
+ refreshRect(aDstRect);
+}
+
+std::shared_ptr<SalBitmap> AquaGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY,
+ tools::Long nDX, tools::Long nDY)
+{
+ SAL_WARN_IF(!mrShared.maLayer.isSet(), "vcl.quartz",
+ "AquaSalGraphics::getBitmap() with no layer this=" << this);
+
+ mrShared.applyXorContext();
+
+ std::shared_ptr<QuartzSalBitmap> pBitmap = std::make_shared<QuartzSalBitmap>();
+ if (!pBitmap->Create(mrShared.maLayer, mrShared.mnBitmapDepth, nX, nY, nDX, nDY,
+ mrShared.isFlipped()))
+ {
+ pBitmap = nullptr;
+ }
+ return pBitmap;
+}
+
+Color AquaGraphicsBackend::getPixel(tools::Long nX, tools::Long nY)
+{
+ // return default value on printers or when out of bounds
+ if (!mrShared.maLayer.isSet() || (nX < 0) || (nX >= mrShared.mnWidth) || (nY < 0)
+ || (nY >= mrShared.mnHeight))
+ {
+ return COL_BLACK;
+ }
+
+ // prepare creation of matching a CGBitmapContext
+#if defined OSL_BIGENDIAN
+ struct
+ {
+ unsigned char b, g, r, a;
+ } aPixel;
+#else
+ struct
+ {
+ unsigned char a, r, g, b;
+ } aPixel;
+#endif
+
+ // create a one-pixel bitmap context
+ // TODO: is it worth to cache it?
+ CGContextRef xOnePixelContext = CGBitmapContextCreate(
+ &aPixel, 1, 1, 8, 32, GetSalData()->mxRGBSpace,
+ uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Big));
+
+ // update this graphics layer
+ mrShared.applyXorContext();
+
+ // copy the requested pixel into the bitmap context
+ if (mrShared.isFlipped())
+ {
+ nY = mrShared.mnHeight - nY;
+ }
+ const CGPoint aCGPoint = CGPointMake(-nX, -nY);
+ CGContextDrawLayerAtPoint(xOnePixelContext, aCGPoint, mrShared.maLayer.get());
+
+ CGContextRelease(xOnePixelContext);
+
+ Color nColor(aPixel.r, aPixel.g, aPixel.b);
+ return nColor;
+}
+
+void AquaSalGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
+{
+#ifndef IOS
+ if (!mnRealDPIY)
+ {
+ initResolution((maShared.mbWindow && maShared.mpFrame) ? maShared.mpFrame->getNSWindow()
+ : nil);
+ }
+
+ rDPIX = mnRealDPIX;
+ rDPIY = mnRealDPIY;
+#else
+ // This *must* be 96 or else the iOS app will behave very badly (tiles are scaled wrongly and
+ // don't match each others at their boundaries, and other issues). But *why* it must be 96 I
+ // have no idea. The commit that changed it to 96 from (the arbitrary) 200 did not say. If you
+ // know where else 96 is explicitly or implicitly hard-coded, please modify this comment.
+
+ // Follow-up: It might be this: in 'online', loleaflet/src/map/Map.js:
+ // 15 = 1440 twips-per-inch / 96 dpi.
+ // Chosen to match previous hardcoded value of 3840 for
+ // the current tile pixel size of 256.
+ rDPIX = rDPIY = 96;
+#endif
+}
+
+void AquaGraphicsBackend::pattern50Fill()
+{
+ static const CGFloat aFillCol[4] = { 1, 1, 1, 1 };
+ static const CGPatternCallbacks aCallback = { 0, &drawPattern50, nullptr };
+ static const CGColorSpaceRef mxP50Space = CGColorSpaceCreatePattern(GetSalData()->mxRGBSpace);
+ static const CGPatternRef mxP50Pattern
+ = CGPatternCreate(nullptr, CGRectMake(0, 0, 4, 4), CGAffineTransformIdentity, 4, 4,
+ kCGPatternTilingConstantSpacing, false, &aCallback);
+ SAL_WARN_IF(!mrShared.maContextHolder.get(), "vcl.quartz", "maContextHolder.get() is NULL");
+ CGContextSetFillColorSpace(mrShared.maContextHolder.get(), mxP50Space);
+ CGContextSetFillPattern(mrShared.maContextHolder.get(), mxP50Pattern, aFillCol);
+ CGContextFillPath(mrShared.maContextHolder.get());
+}
+
+void AquaGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight, SalInvert nFlags)
+{
+ if (mrShared.checkContext())
+ {
+ CGRect aCGRect = CGRectMake(nX, nY, nWidth, nHeight);
+ mrShared.maContextHolder.saveState();
+ if (nFlags & SalInvert::TrackFrame)
+ {
+ const CGFloat dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ CGContextSetRGBStrokeColor(mrShared.maContextHolder.get(), 1.0, 1.0, 1.0, 1.0);
+ CGContextSetLineDash(mrShared.maContextHolder.get(), 0, dashLengths, 2);
+ CGContextSetLineWidth(mrShared.maContextHolder.get(), 2.0);
+ CGContextStrokeRect(mrShared.maContextHolder.get(), aCGRect);
+ }
+ else if (nFlags & SalInvert::N50)
+ {
+ //CGContextSetAllowsAntialiasing( maContextHolder.get(), false );
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ CGContextAddRect(mrShared.maContextHolder.get(), aCGRect);
+ pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ CGContextSetRGBFillColor(mrShared.maContextHolder.get(), 1.0, 1.0, 1.0, 1.0);
+ CGContextFillRect(mrShared.maContextHolder.get(), aCGRect);
+ }
+ mrShared.maContextHolder.restoreState();
+ refreshRect(aCGRect);
+ }
+}
+
+namespace
+{
+CGPoint* makeCGptArray(sal_uInt32 nPoints, const Point* pPtAry)
+{
+ CGPoint* CGpoints = new CGPoint[nPoints];
+ for (sal_uLong i = 0; i < nPoints; i++)
+ {
+ CGpoints[i].x = pPtAry[i].getX();
+ CGpoints[i].y = pPtAry[i].getY();
+ }
+ return CGpoints;
+}
+
+} // end anonymous ns
+
+void AquaGraphicsBackend::invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nSalFlags)
+{
+ if (mrShared.checkContext())
+ {
+ mrShared.maContextHolder.saveState();
+ CGPoint* CGpoints = makeCGptArray(nPoints, pPtAry);
+ CGContextAddLines(mrShared.maContextHolder.get(), CGpoints, nPoints);
+ if (nSalFlags & SalInvert::TrackFrame)
+ {
+ const CGFloat dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ CGContextSetRGBStrokeColor(mrShared.maContextHolder.get(), 1.0, 1.0, 1.0, 1.0);
+ CGContextSetLineDash(mrShared.maContextHolder.get(), 0, dashLengths, 2);
+ CGContextSetLineWidth(mrShared.maContextHolder.get(), 2.0);
+ CGContextStrokePath(mrShared.maContextHolder.get());
+ }
+ else if (nSalFlags & SalInvert::N50)
+ {
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeDifference);
+ CGContextSetRGBFillColor(mrShared.maContextHolder.get(), 1.0, 1.0, 1.0, 1.0);
+ CGContextFillPath(mrShared.maContextHolder.get());
+ }
+ const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrShared.maContextHolder.get());
+ mrShared.maContextHolder.restoreState();
+ delete[] CGpoints;
+ refreshRect(aRefreshRect);
+ }
+}
+
+#ifndef IOS
+bool AquaGraphicsBackend::drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight, void* pEpsData, sal_uInt32 nByteCount)
+{
+ // convert the raw data to an NSImageRef
+ NSData* xNSData = [NSData dataWithBytes:pEpsData length:static_cast<int>(nByteCount)];
+ NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData:xNSData];
+ if (!xEpsImage)
+ {
+ return false;
+ }
+ // get the target context
+ if (!mrShared.checkContext())
+ {
+ return false;
+ }
+ // NOTE: flip drawing, else the nsimage would be drawn upside down
+ mrShared.maContextHolder.saveState();
+ // CGContextTranslateCTM( maContextHolder.get(), 0, +mnHeight );
+ CGContextScaleCTM(mrShared.maContextHolder.get(), +1, -1);
+ nY = /*mnHeight*/ -(nY + nHeight);
+
+ // prepare the target context
+ NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext];
+ [pOrigNSCtx retain];
+
+ // create new context
+ NSGraphicsContext* pDrawNSCtx =
+ [NSGraphicsContext graphicsContextWithCGContext:mrShared.maContextHolder.get()
+ flipped:mrShared.isFlipped()];
+ // set it, setCurrentContext also releases the previously set one
+ [NSGraphicsContext setCurrentContext:pDrawNSCtx];
+
+ // draw the EPS
+ const NSRect aDstRect = NSMakeRect(nX, nY, nWidth, nHeight);
+ const bool bOK = [xEpsImage drawInRect:aDstRect];
+
+ // restore the NSGraphicsContext
+ [NSGraphicsContext setCurrentContext:pOrigNSCtx];
+ [pOrigNSCtx release]; // restore the original retain count
+
+ mrShared.maContextHolder.restoreState();
+ // mark the destination rectangle as updated
+ refreshRect(aDstRect);
+
+ return bOK;
+}
+#else
+bool AquaGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/,
+ tools::Long /*nHeight*/, void* /*pEpsData*/,
+ sal_uInt32 /*nByteCount*/)
+{
+ return false;
+}
+#endif
+
+bool AquaGraphicsBackend::blendBitmap(const SalTwoRect& /*rPosAry*/, const SalBitmap& /*rBitmap*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::blendAlphaBitmap(const SalTwoRect& /*rPosAry*/,
+ const SalBitmap& /*rSrcBitmap*/,
+ const SalBitmap& /*rMaskBitmap*/,
+ const SalBitmap& /*rAlphaBitmap*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap,
+ const SalBitmap& rAlphaBmp)
+{
+ // An image mask can't have a depth > 8 bits (should be 1 to 8 bits)
+ if (rAlphaBmp.GetBitCount() > 8)
+ return false;
+
+ // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx)
+ // horizontal/vertical mirroring not implemented yet
+ if (rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0)
+ return false;
+
+ 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,
+ rTR.mnSrcWidth, rTR.mnSrcHeight);
+ if (!xMaskedImage)
+ return false;
+
+ if (mrShared.checkContext())
+ {
+ const CGRect aDstRect
+ = CGRectMake(rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight);
+ CGContextDrawImage(mrShared.maContextHolder.get(), aDstRect, xMaskedImage);
+ refreshRect(aDstRect);
+ }
+
+ CGImageRelease(xMaskedImage);
+
+ return true;
+}
+
+bool AquaGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
+ const basegfx::B2DPoint& rX,
+ const basegfx::B2DPoint& rY,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap* pAlphaBmp, double fAlpha)
+{
+ if (!mrShared.checkContext())
+ return true;
+
+ if (fAlpha != 1.0)
+ return false;
+
+ // get the Quartz image
+ CGImageRef xImage = nullptr;
+ const Size aSize = rSrcBitmap.GetSize();
+ const QuartzSalBitmap& rSrcSalBmp = static_cast<const QuartzSalBitmap&>(rSrcBitmap);
+ const QuartzSalBitmap* pMaskSalBmp = static_cast<const QuartzSalBitmap*>(pAlphaBmp);
+
+ if (!pMaskSalBmp)
+ xImage = rSrcSalBmp.CreateCroppedImage(0, 0, int(aSize.Width()), int(aSize.Height()));
+ else
+ xImage = rSrcSalBmp.CreateWithMask(*pMaskSalBmp, 0, 0, int(aSize.Width()),
+ int(aSize.Height()));
+
+ if (!xImage)
+ return false;
+
+ // setup the image transformation
+ // using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points
+ mrShared.maContextHolder.saveState();
+ const basegfx::B2DVector aXRel = rX - rNull;
+ const basegfx::B2DVector aYRel = rY - rNull;
+ const CGAffineTransform aCGMat = CGAffineTransformMake(
+ aXRel.getX() / aSize.Width(), aXRel.getY() / aSize.Width(), aYRel.getX() / aSize.Height(),
+ aYRel.getY() / aSize.Height(), rNull.getX(), rNull.getY());
+
+ CGContextConcatCTM(mrShared.maContextHolder.get(), aCGMat);
+
+ // draw the transformed image
+ const CGRect aSrcRect = CGRectMake(0, 0, aSize.Width(), aSize.Height());
+ CGContextDrawImage(mrShared.maContextHolder.get(), aSrcRect, xImage);
+
+ CGImageRelease(xImage);
+
+ // restore the Quartz graphics state
+ mrShared.maContextHolder.restoreState();
+
+ // mark the destination as painted
+ const CGRect aDstRect = CGRectApplyAffineTransform(aSrcRect, aCGMat);
+ refreshRect(aDstRect);
+
+ return true;
+}
+
+bool AquaGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; }
+
+bool AquaGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight, sal_uInt8 nTransparency)
+{
+ if (!mrShared.checkContext())
+ return true;
+
+ // save the current state
+ mrShared.maContextHolder.saveState();
+ CGContextSetAlpha(mrShared.maContextHolder.get(), (100 - nTransparency) * (1.0 / 100));
+
+ CGRect aRect = CGRectMake(nX, nY, nWidth - 1, nHeight - 1);
+ if (mrShared.isPenVisible())
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ }
+
+ CGContextBeginPath(mrShared.maContextHolder.get());
+ CGContextAddRect(mrShared.maContextHolder.get(), aRect);
+ CGContextDrawPath(mrShared.maContextHolder.get(), kCGPathFill);
+
+ mrShared.maContextHolder.restoreState();
+ refreshRect(aRect);
+
+ return true;
+}
+
+bool AquaGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolygon*/,
+ const Gradient& /*rGradient*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/,
+ SalGradient const& /*rGradient*/)
+{
+ return false;
+}
+
+bool AquaGraphicsBackend::supportsOperation(OutDevSupportType eType) const
+{
+ switch (eType)
+ {
+ case OutDevSupportType::TransparentRect:
+ case OutDevSupportType::B2DDraw:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index 375fea64a5cb..c938cf772030 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -186,27 +186,11 @@ bool CoreTextFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilit
}
AquaSalGraphics::AquaSalGraphics()
- : mnXorMode( 0 )
- , mnWidth( 0 )
- , mnHeight( 0 )
- , mnBitmapDepth( 0 )
+ : mpBackend(new AquaGraphicsBackend(maShared))
, mnRealDPIX( 0 )
, mnRealDPIY( 0 )
- , mxClipPath( nullptr )
- , maLineColor( COL_WHITE )
- , maFillColor( COL_BLACK )
, maTextColor( COL_BLACK )
, mbNonAntialiasedText( false )
-#ifdef MACOSX
- , mpFrame( nullptr )
-#endif
- , mbPrinter( false )
- , mbVirDev( false )
-#ifdef MACOSX
- , mbWindow( false )
-#else
- , mbForeignContext( false )
-#endif
{
SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this );
@@ -221,38 +205,35 @@ AquaSalGraphics::~AquaSalGraphics()
{
SAL_INFO( "vcl.quartz", "AquaSalGraphics::~AquaSalGraphics() this=" << this );
- if( mxClipPath )
- {
- CGPathRelease( mxClipPath );
- }
+ maShared.unsetClipPath();
ReleaseFonts();
- mpXorEmulation.reset();
+ maShared.mpXorEmulation.reset();
#ifdef IOS
- if (mbForeignContext)
+ if (maShared.mbForeignContext)
return;
#endif
- if (maLayer.isSet())
+ if (maShared.maLayer.isSet())
{
- CGLayerRelease(maLayer.get());
+ CGLayerRelease(maShared.maLayer.get());
}
- else if (maContextHolder.isSet()
+ else if (maShared.maContextHolder.isSet()
#ifdef MACOSX
- && mbWindow
+ && maShared.mbWindow
#endif
)
{
// destroy backbuffer bitmap context that we created ourself
- CGContextRelease(maContextHolder.get());
- maContextHolder.set(nullptr);
+ CGContextRelease(maShared.maContextHolder.get());
+ maShared.maContextHolder.set(nullptr);
}
}
SalGraphicsImpl* AquaSalGraphics::GetImpl() const
{
- return nullptr;
+ return mpBackend.get();
}
void AquaSalGraphics::SetTextColor( Color nColor )
@@ -370,7 +351,7 @@ bool AquaSalGraphics::AddTempDevFont( PhysicalFontCollection*,
void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
{
#ifdef IOS
- if (!CheckContext())
+ if (!maShared.checkContext())
{
SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout() without context");
return;
@@ -444,20 +425,20 @@ void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
std::cerr << "]\n";
#endif
- maContextHolder.saveState();
+ maShared.maContextHolder.saveState();
// The view is vertically flipped (no idea why), flip it back.
- CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0);
- CGContextSetShouldAntialias(maContextHolder.get(), !mbNonAntialiasedText);
- CGContextSetFillColor(maContextHolder.get(), maTextColor.AsArray());
+ CGContextScaleCTM(maShared.maContextHolder.get(), 1.0, -1.0);
+ CGContextSetShouldAntialias(maShared.maContextHolder.get(), !mbNonAntialiasedText);
+ CGContextSetFillColor(maShared.maContextHolder.get(), maTextColor.AsArray());
if (rStyle.mbFauxBold)
{
float fSize = rFontSelect.mnHeight / 23.0f;
- CGContextSetStrokeColor(maContextHolder.get(), maTextColor.AsArray());
- CGContextSetLineWidth(maContextHolder.get(), fSize);
- CGContextSetTextDrawingMode(maContextHolder.get(), kCGTextFillStroke);
+ CGContextSetStrokeColor(maShared.maContextHolder.get(), maTextColor.AsArray());
+ CGContextSetLineWidth(maShared.maContextHolder.get(), fSize);
+ CGContextSetTextDrawingMode(maShared.maContextHolder.get(), kCGTextFillStroke);
}
auto aIt = aGlyphOrientation.cbegin();
@@ -470,18 +451,18 @@ void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
size_t nStartIndex = std::distance(aGlyphOrientation.cbegin(), aIt);
size_t nLen = std::distance(aIt, aNext);
- maContextHolder.saveState();
+ maShared.maContextHolder.saveState();
if (rStyle.mfFontRotation && !bUprightGlyph)
{
- CGContextRotateCTM(maContextHolder.get(), rStyle.mfFontRotation);
+ CGContextRotateCTM(maShared.maContextHolder.get(), rStyle.mfFontRotation);
}
- CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, maContextHolder.get());
- maContextHolder.restoreState();
+ CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, maShared.maContextHolder.get());
+ maShared.maContextHolder.restoreState();
aIt = aNext;
}
- maContextHolder.restoreState();
+ maShared.maContextHolder.restoreState();
}
void AquaSalGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel)
@@ -780,46 +761,9 @@ void AquaSalGraphics::FreeEmbedFontData( const void* pData, tools::Long /*nDataL
SAL_WARN_IF( (pData==nullptr), "vcl", "AquaSalGraphics::FreeEmbedFontData() is not implemented");
}
-bool AquaSalGraphics::IsFlipped() const
-{
-#ifdef MACOSX
- return mbWindow;
-#else
- return false;
-#endif
-}
-
-void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight)
-{
-#ifdef MACOSX
- if( ! mbWindow ) // view only on Window graphics
- return;
-
- if( mpFrame )
- {
- // update a little more around the designated rectangle
- // this helps with antialiased rendering
- // Rounding down x and width can accumulate a rounding error of up to 2
- // The decrementing of x, the rounding error and the antialiasing border
- // require that the width and the height need to be increased by four
- const tools::Rectangle aVclRect(Point(static_cast<tools::Long>(lX-1),
- static_cast<tools::Long>(lY-1) ),
- Size( static_cast<tools::Long>(lWidth+4),
- static_cast<tools::Long>(lHeight+4) ) );
- mpFrame->maInvalidRect.Union( aVclRect );
- }
-#else
- (void) lX;
- (void) lY;
- (void) lWidth;
- (void) lHeight;
- return;
-#endif
-}
-
#ifdef IOS
-bool AquaSalGraphics::CheckContext()
+bool AquaSharedAttributes::checkContext()
{
if (mbForeignContext)
{
diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx
index db6715ce01e2..fec61453367d 100644
--- a/vcl/quartz/salgdicommon.cxx
+++ b/vcl/quartz/salgdicommon.cxx
@@ -46,87 +46,6 @@
using namespace vcl;
-const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 );
-
-static void AddPolygonToPath( CGMutablePathRef xPath,
- const basegfx::B2DPolygon& rPolygon,
- bool bClosePath, bool bPixelSnap, bool bLineDraw )
-{
- // short circuit if there is nothing to do
- const int nPointCount = rPolygon.count();
- if( nPointCount <= 0 )
- {
- return;
- }
-
- const bool bHasCurves = rPolygon.areControlPointsUsed();
- for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
- {
- int nClosedIdx = nPointIdx;
- if( nPointIdx >= nPointCount )
- {
- // prepare to close last curve segment if needed
- if( bClosePath && (nPointIdx == nPointCount) )
- {
- nClosedIdx = 0;
- }
- else
- {
- break;
- }
- }
-
- basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
-
- if( bPixelSnap)
- {
- // snap device coordinates to full pixels
- aPoint.setX( basegfx::fround( aPoint.getX() ) );
- aPoint.setY( basegfx::fround( aPoint.getY() ) );
- }
-
- if( bLineDraw )
- {
- aPoint += aHalfPointOfs;
- }
- if( !nPointIdx )
- {
- // first point => just move there
- CGPathMoveToPoint( xPath, nullptr, aPoint.getX(), aPoint.getY() );
- continue;
- }
-
- bool bPendingCurve = false;
- if( bHasCurves )
- {
- bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx );
- bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx );
- }
-
- if( !bPendingCurve ) // line segment
- {
- CGPathAddLineToPoint( xPath, nullptr, aPoint.getX(), aPoint.getY() );
- }
- else // cubic bezier segment
- {
- basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx );
- basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx );
- if( bLineDraw )
- {
- aCP1 += aHalfPointOfs;
- aCP2 += aHalfPointOfs;
- }
- CGPathAddCurveToPoint( xPath, nullptr, aCP1.getX(), aCP1.getY(),
- aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() );
- }
- }
-
- if( bClosePath )
- {
- CGPathCloseSubpath( xPath );
- }
-}
-
bool AquaSalGraphics::CreateFontSubset( const OUString& rToFile,
const PhysicalFontFace* pFontData,
const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding,
@@ -178,87 +97,13 @@ bool AquaSalGraphics::CreateFontSubset( const OUString& rToFile,
return bRet;
}
-static void alignLinePoint( const Point* i_pIn, float& o_fX, float& o_fY )
-{
- o_fX = static_cast<float>(i_pIn->getX() ) + 0.5;
- o_fY = static_cast<float>(i_pIn->getY() ) + 0.5;
-}
-
-static void DrawPattern50( void*, CGContextRef rContext )
-{
- static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } };
- CGContextAddRects( rContext, aRects, 2 );
- CGContextFillPath( rContext );
-}
-
-static void getBoundRect( sal_uInt32 nPoints, const Point *pPtAry,
- tools::Long &rX, tools::Long& rY, tools::Long& rWidth,
- tools::Long& rHeight )
-{
- tools::Long nX1 = pPtAry->getX();
- tools::Long nX2 = nX1;
- tools::Long nY1 = pPtAry->getY();
- tools::Long nY2 = nY1;
-
- for( sal_uInt32 n = 1; n < nPoints; n++ )
- {
- if( pPtAry[n].getX() < nX1 )
- {
- nX1 = pPtAry[n].getX();
- }
- else if( pPtAry[n].getX() > nX2 )
- {
- nX2 = pPtAry[n].getX();
- }
- if( pPtAry[n].getY() < nY1 )
- {
- nY1 = pPtAry[n].getY();
- }
- else if( pPtAry[n].getY() > nY2 )
- {
- nY2 = pPtAry[n].getY();
- }
- }
- rX = nX1;
- rY = nY1;
- rWidth = nX2 - nX1 + 1;
- rHeight = nY2 - nY1 + 1;
-}
-
-static Color ImplGetROPColor( SalROPColor nROPColor )
-{
- Color nColor;
- if ( nROPColor == SalROPColor::N0 )
- {
- nColor = Color( 0, 0, 0 );
- }
- else
- {
- nColor = Color( 255, 255, 255 );
- }
- return nColor;
-}
-
-// apply the XOR mask to the target context if active and dirty
-void AquaSalGraphics::ApplyXorContext()
-{
- if (!mpXorEmulation)
- {
- return;
- }
- if (mpXorEmulation->UpdateTarget())
- {
- RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect
- }
-}
-
#ifndef IOS
void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
{
- if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame )
+ if (!rGraphics.mnRealDPIY && rGraphics.maShared.mbWindow && rGraphics.maShared.mpFrame)
{
- rGraphics.initResolution( rGraphics.mpFrame->getNSWindow() );
+ rGraphics.initResolution(rGraphics.maShared.mpFrame->getNSWindow());
}
mnRealDPIX = rGraphics.mnRealDPIX;
mnRealDPIY = rGraphics.mnRealDPIY;
@@ -266,852 +111,14 @@ void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
#endif
-bool AquaSalGraphics::blendBitmap( const SalTwoRect&,
- const SalBitmap& )
-{
- return false;
-}
-
-bool AquaSalGraphics::blendAlphaBitmap( const SalTwoRect&,
- const SalBitmap&,
- const SalBitmap&,
- const SalBitmap& )
-{
- return false;
-}
-
-bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
- const SalBitmap& rSrcBitmap,
- const SalBitmap& rAlphaBmp )
-{
- // An image mask can't have a depth > 8 bits (should be 1 to 8 bits)
- if( rAlphaBmp.GetBitCount() > 8 )
- return false;
-
- // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx)
- // horizontal/vertical mirroring not implemented yet
- if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 )
- return false;
-
- 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, rTR.mnSrcWidth,
- rTR.mnSrcHeight );
- if( !xMaskedImage )
- return false;
-
- if ( CheckContext() )
- {
- const CGRect aDstRect = CGRectMake( rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight);
- CGContextDrawImage( maContextHolder.get(), aDstRect, xMaskedImage );
- RefreshRect( aDstRect );
- }
-
- CGImageRelease(xMaskedImage);
-
- return true;
-}
-
-bool AquaSalGraphics::drawTransformedBitmap(
- const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY,
- const SalBitmap& rSrcBitmap, const SalBitmap* pAlphaBmp, double fAlpha )
-{
- if( !CheckContext() )
- return true;
-
- if( fAlpha != 1.0 )
- return false;
-
- // get the Quartz image
- CGImageRef xImage = nullptr;
- const Size aSize = rSrcBitmap.GetSize();
- const QuartzSalBitmap& rSrcSalBmp = static_cast<const QuartzSalBitmap&>(rSrcBitmap);
- const QuartzSalBitmap* pMaskSalBmp = static_cast<const QuartzSalBitmap*>(pAlphaBmp);
-
- if( !pMaskSalBmp)
- xImage = rSrcSalBmp.CreateCroppedImage( 0, 0, static_cast<int>(aSize.Width()), static_cast<int>(aSize.Height()) );
- else
- xImage = rSrcSalBmp.CreateWithMask( *pMaskSalBmp, 0, 0, static_cast<int>(aSize.Width()), static_cast<int>(aSize.Height()) );
- if( !xImage )
- return false;
-
- // setup the image transformation
- // using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points
- maContextHolder.saveState();
- const basegfx::B2DVector aXRel = rX - rNull;
- const basegfx::B2DVector aYRel = rY - rNull;
- const CGAffineTransform aCGMat = CGAffineTransformMake(
- aXRel.getX()/aSize.Width(), aXRel.getY()/aSize.Width(),
- aYRel.getX()/aSize.Height(), aYRel.getY()/aSize.Height(),
- rNull.getX(), rNull.getY());
-
- CGContextConcatCTM( maContextHolder.get(), aCGMat );
-
- // draw the transformed image
- const CGRect aSrcRect = CGRectMake(0, 0, aSize.Width(), aSize.Height());
- CGContextDrawImage( maContextHolder.get(), aSrcRect, xImage );
-
- CGImageRelease( xImage );
- // restore the Quartz graphics state
- maContextHolder.restoreState();
-
- // mark the destination as painted
- const CGRect aDstRect = CGRectApplyAffineTransform( aSrcRect, aCGMat );
- RefreshRect( aDstRect );
-
- return true;
-}
-
-bool AquaSalGraphics::hasFastDrawTransformedBitmap() const
-{
- return false;
-}
-
-bool AquaSalGraphics::drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth,
- tools::Long nHeight, sal_uInt8 nTransparency )
-{
- if( !CheckContext() )
- return true;
-
- // save the current state
- maContextHolder.saveState();
- CGContextSetAlpha( maContextHolder.get(), (100-nTransparency) * (1.0/100) );
-
- CGRect aRect = CGRectMake(nX, nY, nWidth-1, nHeight-1);
- if( IsPenVisible() )
- {
- aRect.origin.x += 0.5;
- aRect.origin.y += 0.5;
- }
-
- CGContextBeginPath( maContextHolder.get() );
- CGContextAddRect( maContextHolder.get(), aRect );
- CGContextDrawPath( maContextHolder.get(), kCGPathFill );
-
- maContextHolder.restoreState();
- RefreshRect( aRect );
-
- return true;
-}
-
-void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
-{
- if( !CheckContext() )
- return;
-
- const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
- CGImageRef xImage = rBitmap.CreateCroppedImage( static_cast<int>(rPosAry.mnSrcX), static_cast<int>(rPosAry.mnSrcY),
- static_cast<int>(rPosAry.mnSrcWidth), static_cast<int>(rPosAry.mnSrcHeight) );
- if( !xImage )
- return;
-
- const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
- CGContextDrawImage( maContextHolder.get(), aDstRect, xImage );
-
- CGImageRelease( xImage );
- RefreshRect( aDstRect );
-}
-
-void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
- const SalBitmap& rTransparentBitmap )
-{
- if( !CheckContext() )
- return;
-
- const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
- const QuartzSalBitmap& rMask = static_cast<const QuartzSalBitmap&>(rTransparentBitmap);
- CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, rPosAry.mnSrcX, rPosAry.mnSrcY,
- rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ) );
- if( !xMaskedImage )
- return;
-
- const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
- CGContextDrawImage( maContextHolder.get(), aDstRect, xMaskedImage );
- CGImageRelease( xMaskedImage );
- RefreshRect( aDstRect );
-}
-
-#ifndef IOS
-
-bool AquaSalGraphics::drawEPS(
- tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
- void* pEpsData, sal_uInt32 nByteCount )
-{
- // convert the raw data to an NSImageRef
- NSData* xNSData = [NSData dataWithBytes:pEpsData length:static_cast<int>(nByteCount)];
- NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData: xNSData];
- if( !xEpsImage )
- {
- return false;
- }
- // get the target context
- if( !CheckContext() )
- {
- return false;
- }
- // NOTE: flip drawing, else the nsimage would be drawn upside down
- maContextHolder.saveState();
-// CGContextTranslateCTM( maContextHolder.get(), 0, +mnHeight );
- CGContextScaleCTM( maContextHolder.get(), +1, -1 );
- nY = /*mnHeight*/ - (nY + nHeight);
-
- // prepare the target context
- NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext];
- [pOrigNSCtx retain];
-
- // create new context
- NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithCGContext: maContextHolder.get() flipped: IsFlipped()];
- // set it, setCurrentContext also releases the previously set one
- [NSGraphicsContext setCurrentContext: pDrawNSCtx];
-
- // draw the EPS
- const NSRect aDstRect = NSMakeRect( nX, nY, nWidth, nHeight);
- const bool bOK = [xEpsImage drawInRect: aDstRect];
-
- // restore the NSGraphicsContext
- [NSGraphicsContext setCurrentContext: pOrigNSCtx];
- [pOrigNSCtx release]; // restore the original retain count
-
- maContextHolder.restoreState();
- // mark the destination rectangle as updated
- RefreshRect( aDstRect );
-
- return bOK;
-}
-
-#endif
-
-void AquaSalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
-{
- if( nX1 == nX2 && nY1 == nY2 )
- {
- // #i109453# platform independent code expects at least one pixel to be drawn
- drawPixel( nX1, nY1 );
-
- return;
- }
-
- if( !CheckContext() )
- return;
-
- CGContextBeginPath( maContextHolder.get() );
- CGContextMoveToPoint( maContextHolder.get(), static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 );
- CGContextAddLineToPoint( maContextHolder.get(), static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 );
- CGContextDrawPath( maContextHolder.get(), kCGPathStroke );
-
- tools::Rectangle aRefreshRect( nX1, nY1, nX2, nY2 );
- (void) aRefreshRect;
- // Is a call to RefreshRect( aRefreshRect ) missing here?
-}
-
-void AquaSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, Color nMaskColor )
-{
- if( !CheckContext() )
- return;
-
- const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap);
- CGImageRef xImage = rBitmap.CreateColorMask( rPosAry.mnSrcX, rPosAry.mnSrcY,
- rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
- nMaskColor );
- if( !xImage )
- return;
-
- const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
- CGContextDrawImage( maContextHolder.get(), aDstRect, xImage );
- CGImageRelease( xImage );
- RefreshRect( aDstRect );
-}
-
-void AquaSalGraphics::drawPixel( tools::Long nX, tools::Long nY )
-{
- // draw pixel with current line color
- ImplDrawPixel( nX, nY, maLineColor );
-}
-
-void AquaSalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
-{
- const RGBAColor aPixelColor( nColor );
- ImplDrawPixel( nX, nY, aPixelColor );
-}
-
-bool AquaSalGraphics::drawPolyLine(
- const basegfx::B2DHomMatrix& rObjectToDevice,
- const basegfx::B2DPolygon& rPolyLine,
- double fTransparency,
- double fLineWidth,
- const std::vector< double >* pStroke, // MM01
- basegfx::B2DLineJoin eLineJoin,
- css::drawing::LineCap eLineCap,
- double fMiterMinimumAngle,
- bool bPixelSnapHairline)
-{
- // MM01 check done for simple reasons
- if(!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
- {
- return true;
- }
-
-#ifdef IOS
- if( !CheckContext() )
- return false;
-#endif
-
- // tdf#124848 get correct LineWidth in discrete coordinates,
- if(fLineWidth == 0) // hairline
- fLineWidth = 1.0;
- else // Adjust line width for object-to-device scale.
- fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
-
- // #i101491# Aqua does not support B2DLineJoin::NONE; return false to use
- // the fallback (own geometry preparation)
- // #i104886# linejoin-mode and thus the above only applies to "fat" lines
- if( (basegfx::B2DLineJoin::NONE == eLineJoin) && (fLineWidth > 1.3) )
- return false;
-
- // MM01 need to do line dashing as fallback stuff here now
- const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
- const bool bStrokeUsed(0.0 != fDotDashLength);
- assert(!bStrokeUsed || (bStrokeUsed && pStroke));
- basegfx::B2DPolyPolygon aPolyPolygonLine;
-
- if(bStrokeUsed)
- {
- // apply LineStyle
- basegfx::utils::applyLineDashing(
- rPolyLine, // source
- *pStroke, // pattern
- &aPolyPolygonLine, // target for lines
- nullptr, // target for gaps
- fDotDashLength); // full length if available
- }
- else
- {
- // no line dashing, just copy
- aPolyPolygonLine.append(rPolyLine);
- }
-
- // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
- aPolyPolygonLine.transform(rObjectToDevice);
- if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); }
-
- // setup line attributes
- CGLineJoin aCGLineJoin = kCGLineJoinMiter;
- switch( eLineJoin )
- {
- case basegfx::B2DLineJoin::NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
- case basegfx::B2DLineJoin::Bevel: aCGLineJoin = kCGLineJoinBevel; break;
- case basegfx::B2DLineJoin::Miter: aCGLineJoin = kCGLineJoinMiter; break;
- case basegfx::B2DLineJoin::Round: aCGLineJoin = kCGLineJoinRound; break;
- }
- // convert miter minimum angle to miter limit
- CGFloat fCGMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0);
- // setup cap attribute
- CGLineCap aCGLineCap(kCGLineCapButt);
-
- switch(eLineCap)
- {
- default: // css::drawing::LineCap_BUTT:
- {
- aCGLineCap = kCGLineCapButt;
- break;
- }
- case css::drawing::LineCap_ROUND:
- {
- aCGLineCap = kCGLineCapRound;
- break;
- }
- case css::drawing::LineCap_SQUARE:
- {
- aCGLineCap = kCGLineCapSquare;
- break;
- }
- }
-
- // setup poly-polygon path
- CGMutablePathRef xPath = CGPathCreateMutable();
-
- // MM01 todo - I assume that this is OKAY to be done in one run for quartz
- // but this NEEDS to be checked/verified
- for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
- {
- const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
- AddPolygonToPath(
- xPath,
- aPolyLine,
- aPolyLine.isClosed(),
- !getAntiAlias(),
- true);
- }
-
- const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
- // #i97317# workaround for Quartz having problems with drawing small polygons
- if( (aRefreshRect.size.width > 0.125) || (aRefreshRect.size.height > 0.125) )
- {
- // use the path to prepare the graphics context
- maContextHolder.saveState();
- CGContextBeginPath( maContextHolder.get() );
- CGContextAddPath( maContextHolder.get(), xPath );
- // draw path with antialiased line
- CGContextSetShouldAntialias( maContextHolder.get(), getAntiAlias() );
- CGContextSetAlpha( maContextHolder.get(), 1.0 - fTransparency );
- CGContextSetLineJoin( maContextHolder.get(), aCGLineJoin );
- CGContextSetLineCap( maContextHolder.get(), aCGLineCap );
- CGContextSetLineWidth( maContextHolder.get(), fLineWidth );
- CGContextSetMiterLimit(maContextHolder.get(), fCGMiterLimit);
- CGContextDrawPath( maContextHolder.get(), kCGPathStroke );
- maContextHolder.restoreState();
-
- // mark modified rectangle as updated
- RefreshRect( aRefreshRect );
- }
-
- CGPathRelease( xPath );
-
- return true;
-}
-
-bool AquaSalGraphics::drawPolyLineBezier( sal_uInt32, const Point*, const PolyFlags* )
-{
- return false;
-}
-
-bool AquaSalGraphics::drawPolyPolygon(
- const basegfx::B2DHomMatrix& rObjectToDevice,
- const basegfx::B2DPolyPolygon& rPolyPolygon,
- double fTransparency)
-{
-#ifdef IOS
- if (!maContextHolder.isSet())
- return true;
-#endif
-
- // short circuit if there is nothing to do
- if( rPolyPolygon.count() == 0 )
- return true;
-
- // ignore invisible polygons
- if( (fTransparency >= 1.0) || (fTransparency < 0) )
- return true;
-
- // Fallback: Transform to DeviceCoordinates
- basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
- aPolyPolygon.transform(rObjectToDevice);
-
- // setup poly-polygon path
- CGMutablePathRef xPath = CGPathCreateMutable();
- // tdf#120252 Use the correct, already transformed PolyPolygon (as long as
- // the transformation is not used here...)
- for(auto const& rPolygon : aPolyPolygon)
- {
- AddPolygonToPath( xPath, rPolygon, true, !getAntiAlias(), IsPenVisible() );
- }
-
- const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
- // #i97317# workaround for Quartz having problems with drawing small polygons
- if( (aRefreshRect.size.width > 0.125) || (aRefreshRect.size.height > 0.125) )
- {
- // prepare drawing mode
- CGPathDrawingMode eMode;
- if( IsBrushVisible() && IsPenVisible() )
- {
- eMode = kCGPathEOFillStroke;
- }
- else if( IsPenVisible() )
- {
- eMode = kCGPathStroke;
- }
- else if( IsBrushVisible() )
- {
- eMode = kCGPathEOFill;
- }
- else
- {
- SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" );
- CGPathRelease( xPath );
- return true;
- }
-
- // use the path to prepare the graphics context
- maContextHolder.saveState();
- CGContextBeginPath( maContextHolder.get() );
- CGContextAddPath( maContextHolder.get(), xPath );
-
- // draw path with antialiased polygon
- CGContextSetShouldAntialias( maContextHolder.get(), getAntiAlias() );
- CGContextSetAlpha( maContextHolder.get(), 1.0 - fTransparency );
- CGContextDrawPath( maContextHolder.get(), eMode );
- maContextHolder.restoreState();
-
- // mark modified rectangle as updated
- RefreshRect( aRefreshRect );
- }
-
- CGPathRelease( xPath );
-
- return true;
-}
-
-void AquaSalGraphics::drawPolyPolygon( sal_uInt32 nPolyCount, const sal_uInt32 *pPoints, const Point* *ppPtAry )
-{
- if( nPolyCount <= 0 )
- return;
-
- if( !CheckContext() )
- return;
-
- // find bound rect
- tools::Long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0;
- getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight );
-
- for( sal_uInt32 n = 1; n < nPolyCount; n++ )
- {
- tools::Long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight;
- getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH );
- if( nX < leftX )
- {
- maxWidth += leftX - nX;
- leftX = nX;
- }
- if( nY < topY )
- {
- maxHeight += topY - nY;
- topY = nY;
- }
- if( nX + nW > leftX + maxWidth )
- {
- maxWidth = nX + nW - leftX;
- }
- if( nY + nH > topY + maxHeight )
- {
- maxHeight = nY + nH - topY;
- }
- }
-
- // prepare drawing mode
- CGPathDrawingMode eMode;
- if( IsBrushVisible() && IsPenVisible() )
- {
- eMode = kCGPathEOFillStroke;
- }
- else if( IsPenVisible() )
- {
- eMode = kCGPathStroke;
- }
- else if( IsBrushVisible() )
- {
- eMode = kCGPathEOFill;
- }
- else
- {
- SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" );
- return;
- }
-
- // convert to CGPath
- CGContextBeginPath( maContextHolder.get() );
- if( IsPenVisible() )
- {
- for( sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++ )
- {
- const sal_uInt32 nPoints = pPoints[nPoly];
- if( nPoints > 1 )
- {
- const Point *pPtAry = ppPtAry[nPoly];
- float fX, fY;
-
- alignLinePoint( pPtAry, fX, fY );
- CGContextMoveToPoint( maContextHolder.get(), fX, fY );
- pPtAry++;
-
- for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
- {
- alignLinePoint( pPtAry, fX, fY );
- CGContextAddLineToPoint( maContextHolder.get(), fX, fY );
- }
- CGContextClosePath(maContextHolder.get());
- }
- }
- }
- else
- {
- for( sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++ )
- {
- const sal_uInt32 nPoints = pPoints[nPoly];
- if( nPoints > 1 )
- {
- const Point *pPtAry = ppPtAry[nPoly];
- CGContextMoveToPoint( maContextHolder.get(), pPtAry->getX(), pPtAry->getY() );
- pPtAry++;
- for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
- {
- CGContextAddLineToPoint( maContextHolder.get(), pPtAry->getX(), pPtAry->getY() );
- }
- CGContextClosePath(maContextHolder.get());
- }
- }
- }
-
- CGContextDrawPath( maContextHolder.get(), eMode );
-
- RefreshRect( leftX, topY, maxWidth, maxHeight );
-}
-
-void AquaSalGraphics::drawPolygon( sal_uInt32 nPoints, const Point *pPtAry )
-{
- if( nPoints <= 1 )
- return;
-
- if( !CheckContext() )
- return;
-
- tools::Long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
- getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
-
- CGPathDrawingMode eMode;
- if( IsBrushVisible() && IsPenVisible() )
- {
- eMode = kCGPathEOFillStroke;
- }
- else if( IsPenVisible() )
- {
- eMode = kCGPathStroke;
- }
- else if( IsBrushVisible() )
- {
- eMode = kCGPathEOFill;
- }
- else
- {
- SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" );
- return;
- }
-
- CGContextBeginPath( maContextHolder.get() );
-
- if( IsPenVisible() )
- {
- float fX, fY;
- alignLinePoint( pPtAry, fX, fY );
- CGContextMoveToPoint( maContextHolder.get(), fX, fY );
- pPtAry++;
- for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
- {
- alignLinePoint( pPtAry, fX, fY );
- CGContextAddLineToPoint( maContextHolder.get(), fX, fY );
- }
- }
- else
- {
- CGContextMoveToPoint( maContextHolder.get(), pPtAry->getX(), pPtAry->getY() );
- pPtAry++;
- for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
- {
- CGContextAddLineToPoint( maContextHolder.get(), pPtAry->getX(), pPtAry->getY() );
- }
- }
-
- CGContextClosePath( maContextHolder.get() );
- CGContextDrawPath( maContextHolder.get(), eMode );
- RefreshRect( nX, nY, nWidth, nHeight );
-}
-
-bool AquaSalGraphics::drawPolygonBezier( sal_uInt32, const Point*, const PolyFlags* )
-{
- return false;
-}
-
-bool AquaSalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
- const Point* const*, const PolyFlags* const* )
-{
- return false;
-}
-
-void AquaSalGraphics::drawRect(
- tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
-{
- if( !CheckContext() )
- return;
-
- CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) );
- if( IsPenVisible() )
- {
- aRect.origin.x += 0.5;
- aRect.origin.y += 0.5;
- aRect.size.width -= 1;
- aRect.size.height -= 1;
- }
-
- if( IsBrushVisible() )
- {
- CGContextFillRect( maContextHolder.get(), aRect );
- }
- if( IsPenVisible() )
- {
- CGContextStrokeRect( maContextHolder.get(), aRect );
- }
- RefreshRect( nX, nY, nWidth, nHeight );
-}
-
-void AquaSalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point *pPtAry )
-{
- if( nPoints < 1 )
- return;
-
- if( !CheckContext() )
- return;
-
- tools::Long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
- getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
-
- float fX, fY;
- CGContextBeginPath( maContextHolder.get() );
- alignLinePoint( pPtAry, fX, fY );
- CGContextMoveToPoint( maContextHolder.get(), fX, fY );
- pPtAry++;
-
- for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
- {
- alignLinePoint( pPtAry, fX, fY );
- CGContextAddLineToPoint( maContextHolder.get(), fX, fY );
- }
- CGContextStrokePath(maContextHolder.get());
-
- RefreshRect( nX, nY, nWidth, nHeight );
-}
-
-sal_uInt16 AquaSalGraphics::GetBitCount() const
-{
- sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24;
- return nBits;
-}
-
-std::shared_ptr<SalBitmap> AquaSalGraphics::getBitmap(
- tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY )
-{
- SAL_WARN_IF(!maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::getBitmap() with no layer this=" << this);
-
- ApplyXorContext();
-
- std::shared_ptr<QuartzSalBitmap> pBitmap = std::make_shared<QuartzSalBitmap>();
- if (!pBitmap->Create(maLayer, mnBitmapDepth, nX, nY, nDX, nDY, IsFlipped()))
- {
- pBitmap = nullptr;
- }
- return pBitmap;
-}
-
SystemGraphicsData AquaSalGraphics::GetGraphicsData() const
{
SystemGraphicsData aRes;
aRes.nSize = sizeof(aRes);
- aRes.rCGContext = maContextHolder.get();
+ aRes.rCGContext = maShared.maContextHolder.get();
return aRes;
}
-tools::Long AquaSalGraphics::GetGraphicsWidth() const
-{
- tools::Long w = 0;
- if( maContextHolder.isSet() && (
-#ifndef IOS
- mbWindow ||
-#endif
- mbVirDev) )
- {
- w = mnWidth;
- }
-
-#ifndef IOS
- if( w == 0 )
- {
- if( mbWindow && mpFrame )
- {
- w = mpFrame->maGeometry.nWidth;
- }
- }
-#endif
- return w;
-}
-
-Color AquaSalGraphics::getPixel( tools::Long nX, tools::Long nY )
-{
- // return default value on printers or when out of bounds
- if (!maLayer.isSet() || (nX < 0) || (nX >= mnWidth) ||
- (nY < 0) || (nY >= mnHeight))
- {
- return COL_BLACK;
- }
- // prepare creation of matching a CGBitmapContext
-#if defined OSL_BIGENDIAN
- struct{ unsigned char b, g, r, a; } aPixel;
-#else
- struct{ unsigned char a, r, g, b; } aPixel;
-#endif
-
- // create a one-pixel bitmap context
- // TODO: is it worth to cache it?
- CGContextRef xOnePixelContext =
- CGBitmapContextCreate( &aPixel, 1, 1, 8, 32,
- GetSalData()->mxRGBSpace,
- uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Big) );
-
- // update this graphics layer
- ApplyXorContext();
-
- // copy the requested pixel into the bitmap context
- if( IsFlipped() )
- {
- nY = mnHeight - nY;
- }
- const CGPoint aCGPoint = CGPointMake(-nX, -nY);
- CGContextDrawLayerAtPoint(xOnePixelContext, aCGPoint, maLayer.get());
-
- CGContextRelease( xOnePixelContext );
-
- Color nColor( aPixel.r, aPixel.g, aPixel.b );
- return nColor;
-}
-
-void AquaSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
-{
-#ifndef IOS
- if( !mnRealDPIY )
- {
- initResolution( (mbWindow && mpFrame) ? mpFrame->getNSWindow() : nil );
- }
-
- rDPIX = mnRealDPIX;
- rDPIY = mnRealDPIY;
-#else
- // This *must* be 96 or else the iOS app will behave very badly (tiles are scaled wrongly and
- // don't match each others at their boundaries, and other issues). But *why* it must be 96 I
- // have no idea. The commit that changed it to 96 from (the arbitrary) 200 did not say. If you
- // know where else 96 is explicitly or implicitly hard-coded, please modify this comment.
-
- // Follow-up: It might be this: in 'online', loleaflet/src/map/Map.js:
- // 15 = 1440 twips-per-inch / 96 dpi.
- // Chosen to match previous hardcoded value of 3840 for
- // the current tile pixel size of 256.
- rDPIX = rDPIY = 96;
-#endif
-}
-
-void AquaSalGraphics::ImplDrawPixel( tools::Long nX, tools::Long nY, const RGBAColor& rColor )
-{
- if( !CheckContext() )
- {
- return;
- }
- // overwrite the fill color
- CGContextSetFillColor( maContextHolder.get(), rColor.AsArray() );
- // draw 1x1 rect, there is no pixel drawing in Quartz
- const CGRect aDstRect = CGRectMake(nX, nY, 1, 1);
- CGContextFillRect( maContextHolder.get(), aDstRect );
- RefreshRect( aDstRect );
- // reset the fill color
- CGContextSetFillColor( maContextHolder.get(), maFillColor.AsArray() );
-}
-
#ifndef IOS
void AquaSalGraphics::initResolution(NSWindow* nsWindow)
@@ -1222,302 +229,27 @@ void AquaSalGraphics::initResolution(NSWindow* nsWindow)
#endif
-void AquaSalGraphics::invert(
- tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, SalInvert nFlags )
-{
- if ( CheckContext() )
- {
- CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight);
- maContextHolder.saveState();
- if ( nFlags & SalInvert::TrackFrame )
- {
- const CGFloat dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference );
- CGContextSetRGBStrokeColor ( maContextHolder.get(), 1.0, 1.0, 1.0, 1.0 );
- CGContextSetLineDash ( maContextHolder.get(), 0, dashLengths, 2 );
- CGContextSetLineWidth( maContextHolder.get(), 2.0);
- CGContextStrokeRect ( maContextHolder.get(), aCGRect );
- }
- else if ( nFlags & SalInvert::N50 )
- {
- //CGContextSetAllowsAntialiasing( maContextHolder.get(), false );
- CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference);
- CGContextAddRect( maContextHolder.get(), aCGRect );
- Pattern50Fill();
- }
- else // just invert
- {
- CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference);
- CGContextSetRGBFillColor ( maContextHolder.get(),1.0, 1.0, 1.0 , 1.0 );
- CGContextFillRect ( maContextHolder.get(), aCGRect );
- }
- maContextHolder.restoreState();
- RefreshRect( aCGRect );
- }
-}
-
-namespace {
-
-CGPoint* makeCGptArray(sal_uInt32 nPoints, const Point* pPtAry)
-{
- CGPoint *CGpoints = new CGPoint[nPoints];
- for(sal_uLong i=0;i<nPoints;i++)
- {
- CGpoints[i].x = pPtAry[i].getX();
- CGpoints[i].y = pPtAry[i].getY();
- }
- return CGpoints;
-}
-
-}
-
-void AquaSalGraphics::invert( sal_uInt32 nPoints, const Point* pPtAry, SalInvert nSalFlags )
-{
- if ( CheckContext() )
- {
- maContextHolder.saveState();
- CGPoint* CGpoints = makeCGptArray(nPoints,pPtAry);
- CGContextAddLines ( maContextHolder.get(), CGpoints, nPoints );
- if ( nSalFlags & SalInvert::TrackFrame )
- {
- const CGFloat dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference );
- CGContextSetRGBStrokeColor ( maContextHolder.get(), 1.0, 1.0, 1.0, 1.0 );
- CGContextSetLineDash ( maContextHolder.get(), 0, dashLengths, 2 );
- CGContextSetLineWidth( maContextHolder.get(), 2.0);
- CGContextStrokePath ( maContextHolder.get() );
- }
- else if ( nSalFlags & SalInvert::N50 )
- {
- CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference);
- Pattern50Fill();
- }
- else // just invert
- {
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference );
- CGContextSetRGBFillColor( maContextHolder.get(), 1.0, 1.0, 1.0, 1.0 );
- CGContextFillPath( maContextHolder.get() );
- }
- const CGRect aRefreshRect = CGContextGetClipBoundingBox(maContextHolder.get());
- maContextHolder.restoreState();
- delete [] CGpoints;
- RefreshRect( aRefreshRect );
- }
-}
-
-void AquaSalGraphics::Pattern50Fill()
-{
- static const CGFloat aFillCol[4] = { 1,1,1,1 };
- static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, nullptr };
- static const CGColorSpaceRef mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace );
- static const CGPatternRef mxP50Pattern = CGPatternCreate( nullptr, CGRectMake( 0, 0, 4, 4 ),
- CGAffineTransformIdentity, 4, 4,
- kCGPatternTilingConstantSpacing,
- false, &aCallback );
- SAL_WARN_IF( !maContextHolder.get(), "vcl.quartz", "maContextHolder.get() is NULL" );
- CGContextSetFillColorSpace( maContextHolder.get(), mxP50Space );
- CGContextSetFillPattern( maContextHolder.get(), mxP50Pattern, aFillCol );
- CGContextFillPath( maContextHolder.get() );
-}
-
-void AquaSalGraphics::ResetClipRegion()
-{
- // release old path and indicate no clipping
- if( mxClipPath )
- {
- CGPathRelease( mxClipPath );
- mxClipPath = nullptr;
- }
- if( CheckContext() )
- {
- SetState();
- }
-}
-
-void AquaSalGraphics::SetState()
+void AquaSharedAttributes::setState()
{
maContextHolder.restoreState();
maContextHolder.saveState();
// setup clipping
- if( mxClipPath )
+ if (mxClipPath)
{
- CGContextBeginPath( maContextHolder.get() ); // discard any existing path
- CGContextAddPath( maContextHolder.get(), mxClipPath ); // set the current path to the clipping path
- CGContextClip( maContextHolder.get() ); // use it for clipping
+ CGContextBeginPath(maContextHolder.get()); // discard any existing path
+ CGContextAddPath(maContextHolder.get(), mxClipPath); // set the current path to the clipping path
+ CGContextClip(maContextHolder.get()); // use it for clipping
}
// set RGB colorspace and line and fill colors
- CGContextSetFillColor( maContextHolder.get(), maFillColor.AsArray() );
+ CGContextSetFillColor(maContextHolder.get(), maFillColor.AsArray() );
- CGContextSetStrokeColor( maContextHolder.get(), maLineColor.AsArray() );
- CGContextSetShouldAntialias( maContextHolder.get(), false );
- if( mnXorMode == 2 )
- {
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference );
- }
-}
-
-void AquaSalGraphics::SetLineColor()
-{
- maLineColor.SetAlpha( 0.0 ); // transparent
- if( CheckContext() )
- {
- CGContextSetRGBStrokeColor( maContextHolder.get(), maLineColor.GetRed(), maLineColor.GetGreen(),
- maLineColor.GetBlue(), maLineColor.GetAlpha() );
- }
-}
-
-void AquaSalGraphics::SetLineColor( Color nColor )
-{
- maLineColor = RGBAColor( nColor );
- if( CheckContext() )
- {
- CGContextSetRGBStrokeColor( maContextHolder.get(), maLineColor.GetRed(), maLineColor.GetGreen(),
- maLineColor.GetBlue(), maLineColor.GetAlpha() );
- }
-}
-
-void AquaSalGraphics::SetFillColor()
-{
- maFillColor.SetAlpha( 0.0 ); // transparent
- if( CheckContext() )
- {
- CGContextSetRGBFillColor( maContextHolder.get(), maFillColor.GetRed(), maFillColor.GetGreen(),
- maFillColor.GetBlue(), maFillColor.GetAlpha() );
- }
-}
-
-void AquaSalGraphics::SetFillColor( Color nColor )
-{
- maFillColor = RGBAColor( nColor );
- if( CheckContext() )
- {
- CGContextSetRGBFillColor( maContextHolder.get(), maFillColor.GetRed(), maFillColor.GetGreen(),
- maFillColor.GetBlue(), maFillColor.GetAlpha() );
- }
-}
-
-bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const
-{
- bool bRet = false;
- switch( eType )
- {
- case OutDevSupportType::TransparentRect:
- case OutDevSupportType::B2DDraw:
- bRet = true;
- break;
- default:
- break;
- }
- return bRet;
-}
-
-bool AquaSalGraphics::setClipRegion( const vcl::Region& i_rClip )
-{
- // release old clip path
- if( mxClipPath )
- {
- CGPathRelease( mxClipPath );
- mxClipPath = nullptr;
- }
- mxClipPath = CGPathCreateMutable();
-
- // set current path, either as polypolgon or sequence of rectangles
- RectangleVector aRectangles;
- i_rClip.GetRegionRectangles(aRectangles);
-
- for(const auto& rRect : aRectangles)
- {
- const tools::Long nW(rRect.Right() - rRect.Left() + 1); // uses +1 logic in original
-
- if(nW)
- {
- const tools::Long nH(rRect.Bottom() - rRect.Top() + 1); // uses +1 logic in original
-
- if(nH)
- {
- const CGRect aRect = CGRectMake( rRect.Left(), rRect.Top(), nW, nH);
- CGPathAddRect( mxClipPath, nullptr, aRect );
- }
- }
- }
- // set the current path as clip region
- if( CheckContext() )
- {
- SetState();
- }
- return true;
-}
-
-void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor )
-{
- if( ! mbPrinter )
- {
- SetFillColor( ImplGetROPColor( nROPColor ) );
- }
-}
-
-void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor )
-{
- if( ! mbPrinter )
- {
- SetLineColor( ImplGetROPColor( nROPColor ) );
- }
-}
-
-void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
-{
- // return early if XOR mode remains unchanged
- if( mbPrinter )
- {
- return;
- }
- if( ! bSet && mnXorMode == 2 )
- {
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeNormal );
- mnXorMode = 0;
- return;
- }
- else if( bSet && bInvertOnly && mnXorMode == 0)
- {
- CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference );
- mnXorMode = 2;
- return;
- }
-
- if (!mpXorEmulation && !bSet)
- {
- return;
- }
- if (mpXorEmulation && bSet == mpXorEmulation->IsEnabled())
- {
- return;
- }
- if( !CheckContext() )
- {
- return;
- }
- // prepare XOR emulation
- if (!mpXorEmulation)
- {
- mpXorEmulation = std::make_unique<XorEmulation>();
- mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
- }
-
- // change the XOR mode
- if( bSet )
- {
- mpXorEmulation->Enable();
- maContextHolder.set(mpXorEmulation->GetMaskContext());
- mnXorMode = 1;
- }
- else
+ CGContextSetStrokeColor(maContextHolder.get(), maLineColor.AsArray() );
+ CGContextSetShouldAntialias(maContextHolder.get(), false );
+ if (mnXorMode == 2)
{
- mpXorEmulation->UpdateTarget();
- mpXorEmulation->Disable();
- maContextHolder.set(mpXorEmulation->GetTargetContext());
- mnXorMode = 0;
+ CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference );
}
}
@@ -1525,9 +257,9 @@ void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
void AquaSalGraphics::updateResolution()
{
- SAL_WARN_IF( !mbWindow, "vcl", "updateResolution on inappropriate graphics" );
+ SAL_WARN_IF(!maShared.mbWindow, "vcl", "updateResolution on inappropriate graphics");
- initResolution( (mbWindow && mpFrame) ? mpFrame->getNSWindow() : nil );
+ initResolution((maShared.mbWindow && maShared.mpFrame) ? maShared.mpFrame->getNSWindow() : nil);
}
#endif