summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2021-04-07 23:36:57 +0900
committerTomaž Vajngerl <quikee@gmail.com>2021-04-30 12:20:27 +0200
commit560c9ec9e27e771d61f1396a1c87dd38e29099c1 (patch)
tree1308f18553052b83d3a2618c9fcc9bc8da1501dc /vcl
parent6b7c2fa65eb68be520ed4135cc245e33fa22e8bf (diff)
vcl: iOS/macOS - move graphic render func. into AquaGraphicsBackend
This change moves graphic rendering function under AquaSalGraphics into a new AquaGraphicsBackend, which inherits from SalGraphicsImpl. This is part of the refactoring to make it mandatory that a SalGraphics always has a SalGraphicsImpl associated, which will make it possible to simplify the SalGraphics interface and enable the posibility to implement alernative graphic backends (Skia). Common variables and attributes are moved to AquaSharedAttributes and are shared between SalGraphics and SalGraphicsImpl. Change-Id: Ie48da87002ec8e4011ba92fdc9170f3a86761517 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114701 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-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