1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/extensions/Xrender.h>
23
24
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolypolygon.hxx>
27 #include <basegfx/polygon/b2dpolypolygontools.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <basegfx/curve/b2dcubicbezier.hxx>
30
31 #include <headless/svpgdi.hxx>
32
33 #include <vcl/sysdata.hxx>
34 #include <vcl/virdev.hxx>
35 #include <sal/log.hxx>
36
37 #include <unx/salunx.h>
38 #include <unx/saldisp.hxx>
39 #include <unx/salgdi.h>
40 #include <unx/x11/xlimits.hxx>
41
42 #include <salframe.hxx>
43 #include <salgdiimpl.hxx>
44 #include <textrender.hxx>
45 #include <salvd.hxx>
46 #include "gdiimpl.hxx"
47
48 #include <unx/x11/x11cairotextrender.hxx>
49 #include <unx/x11/xrender_peer.hxx>
50 #include "cairo_xlib_cairo.hxx"
51 #include <cairo-xlib.h>
52
53 #include <config_features.h>
54 #include <vcl/skia/SkiaHelper.hxx>
55 #if HAVE_FEATURE_SKIA
56 #include <skia/x11/gdiimpl.hxx>
57 #include <skia/x11/textrender.hxx>
58 #endif
59
X11SalGraphics()60 X11SalGraphics::X11SalGraphics():
61 m_pFrame(nullptr),
62 m_pVDev(nullptr),
63 m_pColormap(nullptr),
64 hDrawable_(None),
65 m_pExternalSurface(nullptr),
66 m_nXScreen( 0 ),
67 m_pXRenderFormat(nullptr),
68 m_aXRenderPicture(0),
69 mpClipRegion(nullptr),
70 #if ENABLE_CAIRO_CANVAS
71 maClipRegion(),
72 mnPenColor(SALCOLOR_NONE),
73 mnFillColor(SALCOLOR_NONE),
74 #endif // ENABLE_CAIRO_CANVAS
75 hBrush_(None),
76 bWindow_(false),
77 bVirDev_(false),
78 m_bSkia(SkiaHelper::isVCLSkiaEnabled())
79 {
80 #if HAVE_FEATURE_SKIA
81 if (m_bSkia)
82 {
83 mxImpl.reset(new X11SkiaSalGraphicsImpl(*this));
84 mxTextRenderImpl.reset(new SkiaTextRender);
85 }
86 else
87 #endif
88 {
89 mxTextRenderImpl.reset(new X11CairoTextRender(*this));
90 mxImpl.reset(new X11SalGraphicsImpl(*this));
91 }
92
93 }
94
~X11SalGraphics()95 X11SalGraphics::~X11SalGraphics() COVERITY_NOEXCEPT_FALSE
96 {
97 DeInit();
98 ReleaseFonts();
99 freeResources();
100 }
101
freeResources()102 void X11SalGraphics::freeResources()
103 {
104 Display *pDisplay = GetXDisplay();
105
106 if( mpClipRegion )
107 {
108 XDestroyRegion( mpClipRegion );
109 mpClipRegion = None;
110 }
111
112 mxImpl->freeResources();
113
114 if( hBrush_ )
115 {
116 XFreePixmap( pDisplay, hBrush_ );
117 hBrush_ = None;
118 }
119 if( m_pDeleteColormap )
120 {
121 m_pDeleteColormap.reset();
122 m_pColormap = nullptr;
123 }
124 if( m_aXRenderPicture )
125 {
126 XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
127 m_aXRenderPicture = 0;
128 }
129 }
130
GetImpl() const131 SalGraphicsImpl* X11SalGraphics::GetImpl() const
132 {
133 return mxImpl.get();
134 }
135
SetDrawable(Drawable aDrawable,cairo_surface_t * pExternalSurface,SalX11Screen nXScreen)136 void X11SalGraphics::SetDrawable(Drawable aDrawable, cairo_surface_t* pExternalSurface, SalX11Screen nXScreen)
137 {
138 m_pExternalSurface = pExternalSurface;
139
140 // shortcut if nothing changed
141 if( hDrawable_ == aDrawable )
142 return;
143
144 // free screen specific resources if needed
145 if( nXScreen != m_nXScreen )
146 {
147 freeResources();
148 m_pColormap = &vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetColormap( nXScreen );
149 m_nXScreen = nXScreen;
150 }
151
152 hDrawable_ = aDrawable;
153 SetXRenderFormat( nullptr );
154 if( m_aXRenderPicture )
155 {
156 XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
157 m_aXRenderPicture = 0;
158 }
159 }
160
Init(SalFrame * pFrame,Drawable aTarget,SalX11Screen nXScreen)161 void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
162 SalX11Screen nXScreen )
163 {
164 m_pColormap = &vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetColormap(nXScreen);
165 m_nXScreen = nXScreen;
166
167 m_pFrame = pFrame;
168 m_pVDev = nullptr;
169
170 bWindow_ = true;
171 bVirDev_ = false;
172
173 SetDrawable(aTarget, nullptr, nXScreen);
174 mxImpl->Init();
175 }
176
DeInit()177 void X11SalGraphics::DeInit()
178 {
179 mxImpl->DeInit();
180 SetDrawable(None, nullptr, m_nXScreen);
181 }
182
SetClipRegion(GC pGC,Region pXReg) const183 void X11SalGraphics::SetClipRegion( GC pGC, Region pXReg ) const
184 {
185 Display *pDisplay = GetXDisplay();
186
187 int n = 0;
188 Region Regions[3];
189
190 if( mpClipRegion )
191 Regions[n++] = mpClipRegion;
192
193 if( pXReg && !XEmptyRegion( pXReg ) )
194 Regions[n++] = pXReg;
195
196 if( 0 == n )
197 XSetClipMask( pDisplay, pGC, None );
198 else if( 1 == n )
199 XSetRegion( pDisplay, pGC, Regions[0] );
200 else
201 {
202 Region pTmpRegion = XCreateRegion();
203 XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
204
205 XSetRegion( pDisplay, pGC, pTmpRegion );
206 XDestroyRegion( pTmpRegion );
207 }
208 }
209
210 // Calculate a dither-pixmap and make a brush of it
211 #define P_DELTA 51
212 #define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
213
GetDitherPixmap(Color nColor)214 bool X11SalGraphics::GetDitherPixmap( Color nColor )
215 {
216 static const short nOrdDither8Bit[ 8 ][ 8 ] =
217 {
218 { 0, 38, 9, 48, 2, 40, 12, 50},
219 {25, 12, 35, 22, 28, 15, 37, 24},
220 { 6, 44, 3, 41, 8, 47, 5, 44},
221 {32, 19, 28, 16, 34, 21, 31, 18},
222 { 1, 40, 11, 49, 0, 39, 10, 48},
223 {27, 14, 36, 24, 26, 13, 36, 23},
224 { 8, 46, 4, 43, 7, 45, 4, 42},
225 {33, 20, 30, 17, 32, 20, 29, 16}
226 };
227
228 // test for correct depth (8bit)
229 if( GetColormap().GetVisual().GetDepth() != 8 )
230 return false;
231
232 char pBits[64];
233 char *pBitsPtr = pBits;
234
235 // Set the palette-entries for the dithering tile
236 sal_uInt8 nColorRed = nColor.GetRed();
237 sal_uInt8 nColorGreen = nColor.GetGreen();
238 sal_uInt8 nColorBlue = nColor.GetBlue();
239
240 for(auto & nY : nOrdDither8Bit)
241 {
242 for( int nX = 0; nX < 8; nX++ )
243 {
244 short nMagic = nY[nX];
245 sal_uInt8 nR = P_DELTA * DMAP( nColorRed, nMagic );
246 sal_uInt8 nG = P_DELTA * DMAP( nColorGreen, nMagic );
247 sal_uInt8 nB = P_DELTA * DMAP( nColorBlue, nMagic );
248
249 *pBitsPtr++ = GetColormap().GetPixel( Color( nR, nG, nB ) );
250 }
251 }
252
253 // create the tile as ximage and an according pixmap -> caching
254 XImage *pImage = XCreateImage( GetXDisplay(),
255 GetColormap().GetXVisual(),
256 8,
257 ZPixmap,
258 0, // offset
259 pBits, // data
260 8, 8, // width & height
261 8, // bitmap_pad
262 0 ); // (default) bytes_per_line
263
264 if( !hBrush_ )
265 hBrush_ = limitXCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
266
267 // put the ximage to the pixmap
268 XPutImage( GetXDisplay(),
269 hBrush_,
270 GetDisplay()->GetCopyGC( m_nXScreen ),
271 pImage,
272 0, 0, // Source
273 0, 0, // Destination
274 8, 8 ); // width & height
275
276 // destroy image-frame but not palette-data
277 pImage->data = nullptr;
278 XDestroyImage( pImage );
279
280 return true;
281 }
282
GetResolution(sal_Int32 & rDPIX,sal_Int32 & rDPIY)283 void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
284 {
285 char* pForceDpi;
286 if ((pForceDpi = getenv("SAL_FORCEDPI")))
287 {
288 OString sForceDPI(pForceDpi);
289 rDPIX = rDPIY = sForceDPI.toInt32();
290 return;
291 }
292
293 const SalDisplay *pDisplay = GetDisplay();
294 if (!pDisplay)
295 {
296 SAL_WARN( "vcl", "Null display");
297 rDPIX = rDPIY = 96;
298 return;
299 }
300
301 Pair dpi = pDisplay->GetResolution();
302 rDPIX = dpi.A();
303 rDPIY = dpi.B();
304
305 if ( rDPIY > 200 )
306 {
307 rDPIX = Divide( rDPIX * 200, rDPIY );
308 rDPIY = 200;
309 }
310
311 // #i12705# equalize x- and y-resolution if they are close enough
312 if( rDPIX == rDPIY )
313 return;
314
315 // different x- and y- resolutions are usually artifacts of
316 // a wrongly calculated screen size.
317 #ifdef DEBUG
318 SAL_INFO("vcl.gdi", "Forcing Resolution from "
319 << std::hex << rDPIX
320 << std::dec << rDPIX
321 << " to "
322 << std::hex << rDPIY
323 << std::dec << rDPIY);
324 #endif
325 rDPIX = rDPIY; // y-resolution is more trustworthy
326 }
327
GetBitCount() const328 sal_uInt16 X11SalGraphics::GetBitCount() const
329 {
330 return mxImpl->GetBitCount();
331 }
332
GetGraphicsWidth() const333 tools::Long X11SalGraphics::GetGraphicsWidth() const
334 {
335 return mxImpl->GetGraphicsWidth();
336 }
337
ResetClipRegion()338 void X11SalGraphics::ResetClipRegion()
339 {
340 #if ENABLE_CAIRO_CANVAS
341 maClipRegion.SetNull();
342 #endif
343 mxImpl->ResetClipRegion();
344 }
345
setClipRegion(const vcl::Region & i_rClip)346 bool X11SalGraphics::setClipRegion( const vcl::Region& i_rClip )
347 {
348 #if ENABLE_CAIRO_CANVAS
349 maClipRegion = i_rClip;
350 #endif
351 return mxImpl->setClipRegion( i_rClip );
352 }
353
SetLineColor()354 void X11SalGraphics::SetLineColor()
355 {
356 #if ENABLE_CAIRO_CANVAS
357 mnPenColor = SALCOLOR_NONE;
358 #endif // ENABLE_CAIRO_CANVAS
359
360 mxImpl->SetLineColor();
361 }
362
SetLineColor(Color nColor)363 void X11SalGraphics::SetLineColor( Color nColor )
364 {
365 #if ENABLE_CAIRO_CANVAS
366 mnPenColor = nColor;
367 #endif // ENABLE_CAIRO_CANVAS
368
369 mxImpl->SetLineColor( nColor );
370 }
371
SetFillColor()372 void X11SalGraphics::SetFillColor()
373 {
374 #if ENABLE_CAIRO_CANVAS
375 mnFillColor = SALCOLOR_NONE;
376 #endif // ENABLE_CAIRO_CANVAS
377
378 mxImpl->SetFillColor();
379 }
380
SetFillColor(Color nColor)381 void X11SalGraphics::SetFillColor( Color nColor )
382 {
383 #if ENABLE_CAIRO_CANVAS
384 mnFillColor = nColor;
385 #endif // ENABLE_CAIRO_CANVAS
386
387 mxImpl->SetFillColor( nColor );
388 }
389
SetROPLineColor(SalROPColor nROPColor)390 void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
391 {
392 mxImpl->SetROPLineColor( nROPColor );
393 }
394
SetROPFillColor(SalROPColor nROPColor)395 void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
396 {
397 mxImpl->SetROPFillColor( nROPColor );
398 }
399
SetXORMode(bool bSet,bool bInvertOnly)400 void X11SalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
401 {
402 mxImpl->SetXORMode( bSet, bInvertOnly );
403 }
404
drawPixel(tools::Long nX,tools::Long nY)405 void X11SalGraphics::drawPixel( tools::Long nX, tools::Long nY )
406 {
407 mxImpl->drawPixel( nX, nY );
408 }
409
drawPixel(tools::Long nX,tools::Long nY,Color nColor)410 void X11SalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
411 {
412 mxImpl->drawPixel( nX, nY, nColor );
413 }
414
drawLine(tools::Long nX1,tools::Long nY1,tools::Long nX2,tools::Long nY2)415 void X11SalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
416 {
417 mxImpl->drawLine( nX1, nY1, nX2, nY2 );
418 }
419
drawRect(tools::Long nX,tools::Long nY,tools::Long nDX,tools::Long nDY)420 void X11SalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY )
421 {
422 mxImpl->drawRect( nX, nY, nDX, nDY );
423 }
424
drawPolyLine(sal_uInt32 nPoints,const Point * pPtAry)425 void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point *pPtAry )
426 {
427 mxImpl->drawPolyLine( nPoints, pPtAry );
428 }
429
drawPolygon(sal_uInt32 nPoints,const Point * pPtAry)430 void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
431 {
432 mxImpl->drawPolygon( nPoints, pPtAry );
433 }
434
drawPolyPolygon(sal_uInt32 nPoly,const sal_uInt32 * pPoints,const Point ** pPtAry)435 void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
436 const sal_uInt32 *pPoints,
437 const Point* *pPtAry )
438 {
439 mxImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
440 }
441
drawPolyLineBezier(sal_uInt32 nPoints,const Point * pPtAry,const PolyFlags * pFlgAry)442 bool X11SalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
443 {
444 return mxImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
445 }
446
drawPolygonBezier(sal_uInt32 nPoints,const Point * pPtAry,const PolyFlags * pFlgAry)447 bool X11SalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
448 {
449 return mxImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
450 }
451
drawPolyPolygonBezier(sal_uInt32 nPoints,const sal_uInt32 * pPoints,const Point * const * pPtAry,const PolyFlags * const * pFlgAry)452 bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoints, const sal_uInt32* pPoints,
453 const Point* const* pPtAry, const PolyFlags* const* pFlgAry)
454 {
455 return mxImpl->drawPolyPolygonBezier( nPoints, pPoints, pPtAry, pFlgAry );
456 }
457
invert(sal_uInt32 nPoints,const Point * pPtAry,SalInvert nFlags)458 void X11SalGraphics::invert( sal_uInt32 nPoints,
459 const Point* pPtAry,
460 SalInvert nFlags )
461 {
462 mxImpl->invert( nPoints, pPtAry, nFlags );
463 }
464
drawEPS(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight,void * pPtr,sal_uInt32 nSize)465 bool X11SalGraphics::drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth,
466 tools::Long nHeight, void* pPtr, sal_uInt32 nSize )
467 {
468 return mxImpl->drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize );
469 }
470
GetXRenderFormat() const471 XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const
472 {
473 if( m_pXRenderFormat == nullptr )
474 m_pXRenderFormat = XRenderPeer::GetInstance().FindVisualFormat( GetVisual().visual );
475 return m_pXRenderFormat;
476 }
477
GetGraphicsData() const478 SystemGraphicsData X11SalGraphics::GetGraphicsData() const
479 {
480 SystemGraphicsData aRes;
481
482 aRes.nSize = sizeof(aRes);
483 aRes.pDisplay = GetXDisplay();
484 aRes.hDrawable = hDrawable_;
485 aRes.pVisual = GetVisual().visual;
486 aRes.nScreen = m_nXScreen.getXScreen();
487 aRes.pXRenderFormat = m_pXRenderFormat;
488 return aRes;
489 }
490
Flush()491 void X11SalGraphics::Flush()
492 {
493 if( X11GraphicsImpl* x11Impl = dynamic_cast< X11GraphicsImpl* >( mxImpl.get()))
494 x11Impl->Flush();
495 }
496
497 #if ENABLE_CAIRO_CANVAS
498
SupportsCairo() const499 bool X11SalGraphics::SupportsCairo() const
500 {
501 static bool bSupportsCairo = [this] {
502 Display *pDisplay = GetXDisplay();
503 int nDummy;
504 return XQueryExtension(pDisplay, "RENDER", &nDummy, &nDummy, &nDummy);
505 }();
506 return bSupportsCairo;
507 }
508
CreateSurface(const cairo::CairoSurfaceSharedPtr & rSurface) const509 cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const
510 {
511 return std::make_shared<cairo::X11Surface>(rSurface);
512 }
513
514 namespace
515 {
getSysData(const vcl::Window & rWindow)516 cairo::X11SysData getSysData( const vcl::Window& rWindow )
517 {
518 const SystemEnvData* pSysData = rWindow.GetSystemData();
519
520 if( !pSysData )
521 return cairo::X11SysData();
522 else
523 return cairo::X11SysData(*pSysData, rWindow.ImplGetFrame());
524 }
525
getSysData(const VirtualDevice & rVirDev)526 cairo::X11SysData getSysData( const VirtualDevice& rVirDev )
527 {
528 return cairo::X11SysData( rVirDev.GetSystemGfxData() );
529 }
530 }
531
CreateSurface(const OutputDevice & rRefDevice,int x,int y,int width,int height) const532 cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface( const OutputDevice& rRefDevice,
533 int x, int y, int width, int height ) const
534 {
535 if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
536 return std::make_shared<cairo::X11Surface>(getSysData(*rRefDevice.GetOwnerWindow()),
537 x,y,width,height);
538 if( rRefDevice.IsVirtual() )
539 return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const VirtualDevice&>(rRefDevice)),
540 x,y,width,height);
541 return cairo::SurfaceSharedPtr();
542 }
543
CreateBitmapSurface(const OutputDevice & rRefDevice,const BitmapSystemData & rData,const Size & rSize) const544 cairo::SurfaceSharedPtr X11SalGraphics::CreateBitmapSurface( const OutputDevice& rRefDevice,
545 const BitmapSystemData& rData,
546 const Size& rSize ) const
547 {
548 SAL_INFO("vcl", "requested size: " << rSize.Width() << " x " << rSize.Height()
549 << " available size: " << rData.mnWidth << " x "
550 << rData.mnHeight);
551 if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
552 {
553 if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
554 return std::make_shared<cairo::X11Surface>(getSysData(*rRefDevice.GetOwnerWindow()), rData );
555 else if( rRefDevice.IsVirtual() )
556 return std::make_shared<cairo::X11Surface>(getSysData(static_cast<const VirtualDevice&>(rRefDevice)), rData );
557 }
558
559 return cairo::SurfaceSharedPtr();
560 }
561
GetNativeSurfaceHandle(cairo::SurfaceSharedPtr & rSurface,const basegfx::B2ISize &) const562 css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& /*rSize*/) const
563 {
564 cairo::X11Surface& rXlibSurface=dynamic_cast<cairo::X11Surface&>(*rSurface);
565 css::uno::Sequence< css::uno::Any > args( 3 );
566 args[0] <<= false; // do not call XFreePixmap on it
567 args[1] <<= sal_Int64(rXlibSurface.getPixmap()->mhDrawable);
568 args[2] <<= sal_Int32( rXlibSurface.getDepth() );
569 return css::uno::Any(args);
570 }
571
572 #endif // ENABLE_CAIRO_CANVAS
573
574 // draw a poly-polygon
drawPolyPolygon(const basegfx::B2DHomMatrix & rObjectToDevice,const basegfx::B2DPolyPolygon & rPolyPolygon,double fTransparency)575 bool X11SalGraphics::drawPolyPolygon(
576 const basegfx::B2DHomMatrix& rObjectToDevice,
577 const basegfx::B2DPolyPolygon& rPolyPolygon,
578 double fTransparency)
579 {
580 if(fTransparency >= 1.0)
581 {
582 return true;
583 }
584
585 if(rPolyPolygon.count() == 0)
586 {
587 return true;
588 }
589
590 #if ENABLE_CAIRO_CANVAS
591 // Fallback: Transform to DeviceCoordinates
592 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
593 aPolyPolygon.transform(rObjectToDevice);
594
595 if(SALCOLOR_NONE == mnFillColor && SALCOLOR_NONE == mnPenColor)
596 {
597 return true;
598 }
599
600 // enable by setting to something
601 static const char* pUseCairoForPolygons(getenv("SAL_ENABLE_USE_CAIRO_FOR_POLYGONS"));
602
603 if (!m_bSkia && nullptr != pUseCairoForPolygons && SupportsCairo())
604 {
605 // snap to raster if requested
606 const bool bSnapPoints(!getAntiAlias());
607
608 if(bSnapPoints)
609 {
610 aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygon);
611 }
612
613 cairo_t* cr = getCairoContext();
614 clipRegion(cr);
615
616 for(auto const& rPolygon : aPolyPolygon)
617 {
618 const sal_uInt32 nPointCount(rPolygon.count());
619
620 if(nPointCount)
621 {
622 const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nPointCount : nPointCount - 1);
623
624 if(nEdgeCount)
625 {
626 basegfx::B2DCubicBezier aEdge;
627
628 for(sal_uInt32 b = 0; b < nEdgeCount; ++b)
629 {
630 rPolygon.getBezierSegment(b, aEdge);
631
632 if(!b)
633 {
634 const basegfx::B2DPoint aStart(aEdge.getStartPoint());
635 cairo_move_to(cr, aStart.getX(), aStart.getY());
636 }
637
638 const basegfx::B2DPoint aEnd(aEdge.getEndPoint());
639
640 if(aEdge.isBezier())
641 {
642 const basegfx::B2DPoint aCP1(aEdge.getControlPointA());
643 const basegfx::B2DPoint aCP2(aEdge.getControlPointB());
644 cairo_curve_to(cr,
645 aCP1.getX(), aCP1.getY(),
646 aCP2.getX(), aCP2.getY(),
647 aEnd.getX(), aEnd.getY());
648 }
649 else
650 {
651 cairo_line_to(cr, aEnd.getX(), aEnd.getY());
652 }
653 }
654
655 cairo_close_path(cr);
656 }
657 }
658 }
659
660 if(SALCOLOR_NONE != mnFillColor)
661 {
662 cairo_set_source_rgba(cr,
663 mnFillColor.GetRed()/255.0,
664 mnFillColor.GetGreen()/255.0,
665 mnFillColor.GetBlue()/255.0,
666 1.0 - fTransparency);
667 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
668 cairo_fill_preserve(cr);
669 }
670
671 if(SALCOLOR_NONE != mnPenColor)
672 {
673 cairo_set_source_rgba(cr,
674 mnPenColor.GetRed()/255.0,
675 mnPenColor.GetGreen()/255.0,
676 mnPenColor.GetBlue()/255.0,
677 1.0 - fTransparency);
678 cairo_stroke_preserve(cr);
679 }
680
681 releaseCairoContext(cr);
682 return true;
683 }
684 #endif // ENABLE_CAIRO_CANVAS
685
686 return mxImpl->drawPolyPolygon(
687 rObjectToDevice,
688 rPolyPolygon,
689 fTransparency);
690 }
691
692 #if ENABLE_CAIRO_CANVAS
clipRegion(cairo_t * cr)693 void X11SalGraphics::clipRegion(cairo_t* cr)
694 {
695 SvpSalGraphics::clipRegion(cr, maClipRegion);
696 }
697 #endif // ENABLE_CAIRO_CANVAS
698
drawPolyLine(const basegfx::B2DHomMatrix & rObjectToDevice,const basegfx::B2DPolygon & rPolygon,double fTransparency,double fLineWidth,const std::vector<double> * pStroke,basegfx::B2DLineJoin eLineJoin,css::drawing::LineCap eLineCap,double fMiterMinimumAngle,bool bPixelSnapHairline)699 bool X11SalGraphics::drawPolyLine(
700 const basegfx::B2DHomMatrix& rObjectToDevice,
701 const basegfx::B2DPolygon& rPolygon,
702 double fTransparency,
703 double fLineWidth,
704 const std::vector< double >* pStroke, // MM01
705 basegfx::B2DLineJoin eLineJoin,
706 css::drawing::LineCap eLineCap,
707 double fMiterMinimumAngle,
708 bool bPixelSnapHairline)
709 {
710 if(0 == rPolygon.count())
711 {
712 return true;
713 }
714
715 if(fTransparency >= 1.0)
716 {
717 return true;
718 }
719
720 #if ENABLE_CAIRO_CANVAS
721 // disable by setting to something
722 static const char* pUseCairoForFatLines(getenv("SAL_DISABLE_USE_CAIRO_FOR_FATLINES"));
723
724 if (!m_bSkia && nullptr == pUseCairoForFatLines && SupportsCairo())
725 {
726 cairo_t* cr = getCairoContext();
727 clipRegion(cr);
728
729 // Use the now available static drawPolyLine from the Cairo-Headless-Fallback
730 // that will take care of all needed stuff
731 const bool bRetval(
732 SvpSalGraphics::drawPolyLine(
733 cr,
734 nullptr,
735 mnPenColor,
736 getAntiAlias(),
737 rObjectToDevice,
738 rPolygon,
739 fTransparency,
740 fLineWidth,
741 pStroke, // MM01
742 eLineJoin,
743 eLineCap,
744 fMiterMinimumAngle,
745 bPixelSnapHairline));
746
747 releaseCairoContext(cr);
748
749 if(bRetval)
750 {
751 return true;
752 }
753 }
754 #endif // ENABLE_CAIRO_CANVAS
755
756 return mxImpl->drawPolyLine(
757 rObjectToDevice,
758 rPolygon,
759 fTransparency,
760 fLineWidth,
761 pStroke, // MM01
762 eLineJoin,
763 eLineCap,
764 fMiterMinimumAngle,
765 bPixelSnapHairline);
766 }
767
drawGradient(const tools::PolyPolygon & rPoly,const Gradient & rGradient)768 bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
769 {
770 return mxImpl->drawGradient(rPoly, rGradient);
771 }
772
implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon,SalGradient const & rGradient)773 bool X11SalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
774 {
775 return mxImpl->implDrawGradient(rPolyPolygon, rGradient);
776 }
777
GetGeometryProvider() const778 SalGeometryProvider *X11SalGraphics::GetGeometryProvider() const
779 {
780 if (m_pFrame)
781 return static_cast< SalGeometryProvider * >(m_pFrame);
782 else
783 return static_cast< SalGeometryProvider * >(m_pVDev);
784 }
785
getCairoContext()786 cairo_t* X11SalGraphics::getCairoContext()
787 {
788 if (m_pExternalSurface)
789 return cairo_create(m_pExternalSurface);
790
791 cairo_surface_t* surface = cairo_xlib_surface_create(GetXDisplay(), hDrawable_,
792 GetVisual().visual, SAL_MAX_INT16, SAL_MAX_INT16);
793
794 cairo_t *cr = cairo_create(surface);
795 cairo_surface_destroy(surface);
796
797 return cr;
798 }
799
releaseCairoContext(cairo_t * cr)800 void X11SalGraphics::releaseCairoContext(cairo_t* cr)
801 {
802 cairo_destroy(cr);
803 }
804
805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
806