summaryrefslogtreecommitdiffstats
path: root/vcl/unx/generic/gdi/salgdi.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/gdi/salgdi.cxx')
-rw-r--r--vcl/unx/generic/gdi/salgdi.cxx799
1 files changed, 799 insertions, 0 deletions
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
new file mode 100644
index 000000000..3ecbe013a
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -0,0 +1,799 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrender.h>
+
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+
+#include <headless/svpgdi.hxx>
+
+#include <vcl/sysdata.hxx>
+#include <vcl/virdev.hxx>
+#include <sal/log.hxx>
+
+#include <unx/salunx.h>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+#include <unx/x11/xlimits.hxx>
+
+#include <salframe.hxx>
+#include <salgdiimpl.hxx>
+#include <textrender.hxx>
+#include <salvd.hxx>
+#include "gdiimpl.hxx"
+#include <opengl/x11/gdiimpl.hxx>
+#include <unx/x11/x11cairotextrender.hxx>
+#include <opengl/x11/cairotextrender.hxx>
+
+#include <unx/x11/xrender_peer.hxx>
+#include "cairo_xlib_cairo.hxx"
+#include <cairo-xlib.h>
+
+#include <vcl/opengl/OpenGLHelper.hxx>
+
+#include <config_features.h>
+#include <vcl/skia/SkiaHelper.hxx>
+#if HAVE_FEATURE_SKIA
+#include <skia/x11/gdiimpl.hxx>
+#include <skia/x11/textrender.hxx>
+#endif
+
+X11SalGraphics::X11SalGraphics():
+ m_pFrame(nullptr),
+ m_pVDev(nullptr),
+ m_pColormap(nullptr),
+ hDrawable_(None),
+ m_nXScreen( 0 ),
+ m_pXRenderFormat(nullptr),
+ m_aXRenderPicture(0),
+ mpClipRegion(nullptr),
+#if ENABLE_CAIRO_CANVAS
+ maClipRegion(),
+ mnPenColor(SALCOLOR_NONE),
+ mnFillColor(SALCOLOR_NONE),
+#endif // ENABLE_CAIRO_CANVAS
+ nTextPixel_(0),
+ hBrush_(None),
+ bWindow_(false),
+ bVirDev_(false),
+ m_bOpenGL(OpenGLHelper::isVCLOpenGLEnabled()),
+ m_bSkia(SkiaHelper::isVCLSkiaEnabled())
+{
+#if HAVE_FEATURE_SKIA
+ if (m_bSkia)
+ {
+ mxImpl.reset(new X11SkiaSalGraphicsImpl(*this));
+ mxTextRenderImpl.reset(new SkiaTextRender);
+ }
+ else
+#endif
+ if (m_bOpenGL)
+ {
+ mxImpl.reset(new X11OpenGLSalGraphicsImpl(*this));
+ mxTextRenderImpl.reset(new OpenGLX11CairoTextRender(*this));
+ }
+ else
+ {
+ mxTextRenderImpl.reset(new X11CairoTextRender(*this));
+ mxImpl.reset(new X11SalGraphicsImpl(*this));
+ }
+
+}
+
+X11SalGraphics::~X11SalGraphics() COVERITY_NOEXCEPT_FALSE
+{
+ DeInit();
+ ReleaseFonts();
+ freeResources();
+}
+
+void X11SalGraphics::freeResources()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( mpClipRegion )
+ {
+ XDestroyRegion( mpClipRegion );
+ mpClipRegion = None;
+ }
+
+ mxImpl->freeResources();
+
+ if( hBrush_ )
+ {
+ XFreePixmap( pDisplay, hBrush_ );
+ hBrush_ = None;
+ }
+ if( m_pDeleteColormap )
+ {
+ m_pDeleteColormap.reset();
+ m_pColormap = nullptr;
+ }
+ if( m_aXRenderPicture )
+ {
+ XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
+ m_aXRenderPicture = 0;
+ }
+}
+
+SalGraphicsImpl* X11SalGraphics::GetImpl() const
+{
+ return mxImpl.get();
+}
+
+void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen )
+{
+ // shortcut if nothing changed
+ if( hDrawable_ == aDrawable )
+ return;
+
+ // free screen specific resources if needed
+ if( nXScreen != m_nXScreen )
+ {
+ freeResources();
+ m_pColormap = &vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetColormap( nXScreen );
+ m_nXScreen = nXScreen;
+ }
+
+ hDrawable_ = aDrawable;
+ SetXRenderFormat( nullptr );
+ if( m_aXRenderPicture )
+ {
+ XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
+ m_aXRenderPicture = 0;
+ }
+
+ // TODO: moggi: FIXME nTextPixel_ = GetPixel( nTextColor_ );
+}
+
+void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
+ SalX11Screen nXScreen )
+{
+ m_pColormap = &vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetColormap(nXScreen);
+ m_nXScreen = nXScreen;
+
+ m_pFrame = pFrame;
+ m_pVDev = nullptr;
+
+ bWindow_ = true;
+ bVirDev_ = false;
+
+ SetDrawable( aTarget, nXScreen );
+ mxImpl->Init();
+}
+
+void X11SalGraphics::DeInit()
+{
+ mxImpl->DeInit();
+ SetDrawable( None, m_nXScreen );
+}
+
+void X11SalGraphics::SetClipRegion( GC pGC, Region pXReg ) const
+{
+ Display *pDisplay = GetXDisplay();
+
+ int n = 0;
+ Region Regions[3];
+
+ if( mpClipRegion )
+ Regions[n++] = mpClipRegion;
+
+ if( pXReg && !XEmptyRegion( pXReg ) )
+ Regions[n++] = pXReg;
+
+ if( 0 == n )
+ XSetClipMask( pDisplay, pGC, None );
+ else if( 1 == n )
+ XSetRegion( pDisplay, pGC, Regions[0] );
+ else
+ {
+ Region pTmpRegion = XCreateRegion();
+ XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
+
+ XSetRegion( pDisplay, pGC, pTmpRegion );
+ XDestroyRegion( pTmpRegion );
+ }
+}
+
+// Calculate a dither-pixmap and make a brush of it
+#define P_DELTA 51
+#define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
+
+bool X11SalGraphics::GetDitherPixmap( Color nColor )
+{
+ static const short nOrdDither8Bit[ 8 ][ 8 ] =
+ {
+ { 0, 38, 9, 48, 2, 40, 12, 50},
+ {25, 12, 35, 22, 28, 15, 37, 24},
+ { 6, 44, 3, 41, 8, 47, 5, 44},
+ {32, 19, 28, 16, 34, 21, 31, 18},
+ { 1, 40, 11, 49, 0, 39, 10, 48},
+ {27, 14, 36, 24, 26, 13, 36, 23},
+ { 8, 46, 4, 43, 7, 45, 4, 42},
+ {33, 20, 30, 17, 32, 20, 29, 16}
+ };
+
+ // test for correct depth (8bit)
+ if( GetColormap().GetVisual().GetDepth() != 8 )
+ return false;
+
+ char pBits[64];
+ char *pBitsPtr = pBits;
+
+ // Set the palette-entries for the dithering tile
+ sal_uInt8 nColorRed = nColor.GetRed();
+ sal_uInt8 nColorGreen = nColor.GetGreen();
+ sal_uInt8 nColorBlue = nColor.GetBlue();
+
+ for(auto & nY : nOrdDither8Bit)
+ {
+ for( int nX = 0; nX < 8; nX++ )
+ {
+ short nMagic = nY[nX];
+ sal_uInt8 nR = P_DELTA * DMAP( nColorRed, nMagic );
+ sal_uInt8 nG = P_DELTA * DMAP( nColorGreen, nMagic );
+ sal_uInt8 nB = P_DELTA * DMAP( nColorBlue, nMagic );
+
+ *pBitsPtr++ = GetColormap().GetPixel( Color( nR, nG, nB ) );
+ }
+ }
+
+ // create the tile as ximage and an according pixmap -> caching
+ XImage *pImage = XCreateImage( GetXDisplay(),
+ GetColormap().GetXVisual(),
+ 8,
+ ZPixmap,
+ 0, // offset
+ pBits, // data
+ 8, 8, // width & height
+ 8, // bitmap_pad
+ 0 ); // (default) bytes_per_line
+
+ if( !hBrush_ )
+ hBrush_ = limitXCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
+
+ // put the ximage to the pixmap
+ XPutImage( GetXDisplay(),
+ hBrush_,
+ GetDisplay()->GetCopyGC( m_nXScreen ),
+ pImage,
+ 0, 0, // Source
+ 0, 0, // Destination
+ 8, 8 ); // width & height
+
+ // destroy image-frame but not palette-data
+ pImage->data = nullptr;
+ XDestroyImage( pImage );
+
+ return true;
+}
+
+void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
+{
+ char* pForceDpi;
+ if ((pForceDpi = getenv("SAL_FORCEDPI")))
+ {
+ OString sForceDPI(pForceDpi);
+ rDPIX = rDPIY = sForceDPI.toInt32();
+ return;
+ }
+
+ const SalDisplay *pDisplay = GetDisplay();
+ if (!pDisplay)
+ {
+ SAL_WARN( "vcl", "Null display");
+ rDPIX = rDPIY = 96;
+ return;
+ }
+
+ Pair dpi = pDisplay->GetResolution();
+ rDPIX = dpi.A();
+ rDPIY = dpi.B();
+
+ if ( rDPIY > 200 )
+ {
+ rDPIX = Divide( rDPIX * 200, rDPIY );
+ rDPIY = 200;
+ }
+
+ // #i12705# equalize x- and y-resolution if they are close enough
+ if( rDPIX != rDPIY )
+ {
+ // different x- and y- resolutions are usually artifacts of
+ // a wrongly calculated screen size.
+#ifdef DEBUG
+ SAL_INFO("vcl.gdi", "Forcing Resolution from "
+ << std::hex << rDPIX
+ << std::dec << rDPIX
+ << " to "
+ << std::hex << rDPIY
+ << std::dec << rDPIY);
+#endif
+ rDPIX = rDPIY; // y-resolution is more trustworthy
+ }
+}
+
+sal_uInt16 X11SalGraphics::GetBitCount() const
+{
+ return mxImpl->GetBitCount();
+}
+
+long X11SalGraphics::GetGraphicsWidth() const
+{
+ return mxImpl->GetGraphicsWidth();
+}
+
+void X11SalGraphics::ResetClipRegion()
+{
+#if ENABLE_CAIRO_CANVAS
+ maClipRegion.SetNull();
+#endif
+ mxImpl->ResetClipRegion();
+}
+
+bool X11SalGraphics::setClipRegion( const vcl::Region& i_rClip )
+{
+#if ENABLE_CAIRO_CANVAS
+ maClipRegion = i_rClip;
+#endif
+ return mxImpl->setClipRegion( i_rClip );
+}
+
+void X11SalGraphics::SetLineColor()
+{
+#if ENABLE_CAIRO_CANVAS
+ mnPenColor = SALCOLOR_NONE;
+#endif // ENABLE_CAIRO_CANVAS
+
+ mxImpl->SetLineColor();
+}
+
+void X11SalGraphics::SetLineColor( Color nColor )
+{
+#if ENABLE_CAIRO_CANVAS
+ mnPenColor = nColor;
+#endif // ENABLE_CAIRO_CANVAS
+
+ mxImpl->SetLineColor( nColor );
+}
+
+void X11SalGraphics::SetFillColor()
+{
+#if ENABLE_CAIRO_CANVAS
+ mnFillColor = SALCOLOR_NONE;
+#endif // ENABLE_CAIRO_CANVAS
+
+ mxImpl->SetFillColor();
+}
+
+void X11SalGraphics::SetFillColor( Color nColor )
+{
+#if ENABLE_CAIRO_CANVAS
+ mnFillColor = nColor;
+#endif // ENABLE_CAIRO_CANVAS
+
+ mxImpl->SetFillColor( nColor );
+}
+
+void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ mxImpl->SetROPLineColor( nROPColor );
+}
+
+void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ mxImpl->SetROPFillColor( nROPColor );
+}
+
+void X11SalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
+{
+ mxImpl->SetXORMode( bSet, bInvertOnly );
+}
+
+void X11SalGraphics::drawPixel( long nX, long nY )
+{
+ mxImpl->drawPixel( nX, nY );
+}
+
+void X11SalGraphics::drawPixel( long nX, long nY, Color nColor )
+{
+ mxImpl->drawPixel( nX, nY, nColor );
+}
+
+void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ mxImpl->drawLine( nX1, nY1, nX2, nY2 );
+}
+
+void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ mxImpl->drawRect( nX, nY, nDX, nDY );
+}
+
+void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry )
+{
+ mxImpl->drawPolyLine( nPoints, pPtAry );
+}
+
+void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
+{
+ mxImpl->drawPolygon( nPoints, pPtAry );
+}
+
+void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ mxImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
+}
+
+bool X11SalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry )
+{
+ return mxImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
+}
+
+bool X11SalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry )
+{
+ return mxImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
+}
+
+bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoints, const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry)
+{
+ return mxImpl->drawPolyPolygonBezier( nPoints, pPoints, pPtAry, pFlgAry );
+}
+
+void X11SalGraphics::invert( sal_uInt32 nPoints,
+ const SalPoint* pPtAry,
+ SalInvert nFlags )
+{
+ mxImpl->invert( nPoints, pPtAry, nFlags );
+}
+
+bool X11SalGraphics::drawEPS( long nX, long nY, long nWidth,
+ long nHeight, void* pPtr, sal_uInt32 nSize )
+{
+ return mxImpl->drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize );
+}
+
+XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const
+{
+ if( m_pXRenderFormat == nullptr )
+ m_pXRenderFormat = XRenderPeer::GetInstance().FindVisualFormat( GetVisual().visual );
+ return m_pXRenderFormat;
+}
+
+SystemGraphicsData X11SalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+
+ aRes.nSize = sizeof(aRes);
+ aRes.pDisplay = GetXDisplay();
+ aRes.hDrawable = hDrawable_;
+ aRes.pVisual = GetVisual().visual;
+ aRes.nScreen = m_nXScreen.getXScreen();
+ aRes.pXRenderFormat = m_pXRenderFormat;
+ return aRes;
+}
+
+#if ENABLE_CAIRO_CANVAS
+
+bool X11SalGraphics::SupportsCairo() const
+{
+ Display *pDisplay = GetXDisplay();
+ int nDummy;
+ return XQueryExtension(pDisplay, "RENDER", &nDummy, &nDummy, &nDummy);
+}
+
+cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const
+{
+ return std::make_shared<cairo::X11Surface>(rSurface);
+}
+
+namespace
+{
+ cairo::X11SysData getSysData( const vcl::Window& rWindow )
+ {
+ const SystemEnvData* pSysData = rWindow.GetSystemData();
+
+ if( !pSysData )
+ return cairo::X11SysData();
+ else
+ return cairo::X11SysData(*pSysData);
+ }
+
+ cairo::X11SysData getSysData( const VirtualDevice& rVirDev )
+ {
+ return cairo::X11SysData( rVirDev.GetSystemGfxData() );
+ }
+}
+
+cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface( const OutputDevice& rRefDevice,
+ int x, int y, int width, int height ) const
+{
+ if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
+ return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const vcl::Window&>(rRefDevice)),
+ x,y,width,height);
+ if( rRefDevice.IsVirtual() )
+ return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const VirtualDevice&>(rRefDevice)),
+ x,y,width,height);
+ return cairo::SurfaceSharedPtr();
+}
+
+cairo::SurfaceSharedPtr X11SalGraphics::CreateBitmapSurface( const OutputDevice& rRefDevice,
+ const BitmapSystemData& rData,
+ const Size& rSize ) const
+{
+ SAL_INFO("vcl", "requested size: " << rSize.Width() << " x " << rSize.Height()
+ << " available size: " << rData.mnWidth << " x "
+ << rData.mnHeight);
+ if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
+ {
+ if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
+ return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const vcl::Window&>(rRefDevice)), rData );
+ else if( rRefDevice.IsVirtual() )
+ return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const VirtualDevice&>(rRefDevice)), rData );
+ }
+
+ return cairo::SurfaceSharedPtr();
+}
+
+css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& /*rSize*/) const
+{
+ cairo::X11Surface& rXlibSurface=dynamic_cast<cairo::X11Surface&>(*rSurface);
+ css::uno::Sequence< css::uno::Any > args( 3 );
+ args[0] <<= false; // do not call XFreePixmap on it
+ args[1] <<= rXlibSurface.getPixmap()->mhDrawable;
+ args[2] <<= sal_Int32( rXlibSurface.getDepth() );
+ return css::uno::Any(args);
+}
+
+#endif // ENABLE_CAIRO_CANVAS
+
+// draw a poly-polygon
+bool X11SalGraphics::drawPolyPolygon(
+ const basegfx::B2DHomMatrix& rObjectToDevice,
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ double fTransparency)
+{
+ if(fTransparency >= 1.0)
+ {
+ return true;
+ }
+
+ if(rPolyPolygon.count() == 0)
+ {
+ return true;
+ }
+
+#if ENABLE_CAIRO_CANVAS
+ // Fallback: Transform to DeviceCoordinates
+ basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+ aPolyPolygon.transform(rObjectToDevice);
+
+ if(SALCOLOR_NONE == mnFillColor && SALCOLOR_NONE == mnPenColor)
+ {
+ return true;
+ }
+
+ // enable by setting to something
+ static const char* pUseCairoForPolygons(getenv("SAL_ENABLE_USE_CAIRO_FOR_POLYGONS"));
+
+ if (!m_bOpenGL && !m_bSkia && nullptr != pUseCairoForPolygons && SupportsCairo())
+ {
+ // snap to raster if requested
+ const bool bSnapPoints(!getAntiAliasB2DDraw());
+
+ if(bSnapPoints)
+ {
+ aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygon);
+ }
+
+ cairo_t* cr = getCairoContext();
+ clipRegion(cr);
+
+ for(auto const& rPolygon : aPolyPolygon)
+ {
+ const sal_uInt32 nPointCount(rPolygon.count());
+
+ if(nPointCount)
+ {
+ const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nPointCount : nPointCount - 1);
+
+ if(nEdgeCount)
+ {
+ basegfx::B2DCubicBezier aEdge;
+
+ for(sal_uInt32 b = 0; b < nEdgeCount; ++b)
+ {
+ rPolygon.getBezierSegment(b, aEdge);
+
+ if(!b)
+ {
+ const basegfx::B2DPoint aStart(aEdge.getStartPoint());
+ cairo_move_to(cr, aStart.getX(), aStart.getY());
+ }
+
+ const basegfx::B2DPoint aEnd(aEdge.getEndPoint());
+
+ if(aEdge.isBezier())
+ {
+ const basegfx::B2DPoint aCP1(aEdge.getControlPointA());
+ const basegfx::B2DPoint aCP2(aEdge.getControlPointB());
+ cairo_curve_to(cr,
+ aCP1.getX(), aCP1.getY(),
+ aCP2.getX(), aCP2.getY(),
+ aEnd.getX(), aEnd.getY());
+ }
+ else
+ {
+ cairo_line_to(cr, aEnd.getX(), aEnd.getY());
+ }
+ }
+
+ cairo_close_path(cr);
+ }
+ }
+ }
+
+ if(SALCOLOR_NONE != mnFillColor)
+ {
+ cairo_set_source_rgba(cr,
+ mnFillColor.GetRed()/255.0,
+ mnFillColor.GetGreen()/255.0,
+ mnFillColor.GetBlue()/255.0,
+ 1.0 - fTransparency);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill_preserve(cr);
+ }
+
+ if(SALCOLOR_NONE != mnPenColor)
+ {
+ cairo_set_source_rgba(cr,
+ mnPenColor.GetRed()/255.0,
+ mnPenColor.GetGreen()/255.0,
+ mnPenColor.GetBlue()/255.0,
+ 1.0 - fTransparency);
+ cairo_stroke_preserve(cr);
+ }
+
+ releaseCairoContext(cr);
+ return true;
+ }
+#endif // ENABLE_CAIRO_CANVAS
+
+ return mxImpl->drawPolyPolygon(
+ rObjectToDevice,
+ rPolyPolygon,
+ fTransparency);
+}
+
+#if ENABLE_CAIRO_CANVAS
+void X11SalGraphics::clipRegion(cairo_t* cr)
+{
+ SvpSalGraphics::clipRegion(cr, maClipRegion);
+}
+#endif // ENABLE_CAIRO_CANVAS
+
+bool X11SalGraphics::drawPolyLine(
+ const basegfx::B2DHomMatrix& rObjectToDevice,
+ const basegfx::B2DPolygon& rPolygon,
+ double fTransparency,
+ double fLineWidth,
+ const std::vector< double >* pStroke, // MM01
+ basegfx::B2DLineJoin eLineJoin,
+ css::drawing::LineCap eLineCap,
+ double fMiterMinimumAngle,
+ bool bPixelSnapHairline)
+{
+ if(0 == rPolygon.count())
+ {
+ return true;
+ }
+
+ if(fTransparency >= 1.0)
+ {
+ return true;
+ }
+
+#if ENABLE_CAIRO_CANVAS
+ // disable by setting to something
+ static const char* pUseCairoForFatLines(getenv("SAL_DISABLE_USE_CAIRO_FOR_FATLINES"));
+
+ if (!m_bOpenGL && !m_bSkia && nullptr == pUseCairoForFatLines && SupportsCairo())
+ {
+ cairo_t* cr = getCairoContext();
+ clipRegion(cr);
+
+ // Use the now available static drawPolyLine from the Cairo-Headless-Fallback
+ // that will take care of all needed stuff
+ const bool bRetval(
+ SvpSalGraphics::drawPolyLine(
+ cr,
+ nullptr,
+ mnPenColor,
+ getAntiAliasB2DDraw(),
+ rObjectToDevice,
+ rPolygon,
+ fTransparency,
+ fLineWidth,
+ pStroke, // MM01
+ eLineJoin,
+ eLineCap,
+ fMiterMinimumAngle,
+ bPixelSnapHairline));
+
+ releaseCairoContext(cr);
+
+ if(bRetval)
+ {
+ return true;
+ }
+ }
+#endif // ENABLE_CAIRO_CANVAS
+
+ return mxImpl->drawPolyLine(
+ rObjectToDevice,
+ rPolygon,
+ fTransparency,
+ fLineWidth,
+ pStroke, // MM01
+ eLineJoin,
+ eLineCap,
+ fMiterMinimumAngle,
+ bPixelSnapHairline);
+}
+
+bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
+{
+ return mxImpl->drawGradient(rPoly, rGradient);
+}
+
+SalGeometryProvider *X11SalGraphics::GetGeometryProvider() const
+{
+ if (m_pFrame)
+ return static_cast< SalGeometryProvider * >(m_pFrame);
+ else
+ return static_cast< SalGeometryProvider * >(m_pVDev);
+}
+
+cairo_t* X11SalGraphics::getCairoContext()
+{
+ cairo_surface_t* surface = cairo_xlib_surface_create(GetXDisplay(), hDrawable_,
+ GetVisual().visual, SAL_MAX_INT16, SAL_MAX_INT16);
+
+ cairo_t *cr = cairo_create(surface);
+ cairo_surface_destroy(surface);
+
+ return cr;
+}
+
+void X11SalGraphics::releaseCairoContext(cairo_t* cr)
+{
+ cairo_destroy(cr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */