diff options
Diffstat (limited to 'vcl/unx/generic/gdi/salgdi.cxx')
-rw-r--r-- | vcl/unx/generic/gdi/salgdi.cxx | 799 |
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: */ |