nss: upgrade to release 3.73
[LibreOffice.git] / vcl / unx / generic / gdi / gdiimpl.cxx
blob97d9067d0be7f810bd8d7bdb05b80ab3a17c8f31
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <numeric>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/extensions/Xrender.h>
26 #include <X11/Xproto.h>
28 #include "gdiimpl.hxx"
30 #include <vcl/gradient.hxx>
31 #include <sal/log.hxx>
33 #include <unx/saldisp.hxx>
34 #include <unx/salbmp.h>
35 #include <unx/salgdi.h>
36 #include <unx/salvd.h>
37 #include <unx/x11/xlimits.hxx>
38 #include <salframe.hxx>
39 #include <unx/x11/xrender_peer.hxx>
41 #include <basegfx/polygon/b2dpolygon.hxx>
42 #include <basegfx/polygon/b2dpolypolygon.hxx>
43 #include <basegfx/polygon/b2dpolypolygontools.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/polygon/b2dpolygonclipper.hxx>
46 #include <basegfx/polygon/b2dlinegeometry.hxx>
47 #include <basegfx/matrix/b2dhommatrix.hxx>
48 #include <basegfx/matrix/b2dhommatrixtools.hxx>
49 #include <basegfx/polygon/b2dtrapezoid.hxx>
50 #include <basegfx/utils/systemdependentdata.hxx>
52 #undef SALGDI2_TESTTRANS
54 #if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
55 #define DBG_TESTTRANS( _def_drawable ) \
56 { \
57 XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
58 0, 0, \
59 rPosAry.mnDestWidth, rPosAry.mnDestHeight, \
60 0, 0 ); \
62 #else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
63 #define DBG_TESTTRANS( _def_drawable )
64 #endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
66 /* From <X11/Intrinsic.h> */
67 typedef unsigned long Pixel;
69 class SalPolyLine
71 std::vector<XPoint> Points_;
72 public:
73 SalPolyLine(sal_uLong nPoints, const Point *p)
74 : Points_(nPoints+1)
76 for (sal_uLong i = 0; i < nPoints; ++i)
78 Points_[i].x = static_cast<short>(p[i].getX());
79 Points_[i].y = static_cast<short>(p[i].getY());
81 Points_[nPoints] = Points_[0]; // close polyline
84 const XPoint &operator[](sal_uLong n) const
86 return Points_[n];
89 XPoint &operator[](sal_uLong n)
91 return Points_[n];
95 namespace
97 void setForeBack(XGCValues& rValues, const SalColormap& rColMap, const SalBitmap& rSalBitmap)
99 rValues.foreground = rColMap.GetWhitePixel();
100 rValues.background = rColMap.GetBlackPixel();
102 //fdo#33455 and fdo#80160 handle 1 bit depth pngs with palette entries
103 //to set fore/back colors
104 SalBitmap& rBitmap = const_cast<SalBitmap&>(rSalBitmap);
105 BitmapBuffer* pBitmapBuffer = rBitmap.AcquireBuffer(BitmapAccessMode::Read);
106 if (!pBitmapBuffer)
107 return;
109 const BitmapPalette& rPalette = pBitmapBuffer->maPalette;
110 if (rPalette.GetEntryCount() == 2)
112 const BitmapColor aWhite(rPalette[rPalette.GetBestIndex(COL_WHITE)]);
113 rValues.foreground = rColMap.GetPixel(aWhite);
115 const BitmapColor aBlack(rPalette[rPalette.GetBestIndex(COL_BLACK)]);
116 rValues.background = rColMap.GetPixel(aBlack);
118 rBitmap.ReleaseBuffer(pBitmapBuffer, BitmapAccessMode::Read);
122 X11SalGraphicsImpl::X11SalGraphicsImpl(X11SalGraphics& rParent):
123 mrParent(rParent),
124 mnBrushColor( 0xFF, 0xFF, 0XFF ),
125 mpBrushGC(nullptr),
126 mnBrushPixel(0),
127 mbPenGC(false),
128 mbBrushGC(false),
129 mbCopyGC(false),
130 mbInvertGC(false),
131 mbInvert50GC(false),
132 mbStippleGC(false),
133 mbTrackingGC(false),
134 mbDitherBrush(false),
135 mbXORMode(false),
136 mpPenGC(nullptr),
137 mnPenColor( 0x00, 0x00, 0x00 ),
138 mnPenPixel(0),
139 mpMonoGC(nullptr),
140 mpCopyGC(nullptr),
141 mpMaskGC(nullptr),
142 mpInvertGC(nullptr),
143 mpInvert50GC(nullptr),
144 mpStippleGC(nullptr),
145 mpTrackingGC(nullptr)
149 X11SalGraphicsImpl::~X11SalGraphicsImpl()
153 void X11SalGraphicsImpl::Init()
155 mnPenPixel = mrParent.GetPixel( mnPenColor );
156 mnBrushPixel = mrParent.GetPixel( mnBrushColor );
159 XID X11SalGraphicsImpl::GetXRenderPicture()
161 XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
163 if( !mrParent.m_aXRenderPicture )
165 // check xrender support for matching visual
166 XRenderPictFormat* pXRenderFormat = mrParent.GetXRenderFormat();
167 if( !pXRenderFormat )
168 return 0;
169 // get the matching xrender target for drawable
170 mrParent.m_aXRenderPicture = rRenderPeer.CreatePicture( mrParent.hDrawable_, pXRenderFormat, 0, nullptr );
174 // reset clip region
175 // TODO: avoid clip reset if already done
176 XRenderPictureAttributes aAttr;
177 aAttr.clip_mask = None;
178 rRenderPeer.ChangePicture( mrParent.m_aXRenderPicture, CPClipMask, &aAttr );
181 return mrParent.m_aXRenderPicture;
184 static void freeGC(Display *pDisplay, GC& rGC)
186 if( rGC )
188 XFreeGC( pDisplay, rGC );
189 rGC = None;
193 void X11SalGraphicsImpl::freeResources()
195 Display *pDisplay = mrParent.GetXDisplay();
197 freeGC( pDisplay, mpPenGC );
198 freeGC( pDisplay, mpBrushGC );
199 freeGC( pDisplay, mpMonoGC );
200 freeGC( pDisplay, mpTrackingGC );
201 freeGC( pDisplay, mpCopyGC );
202 freeGC( pDisplay, mpMaskGC );
203 freeGC( pDisplay, mpInvertGC );
204 freeGC( pDisplay, mpInvert50GC );
205 freeGC( pDisplay, mpStippleGC );
206 mbTrackingGC = mbPenGC = mbBrushGC = mbCopyGC = mbInvertGC = mbInvert50GC = mbStippleGC = false;
209 GC X11SalGraphicsImpl::CreateGC( Drawable hDrawable, unsigned long nMask )
211 XGCValues values;
213 values.graphics_exposures = False;
214 values.foreground = mrParent.m_pColormap->GetBlackPixel()
215 ^ mrParent.m_pColormap->GetWhitePixel();
216 values.function = GXxor;
217 values.line_width = 1;
218 values.fill_style = FillStippled;
219 values.stipple = mrParent.GetDisplay()->GetInvert50( mrParent.m_nXScreen );
220 values.subwindow_mode = ClipByChildren;
222 return XCreateGC( mrParent.GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values );
225 inline GC X11SalGraphicsImpl::GetCopyGC()
227 if( mbXORMode ) return GetInvertGC();
229 if( !mpCopyGC )
230 mpCopyGC = CreateGC( mrParent.GetDrawable() );
232 if( !mbCopyGC )
234 mrParent.SetClipRegion( mpCopyGC );
235 mbCopyGC = true;
237 return mpCopyGC;
240 GC X11SalGraphicsImpl::GetTrackingGC()
242 if( !mpTrackingGC )
244 XGCValues values;
246 values.graphics_exposures = False;
247 values.foreground = mrParent.m_pColormap->GetBlackPixel()
248 ^ mrParent.m_pColormap->GetWhitePixel();
249 values.function = GXxor;
250 values.line_width = 1;
251 values.line_style = LineOnOffDash;
253 mpTrackingGC = XCreateGC( mrParent.GetXDisplay(), mrParent.GetDrawable(),
254 GCGraphicsExposures | GCForeground | GCFunction
255 | GCLineWidth | GCLineStyle,
256 &values );
257 const char dash_list[2] = {2, 2};
258 XSetDashes( mrParent.GetXDisplay(), mpTrackingGC, 0, dash_list, 2 );
261 if( !mbTrackingGC )
263 mrParent.SetClipRegion( mpTrackingGC );
264 mbTrackingGC = true;
267 return mpTrackingGC;
270 GC X11SalGraphicsImpl::GetInvertGC()
272 if( !mpInvertGC )
273 mpInvertGC = CreateGC( mrParent.GetDrawable(),
274 GCGraphicsExposures
275 | GCForeground
276 | GCFunction
277 | GCLineWidth );
279 if( !mbInvertGC )
281 mrParent.SetClipRegion( mpInvertGC );
282 mbInvertGC = true;
284 return mpInvertGC;
287 GC X11SalGraphicsImpl::GetInvert50GC()
289 if( !mpInvert50GC )
291 XGCValues values;
293 values.graphics_exposures = False;
294 values.foreground = mrParent.m_pColormap->GetWhitePixel();
295 values.background = mrParent.m_pColormap->GetBlackPixel();
296 values.function = GXinvert;
297 values.line_width = 1;
298 values.line_style = LineSolid;
299 unsigned long const nValueMask =
300 GCGraphicsExposures
301 | GCForeground
302 | GCBackground
303 | GCFunction
304 | GCLineWidth
305 | GCLineStyle
306 | GCFillStyle
307 | GCStipple;
309 values.fill_style = FillStippled;
310 values.stipple = mrParent.GetDisplay()->GetInvert50( mrParent.m_nXScreen );
312 mpInvert50GC = XCreateGC( mrParent.GetXDisplay(), mrParent.GetDrawable(),
313 nValueMask,
314 &values );
317 if( !mbInvert50GC )
319 mrParent.SetClipRegion( mpInvert50GC );
320 mbInvert50GC = true;
322 return mpInvert50GC;
325 inline GC X11SalGraphicsImpl::GetStippleGC()
327 if( !mpStippleGC )
328 mpStippleGC = CreateGC( mrParent.GetDrawable(),
329 GCGraphicsExposures
330 | GCFillStyle
331 | GCLineWidth );
333 if( !mbStippleGC )
335 XSetFunction( mrParent.GetXDisplay(), mpStippleGC, mbXORMode ? GXxor : GXcopy );
336 mrParent.SetClipRegion( mpStippleGC );
337 mbStippleGC = true;
340 return mpStippleGC;
343 GC X11SalGraphicsImpl::SelectBrush()
345 Display *pDisplay = mrParent.GetXDisplay();
347 SAL_WARN_IF( mnBrushColor == SALCOLOR_NONE, "vcl", "Brush Transparent" );
349 if( !mpBrushGC )
351 XGCValues values;
352 values.subwindow_mode = ClipByChildren;
353 values.fill_rule = EvenOddRule; // Pict import/ Gradient
354 values.graphics_exposures = False;
356 mpBrushGC = XCreateGC( pDisplay, mrParent.hDrawable_,
357 GCSubwindowMode | GCFillRule | GCGraphicsExposures,
358 &values );
361 if( !mbBrushGC )
363 if( !mbDitherBrush )
365 XSetFillStyle ( pDisplay, mpBrushGC, FillSolid );
366 XSetForeground( pDisplay, mpBrushGC, mnBrushPixel );
368 else
370 XSetFillStyle ( pDisplay, mpBrushGC, FillTiled );
371 XSetTile ( pDisplay, mpBrushGC, mrParent.hBrush_ );
373 XSetFunction ( pDisplay, mpBrushGC, mbXORMode ? GXxor : GXcopy );
374 mrParent.SetClipRegion( mpBrushGC );
376 mbBrushGC = true;
379 return mpBrushGC;
382 GC X11SalGraphicsImpl::SelectPen()
384 Display *pDisplay = mrParent.GetXDisplay();
386 if( !mpPenGC )
388 XGCValues values;
389 values.subwindow_mode = ClipByChildren;
390 values.fill_rule = EvenOddRule; // Pict import/ Gradient
391 values.graphics_exposures = False;
393 mpPenGC = XCreateGC( pDisplay, mrParent.hDrawable_,
394 GCSubwindowMode | GCFillRule | GCGraphicsExposures,
395 &values );
398 if( !mbPenGC )
400 if( mnPenColor != SALCOLOR_NONE )
401 XSetForeground( pDisplay, mpPenGC, mnPenPixel );
402 XSetFunction ( pDisplay, mpPenGC, mbXORMode ? GXxor : GXcopy );
403 mrParent.SetClipRegion( mpPenGC );
404 mbPenGC = true;
407 return mpPenGC;
410 void X11SalGraphicsImpl::DrawLines(sal_uInt32 nPoints,
411 const SalPolyLine &rPoints,
412 GC pGC,
413 bool bClose)
415 // calculate how many lines XWindow can draw in one go
416 sal_uLong nMaxLines = (mrParent.GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
417 / sizeof(xPoint);
418 if( nMaxLines > nPoints ) nMaxLines = nPoints;
420 // print all lines that XWindows can draw
421 sal_uLong n;
422 for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
423 XDrawLines( mrParent.GetXDisplay(),
424 mrParent.GetDrawable(),
425 pGC,
426 const_cast<XPoint*>(&rPoints[n]),
427 nMaxLines,
428 CoordModeOrigin );
430 if( n < nPoints )
431 XDrawLines( mrParent.GetXDisplay(),
432 mrParent.GetDrawable(),
433 pGC,
434 const_cast<XPoint*>(&rPoints[n]),
435 nPoints - n,
436 CoordModeOrigin );
437 if( bClose )
439 if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y )
440 drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y );
444 void X11SalGraphicsImpl::copyBits( const SalTwoRect& rPosAry,
445 SalGraphics *pSSrcGraphics )
447 X11SalGraphics* pSrcGraphics = pSSrcGraphics
448 ? static_cast<X11SalGraphics*>(pSSrcGraphics)
449 : &mrParent;
451 if( rPosAry.mnSrcWidth <= 0
452 || rPosAry.mnSrcHeight <= 0
453 || rPosAry.mnDestWidth <= 0
454 || rPosAry.mnDestHeight <= 0 )
456 return;
459 int n;
460 if( pSrcGraphics == &mrParent )
462 n = 2;
464 else if( pSrcGraphics->bWindow_ )
466 // window or compatible virtual device
467 if( pSrcGraphics->GetDisplay() == mrParent.GetDisplay() &&
468 pSrcGraphics->m_nXScreen == mrParent.m_nXScreen &&
469 pSrcGraphics->GetVisual().GetDepth() == mrParent.GetVisual().GetDepth()
471 n = 2; // same Display
472 else
473 n = 1; // printer or other display
475 else if( pSrcGraphics->bVirDev_ )
477 n = 1; // window or compatible virtual device
479 else
480 n = 0;
482 if( n == 2
483 && rPosAry.mnSrcWidth == rPosAry.mnDestWidth
484 && rPosAry.mnSrcHeight == rPosAry.mnDestHeight
487 // #i60699# Need to generate graphics exposures (to repaint
488 // obscured areas beneath overlapping windows), src and dest
489 // are the same window.
490 const bool bNeedGraphicsExposures( pSrcGraphics == &mrParent &&
491 !mrParent.bVirDev_ &&
492 pSrcGraphics->bWindow_ );
494 GC pCopyGC = GetCopyGC();
496 if( bNeedGraphicsExposures )
497 XSetGraphicsExposures( mrParent.GetXDisplay(),
498 pCopyGC,
499 True );
501 XCopyArea( mrParent.GetXDisplay(),
502 pSrcGraphics->GetDrawable(), // source
503 mrParent.GetDrawable(), // destination
504 pCopyGC, // destination clipping
505 rPosAry.mnSrcX, rPosAry.mnSrcY,
506 rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
507 rPosAry.mnDestX, rPosAry.mnDestY );
509 if( bNeedGraphicsExposures )
511 mrParent.YieldGraphicsExpose();
513 if( pCopyGC )
514 XSetGraphicsExposures( mrParent.GetXDisplay(),
515 pCopyGC,
516 False );
519 else if( n )
521 // #i60699# No chance to handle graphics exposures - we copy
522 // to a temp bitmap first, into which no repaints are
523 // technically possible.
524 std::shared_ptr<SalBitmap> xDDB(pSrcGraphics->getBitmap( rPosAry.mnSrcX,
525 rPosAry.mnSrcY,
526 rPosAry.mnSrcWidth,
527 rPosAry.mnSrcHeight ));
529 if( !xDDB )
531 SAL_WARN( "vcl", "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()" );
532 return;
535 SalTwoRect aPosAry( rPosAry );
537 aPosAry.mnSrcX = 0;
538 aPosAry.mnSrcY = 0;
539 drawBitmap( aPosAry, *xDDB );
541 else {
542 SAL_WARN( "vcl", "X11SalGraphicsImpl::CopyBits from Printer not yet implemented" );
546 void X11SalGraphicsImpl::copyArea ( tools::Long nDestX, tools::Long nDestY,
547 tools::Long nSrcX, tools::Long nSrcY,
548 tools::Long nSrcWidth, tools::Long nSrcHeight,
549 bool /*bWindowInvalidate*/)
551 SalTwoRect aPosAry(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
552 copyBits(aPosAry, nullptr);
555 void X11SalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
557 const SalDisplay* pSalDisp = mrParent.GetDisplay();
558 Display* pXDisp = pSalDisp->GetDisplay();
559 const Drawable aDrawable( mrParent.GetDrawable() );
560 const SalColormap& rColMap = pSalDisp->GetColormap( mrParent.m_nXScreen );
561 const tools::Long nDepth = mrParent.GetDisplay()->GetVisual( mrParent.m_nXScreen ).GetDepth();
562 GC aGC( GetCopyGC() );
563 XGCValues aOldVal, aNewVal;
564 int nValues = GCForeground | GCBackground;
566 if( rSalBitmap.GetBitCount() == 1 )
568 // set foreground/background values for 1Bit bitmaps
569 XGetGCValues( pXDisp, aGC, nValues, &aOldVal );
570 setForeBack(aNewVal, rColMap, rSalBitmap);
571 XChangeGC( pXDisp, aGC, nValues, &aNewVal );
574 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, mrParent.m_nXScreen, nDepth, rPosAry, aGC );
576 if( rSalBitmap.GetBitCount() == 1 )
577 XChangeGC( pXDisp, aGC, nValues, &aOldVal );
578 XFlush( pXDisp );
581 void X11SalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry,
582 const SalBitmap& rSrcBitmap,
583 const SalBitmap& rMaskBitmap )
585 // decide if alpha masking or transparency masking is needed
586 BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( BitmapAccessMode::Read );
587 if( pAlphaBuffer != nullptr )
589 ScanlineFormat nMaskFormat = pAlphaBuffer->mnFormat;
590 const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, BitmapAccessMode::Read );
591 if( nMaskFormat == ScanlineFormat::N8BitPal )
592 drawAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap );
595 drawMaskedBitmap( rPosAry, rSrcBitmap, rMaskBitmap );
598 void X11SalGraphicsImpl::drawMaskedBitmap( const SalTwoRect& rPosAry,
599 const SalBitmap& rSalBitmap,
600 const SalBitmap& rTransBitmap )
602 const SalDisplay* pSalDisp = mrParent.GetDisplay();
603 Display* pXDisp = pSalDisp->GetDisplay();
604 Drawable aDrawable( mrParent.GetDrawable() );
606 // figure work mode depth. If this is a VDev Drawable, use its
607 // bitdepth to create pixmaps for, otherwise, XCopyArea will
608 // refuse to work.
609 const sal_uInt16 nDepth( mrParent.m_pVDev ?
610 static_cast< X11SalVirtualDevice* >(mrParent.m_pVDev)->GetDepth() :
611 pSalDisp->GetVisual( mrParent.m_nXScreen ).GetDepth() );
612 Pixmap aFG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth,
613 rPosAry.mnDestHeight, nDepth ) );
614 Pixmap aBG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth,
615 rPosAry.mnDestHeight, nDepth ) );
617 if( aFG && aBG )
619 GC aTmpGC;
620 XGCValues aValues;
621 setForeBack(aValues, pSalDisp->GetColormap(mrParent.m_nXScreen), rSalBitmap);
622 const int nValues = GCFunction | GCForeground | GCBackground;
623 SalTwoRect aTmpRect( rPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0;
625 // draw paint bitmap in pixmap #1
626 aValues.function = GXcopy;
627 aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues );
628 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, mrParent.m_nXScreen, nDepth, aTmpRect, aTmpGC );
629 DBG_TESTTRANS( aFG );
631 // draw background in pixmap #2
632 XCopyArea( pXDisp, aDrawable, aBG, aTmpGC,
633 rPosAry.mnDestX, rPosAry.mnDestY,
634 rPosAry.mnDestWidth, rPosAry.mnDestHeight,
635 0, 0 );
637 DBG_TESTTRANS( aBG );
639 // mask out paint bitmap in pixmap #1 (transparent areas 0)
640 aValues.function = GXand;
641 aValues.foreground = 0x00000000;
642 aValues.background = 0xffffffff;
643 XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
644 static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, mrParent.m_nXScreen, 1, aTmpRect, aTmpGC );
646 DBG_TESTTRANS( aFG );
648 // #105055# For XOR mode, keep background behind bitmap intact
649 if( !mbXORMode )
651 // mask out background in pixmap #2 (nontransparent areas 0)
652 aValues.function = GXand;
653 aValues.foreground = 0xffffffff;
654 aValues.background = 0x00000000;
655 XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
656 static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, mrParent.m_nXScreen, 1, aTmpRect, aTmpGC );
658 DBG_TESTTRANS( aBG );
661 // merge pixmap #1 and pixmap #2 in pixmap #2
662 aValues.function = GXxor;
663 aValues.foreground = 0xffffffff;
664 aValues.background = 0x00000000;
665 XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
666 XCopyArea( pXDisp, aFG, aBG, aTmpGC,
667 0, 0,
668 rPosAry.mnDestWidth, rPosAry.mnDestHeight,
669 0, 0 );
670 DBG_TESTTRANS( aBG );
672 // #105055# Disable XOR temporarily
673 bool bOldXORMode( mbXORMode );
674 mbXORMode = false;
676 // copy pixmap #2 (result) to background
677 XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(),
678 0, 0,
679 rPosAry.mnDestWidth, rPosAry.mnDestHeight,
680 rPosAry.mnDestX, rPosAry.mnDestY );
682 DBG_TESTTRANS( aBG );
684 mbXORMode = bOldXORMode;
686 XFreeGC( pXDisp, aTmpGC );
687 XFlush( pXDisp );
689 else
690 drawBitmap( rPosAry, rSalBitmap );
692 if( aFG )
693 XFreePixmap( pXDisp, aFG );
695 if( aBG )
696 XFreePixmap( pXDisp, aBG );
699 bool X11SalGraphicsImpl::blendBitmap( const SalTwoRect&,
700 const SalBitmap& )
702 return false;
705 bool X11SalGraphicsImpl::blendAlphaBitmap( const SalTwoRect&,
706 const SalBitmap&, const SalBitmap&, const SalBitmap& )
708 return false;
711 bool X11SalGraphicsImpl::drawAlphaBitmap( const SalTwoRect& rTR,
712 const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
714 // non 8-bit alpha not implemented yet
715 if( rAlphaBmp.GetBitCount() != 8 )
716 return false;
717 // #i75531# the workaround below can go when
718 // X11SalGraphics::drawAlphaBitmap()'s render acceleration
719 // can handle the bitmap depth mismatch directly
720 if( rSrcBitmap.GetBitCount() < rAlphaBmp.GetBitCount() )
721 return false;
723 // horizontal mirroring not implemented yet
724 if( rTR.mnDestWidth < 0 )
725 return false;
727 // stretched conversion is not implemented yet
728 if( rTR.mnDestWidth != rTR.mnSrcWidth )
729 return false;
730 if( rTR.mnDestHeight!= rTR.mnSrcHeight )
731 return false;
733 // create destination picture
734 Picture aDstPic = GetXRenderPicture();
735 if( !aDstPic )
736 return false;
738 const SalDisplay* pSalDisp = mrParent.GetDisplay();
739 const SalVisual& rSalVis = pSalDisp->GetVisual( mrParent.m_nXScreen );
740 Display* pXDisplay = pSalDisp->GetDisplay();
742 // create source Picture
743 int nDepth = mrParent.m_pVDev ? static_cast< X11SalVirtualDevice* >(mrParent.m_pVDev)->GetDepth() : rSalVis.GetDepth();
744 const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap );
745 ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( mrParent.hDrawable_, mrParent.m_nXScreen, nDepth, rTR );
746 if( !pSrcDDB )
747 return false;
749 //#i75249# workaround for ImplGetDDB() giving us back a different depth than
750 // we requested. E.g. mask pixmaps are always compatible with the drawable
751 // TODO: find an appropriate picture format for these cases
752 // then remove the workaround below and the one for #i75531#
753 if( nDepth != pSrcDDB->ImplGetDepth() )
754 return false;
756 Pixmap aSrcPM = pSrcDDB->ImplGetPixmap();
757 if( !aSrcPM )
758 return false;
760 // create source picture
761 // TODO: use scoped picture
762 Visual* pSrcXVisual = rSalVis.GetVisual();
763 XRenderPeer& rPeer = XRenderPeer::GetInstance();
764 XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual );
765 if( !pSrcVisFmt )
766 return false;
767 Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, nullptr );
768 if( !aSrcPic )
769 return false;
771 // create alpha Picture
773 // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap
774 // problem is that they don't provide an 8bit Pixmap on a non-8bit display
775 BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( BitmapAccessMode::Read );
777 // an XImage needs its data top_down
778 // TODO: avoid wrongly oriented images in upper layers!
779 const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize;
780 const char* pSrcBits = reinterpret_cast<char*>(pAlphaBuffer->mpBits);
781 char* pAlphaBits = new char[ nImageSize ];
782 if( pAlphaBuffer->mnFormat & ScanlineFormat::TopDown )
783 memcpy( pAlphaBits, pSrcBits, nImageSize );
784 else
786 char* pDstBits = pAlphaBits + nImageSize;
787 const int nLineSize = pAlphaBuffer->mnScanlineSize;
788 for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize )
789 memcpy( pDstBits, pSrcBits, nLineSize );
792 // the alpha values need to be inverted for XRender
793 // TODO: make upper layers use standard alpha
794 tools::Long* pLDst = reinterpret_cast<long*>(pAlphaBits);
795 for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst )
796 *pLDst = ~*pLDst;
798 char* pCDst = reinterpret_cast<char*>(pLDst);
799 for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst )
800 *pCDst = ~*pCDst;
802 const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8();
803 XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0,
804 pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight,
805 pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize );
807 Pixmap aAlphaPM = limitXCreatePixmap( pXDisplay, mrParent.hDrawable_,
808 rTR.mnDestWidth, rTR.mnDestHeight, 8 );
810 XGCValues aAlphaGCV;
811 aAlphaGCV.function = GXcopy;
812 GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV );
813 XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg,
814 rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight );
815 XFreeGC( pXDisplay, aAlphaGC );
816 XFree( pAlphaImg );
817 if( pAlphaBits != reinterpret_cast<char*>(pAlphaBuffer->mpBits) )
818 delete[] pAlphaBits;
820 const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, BitmapAccessMode::Read );
822 XRenderPictureAttributes aAttr;
823 aAttr.repeat = int(true);
824 Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr );
825 if( !aAlphaPic )
826 return false;
828 // set clipping
829 if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) )
830 rPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion );
832 // paint source * mask over destination picture
833 rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic,
834 rTR.mnSrcX, rTR.mnSrcY,
835 rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight );
837 rPeer.FreePicture( aAlphaPic );
838 XFreePixmap(pXDisplay, aAlphaPM);
839 rPeer.FreePicture( aSrcPic );
840 return true;
843 bool X11SalGraphicsImpl::drawTransformedBitmap(
844 const basegfx::B2DPoint&,
845 const basegfx::B2DPoint&,
846 const basegfx::B2DPoint&,
847 const SalBitmap&,
848 const SalBitmap*)
850 // here direct support for transformed bitmaps can be implemented
851 return false;
854 bool X11SalGraphicsImpl::drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth,
855 tools::Long nHeight, sal_uInt8 nTransparency )
857 if( ! mrParent.m_pFrame && ! mrParent.m_pVDev )
858 return false;
860 if( mbPenGC || !mbBrushGC || mbXORMode )
861 return false; // can only perform solid fills without XOR.
863 if( mrParent.m_pVDev && static_cast< X11SalVirtualDevice* >(mrParent.m_pVDev)->GetDepth() < 8 )
864 return false;
866 Picture aDstPic = GetXRenderPicture();
867 if( !aDstPic )
868 return false;
870 const double fTransparency = (100 - nTransparency) * (1.0/100);
871 const XRenderColor aRenderColor = GetXRenderColor( mnBrushColor , fTransparency);
873 XRenderPeer& rPeer = XRenderPeer::GetInstance();
874 rPeer.FillRectangle( PictOpOver,
875 aDstPic,
876 &aRenderColor,
877 nX, nY,
878 nWidth, nHeight );
880 return true;
883 void X11SalGraphicsImpl::drawMask( const SalTwoRect& rPosAry,
884 const SalBitmap &rSalBitmap,
885 Color nMaskColor )
887 const SalDisplay* pSalDisp = mrParent.GetDisplay();
888 Display* pXDisp = pSalDisp->GetDisplay();
889 Drawable aDrawable( mrParent.GetDrawable() );
890 Pixmap aStipple( limitXCreatePixmap( pXDisp, aDrawable,
891 rPosAry.mnDestWidth,
892 rPosAry.mnDestHeight, 1 ) );
894 if( aStipple )
896 SalTwoRect aTwoRect( rPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
897 GC aTmpGC;
898 XGCValues aValues;
900 // create a stipple bitmap first (set bits are changed to unset bits and vice versa)
901 aValues.function = GXcopyInverted;
902 aValues.foreground = 1;
903 aValues.background = 0;
904 aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues );
905 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, mrParent.m_nXScreen, 1, aTwoRect, aTmpGC );
907 XFreeGC( pXDisp, aTmpGC );
909 // Set stipple and draw rectangle
910 GC aStippleGC( GetStippleGC() );
911 int nX = rPosAry.mnDestX, nY = rPosAry.mnDestY;
913 XSetStipple( pXDisp, aStippleGC, aStipple );
914 XSetTSOrigin( pXDisp, aStippleGC, nX, nY );
915 XSetForeground( pXDisp, aStippleGC, mrParent.GetPixel( nMaskColor ) );
916 XFillRectangle( pXDisp, aDrawable, aStippleGC,
917 nX, nY,
918 rPosAry.mnDestWidth, rPosAry.mnDestHeight );
919 XFreePixmap( pXDisp, aStipple );
920 XFlush( pXDisp );
922 else
923 drawBitmap( rPosAry, rSalBitmap );
926 void X11SalGraphicsImpl::ResetClipRegion()
928 if( !mrParent.mpClipRegion )
929 return;
931 mbPenGC = false;
932 mbBrushGC = false;
933 mbCopyGC = false;
934 mbInvertGC = false;
935 mbInvert50GC = false;
936 mbStippleGC = false;
937 mbTrackingGC = false;
939 XDestroyRegion( mrParent.mpClipRegion );
940 mrParent.mpClipRegion = nullptr;
943 bool X11SalGraphicsImpl::setClipRegion( const vcl::Region& i_rClip )
945 if( mrParent.mpClipRegion )
946 XDestroyRegion( mrParent.mpClipRegion );
947 mrParent.mpClipRegion = XCreateRegion();
949 RectangleVector aRectangles;
950 i_rClip.GetRegionRectangles(aRectangles);
952 for (auto const& rectangle : aRectangles)
954 const tools::Long nW(rectangle.GetWidth());
956 if(nW)
958 const tools::Long nH(rectangle.GetHeight());
960 if(nH)
962 XRectangle aRect;
964 aRect.x = static_cast<short>(rectangle.Left());
965 aRect.y = static_cast<short>(rectangle.Top());
966 aRect.width = static_cast<unsigned short>(nW);
967 aRect.height = static_cast<unsigned short>(nH);
968 XUnionRectWithRegion(&aRect, mrParent.mpClipRegion, mrParent.mpClipRegion);
973 //ImplRegionInfo aInfo;
974 //long nX, nY, nW, nH;
975 //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
976 //while( bRegionRect )
978 // if ( nW && nH )
979 // {
980 // XRectangle aRect;
981 // aRect.x = (short)nX;
982 // aRect.y = (short)nY;
983 // aRect.width = (unsigned short)nW;
984 // aRect.height = (unsigned short)nH;
986 // XUnionRectWithRegion( &aRect, mrParent.mpClipRegion, mrParent.mpClipRegion );
987 // }
988 // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
991 // done, invalidate GCs
992 mbPenGC = false;
993 mbBrushGC = false;
994 mbCopyGC = false;
995 mbInvertGC = false;
996 mbInvert50GC = false;
997 mbStippleGC = false;
998 mbTrackingGC = false;
1000 if( XEmptyRegion( mrParent.mpClipRegion ) )
1002 XDestroyRegion( mrParent.mpClipRegion );
1003 mrParent.mpClipRegion= nullptr;
1005 return true;
1008 void X11SalGraphicsImpl::SetLineColor()
1010 if( mnPenColor != SALCOLOR_NONE )
1012 mnPenColor = SALCOLOR_NONE;
1013 mbPenGC = false;
1017 void X11SalGraphicsImpl::SetLineColor( Color nColor )
1019 if( mnPenColor != nColor )
1021 mnPenColor = nColor;
1022 mnPenPixel = mrParent.GetPixel( nColor );
1023 mbPenGC = false;
1027 void X11SalGraphicsImpl::SetFillColor()
1029 if( mnBrushColor != SALCOLOR_NONE )
1031 mbDitherBrush = false;
1032 mnBrushColor = SALCOLOR_NONE;
1033 mbBrushGC = false;
1037 void X11SalGraphicsImpl::SetFillColor( Color nColor )
1039 if( mnBrushColor == nColor )
1040 return;
1042 mbDitherBrush = false;
1043 mnBrushColor = nColor;
1044 mnBrushPixel = mrParent.GetPixel( nColor );
1045 if( TrueColor != mrParent.GetColormap().GetVisual().GetClass()
1046 && mrParent.GetColormap().GetColor( mnBrushPixel ) != mnBrushColor
1047 && nColor != Color( 0x00, 0x00, 0x00 ) // black
1048 && nColor != Color( 0x00, 0x00, 0x80 ) // blue
1049 && nColor != Color( 0x00, 0x80, 0x00 ) // green
1050 && nColor != Color( 0x00, 0x80, 0x80 ) // cyan
1051 && nColor != Color( 0x80, 0x00, 0x00 ) // red
1052 && nColor != Color( 0x80, 0x00, 0x80 ) // magenta
1053 && nColor != Color( 0x80, 0x80, 0x00 ) // brown
1054 && nColor != Color( 0x80, 0x80, 0x80 ) // gray
1055 && nColor != Color( 0xC0, 0xC0, 0xC0 ) // light gray
1056 && nColor != Color( 0x00, 0x00, 0xFF ) // light blue
1057 && nColor != Color( 0x00, 0xFF, 0x00 ) // light green
1058 && nColor != Color( 0x00, 0xFF, 0xFF ) // light cyan
1059 && nColor != Color( 0xFF, 0x00, 0x00 ) // light red
1060 && nColor != Color( 0xFF, 0x00, 0xFF ) // light magenta
1061 && nColor != Color( 0xFF, 0xFF, 0x00 ) // light brown
1062 && nColor != Color( 0xFF, 0xFF, 0xFF ) )
1063 mbDitherBrush = mrParent.GetDitherPixmap(nColor);
1064 mbBrushGC = false;
1067 void X11SalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor )
1069 switch( nROPColor )
1071 case SalROPColor::N0 : // 0
1072 mnPenPixel = Pixel(0);
1073 break;
1074 case SalROPColor::N1 : // 1
1075 mnPenPixel = static_cast<Pixel>(1 << mrParent.GetVisual().GetDepth()) - 1;
1076 break;
1077 case SalROPColor::Invert : // 2
1078 mnPenPixel = static_cast<Pixel>(1 << mrParent.GetVisual().GetDepth()) - 1;
1079 break;
1081 mnPenColor = mrParent.GetColormap().GetColor( mnPenPixel );
1082 mbPenGC = false;
1085 void X11SalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor )
1087 switch( nROPColor )
1089 case SalROPColor::N0 : // 0
1090 mnBrushPixel = Pixel(0);
1091 break;
1092 case SalROPColor::N1 : // 1
1093 mnBrushPixel = static_cast<Pixel>(1 << mrParent.GetVisual().GetDepth()) - 1;
1094 break;
1095 case SalROPColor::Invert : // 2
1096 mnBrushPixel = static_cast<Pixel>(1 << mrParent.GetVisual().GetDepth()) - 1;
1097 break;
1099 mbDitherBrush = false;
1100 mnBrushColor = mrParent.GetColormap().GetColor( mnBrushPixel );
1101 mbBrushGC = false;
1104 void X11SalGraphicsImpl::SetXORMode( bool bSet, bool )
1106 if (mbXORMode != bSet)
1108 mbXORMode = bSet;
1109 mbPenGC = false;
1110 mbBrushGC = false;
1111 mbCopyGC = false;
1112 mbInvertGC = false;
1113 mbInvert50GC = false;
1114 mbStippleGC = false;
1115 mbTrackingGC = false;
1119 void X11SalGraphicsImpl::drawPixel( tools::Long nX, tools::Long nY )
1121 if( mnPenColor != SALCOLOR_NONE )
1122 XDrawPoint( mrParent.GetXDisplay(), mrParent.GetDrawable(), SelectPen(), nX, nY );
1125 void X11SalGraphicsImpl::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
1127 if( nColor == SALCOLOR_NONE )
1128 return;
1130 Display *pDisplay = mrParent.GetXDisplay();
1132 if( (mnPenColor == SALCOLOR_NONE) && !mbPenGC )
1134 SetLineColor( nColor );
1135 XDrawPoint( pDisplay, mrParent.GetDrawable(), SelectPen(), nX, nY );
1136 mnPenColor = SALCOLOR_NONE;
1137 mbPenGC = False;
1139 else
1141 GC pGC = SelectPen();
1143 if( nColor != mnPenColor )
1144 XSetForeground( pDisplay, pGC, mrParent.GetPixel( nColor ) );
1146 XDrawPoint( pDisplay, mrParent.GetDrawable(), pGC, nX, nY );
1148 if( nColor != mnPenColor )
1149 XSetForeground( pDisplay, pGC, mnPenPixel );
1153 void X11SalGraphicsImpl::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
1155 if( mnPenColor != SALCOLOR_NONE )
1157 XDrawLine( mrParent.GetXDisplay(), mrParent.GetDrawable(),SelectPen(),
1158 nX1, nY1, nX2, nY2 );
1162 void X11SalGraphicsImpl::drawRect( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY )
1164 if( mnBrushColor != SALCOLOR_NONE )
1166 XFillRectangle( mrParent.GetXDisplay(),
1167 mrParent.GetDrawable(),
1168 SelectBrush(),
1169 nX, nY, nDX, nDY );
1171 // description DrawRect is wrong; thus -1
1172 if( mnPenColor != SALCOLOR_NONE )
1173 XDrawRectangle( mrParent.GetXDisplay(),
1174 mrParent.GetDrawable(),
1175 SelectPen(),
1176 nX, nY, nDX-1, nDY-1 );
1179 void X11SalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const Point *pPtAry )
1181 drawPolyLine( nPoints, pPtAry, false );
1184 void X11SalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const Point *pPtAry, bool bClose )
1186 if( mnPenColor != SALCOLOR_NONE )
1188 SalPolyLine Points( nPoints, pPtAry );
1190 DrawLines( nPoints, Points, SelectPen(), bClose );
1194 void X11SalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
1196 if( nPoints == 0 )
1197 return;
1199 if( nPoints < 3 )
1201 if( !mbXORMode )
1203 if( 1 == nPoints )
1204 drawPixel( pPtAry[0].getX(), pPtAry[0].getY() );
1205 else
1206 drawLine( pPtAry[0].getX(), pPtAry[0].getY(),
1207 pPtAry[1].getX(), pPtAry[1].getY() );
1209 return;
1212 SalPolyLine Points( nPoints, pPtAry );
1214 nPoints++;
1216 /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
1217 * do not draw the visible part of a polygon
1218 * if it overlaps to the left of screen 0,y.
1219 * This happens to be the case in the gradient drawn in the
1220 * menubar background. workaround for the special case of
1221 * of a rectangle overlapping to the left.
1223 if (nPoints == 5 &&
1224 Points[ 0 ].x == Points[ 1 ].x &&
1225 Points[ 1 ].y == Points[ 2 ].y &&
1226 Points[ 2 ].x == Points[ 3 ].x &&
1227 Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y
1230 bool bLeft = false;
1231 bool bRight = false;
1232 for(unsigned int i = 0; i < nPoints; i++ )
1234 if( Points[i].x < 0 )
1235 bLeft = true;
1236 else
1237 bRight= true;
1239 if( bLeft && ! bRight )
1240 return;
1241 if( bLeft && bRight )
1243 for( unsigned int i = 0; i < nPoints; i++ )
1244 if( Points[i].x < 0 )
1245 Points[i].x = 0;
1249 if( mnBrushColor != SALCOLOR_NONE )
1250 XFillPolygon( mrParent.GetXDisplay(),
1251 mrParent.GetDrawable(),
1252 SelectBrush(),
1253 &Points[0], nPoints,
1254 Complex, CoordModeOrigin );
1256 if( mnPenColor != SALCOLOR_NONE )
1257 DrawLines( nPoints, Points, SelectPen(), true );
1260 void X11SalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly,
1261 const sal_uInt32 *pPoints,
1262 const Point* *pPtAry )
1264 if( mnBrushColor != SALCOLOR_NONE )
1266 sal_uInt32 i, n;
1267 Region pXRegA = nullptr;
1269 for( i = 0; i < nPoly; i++ ) {
1270 n = pPoints[i];
1271 SalPolyLine Points( n, pPtAry[i] );
1272 if( n > 2 )
1274 Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
1275 if( !pXRegA )
1276 pXRegA = pXRegB;
1277 else
1279 XXorRegion( pXRegA, pXRegB, pXRegA );
1280 XDestroyRegion( pXRegB );
1285 if( pXRegA )
1287 XRectangle aXRect;
1288 XClipBox( pXRegA, &aXRect );
1290 GC pGC = SelectBrush();
1291 mrParent.SetClipRegion( pGC, pXRegA ); // ??? twice
1292 XDestroyRegion( pXRegA );
1293 mbBrushGC = false;
1295 XFillRectangle( mrParent.GetXDisplay(),
1296 mrParent.GetDrawable(),
1297 pGC,
1298 aXRect.x, aXRect.y, aXRect.width, aXRect.height );
1302 if( mnPenColor != SALCOLOR_NONE )
1303 for( sal_uInt32 i = 0; i < nPoly; i++ )
1304 drawPolyLine( pPoints[i], pPtAry[i], true );
1307 bool X11SalGraphicsImpl::drawPolyLineBezier( sal_uInt32, const Point*, const PolyFlags* )
1309 return false;
1312 bool X11SalGraphicsImpl::drawPolygonBezier( sal_uInt32, const Point*, const PolyFlags* )
1314 return false;
1317 bool X11SalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
1318 const Point* const*, const PolyFlags* const* )
1320 return false;
1323 void X11SalGraphicsImpl::invert( tools::Long nX,
1324 tools::Long nY,
1325 tools::Long nDX,
1326 tools::Long nDY,
1327 SalInvert nFlags )
1329 GC pGC;
1330 if( SalInvert::N50 & nFlags )
1332 pGC = GetInvert50GC();
1333 XFillRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY );
1335 else
1337 if ( SalInvert::TrackFrame & nFlags )
1339 pGC = GetTrackingGC();
1340 XDrawRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY );
1342 else
1344 pGC = GetInvertGC();
1345 XFillRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY );
1350 void X11SalGraphicsImpl::invert( sal_uInt32 nPoints,
1351 const Point* pPtAry,
1352 SalInvert nFlags )
1354 SalPolyLine Points ( nPoints, pPtAry );
1356 GC pGC;
1357 if( SalInvert::N50 & nFlags )
1358 pGC = GetInvert50GC();
1359 else
1360 if ( SalInvert::TrackFrame & nFlags )
1361 pGC = GetTrackingGC();
1362 else
1363 pGC = GetInvertGC();
1365 if( SalInvert::TrackFrame & nFlags )
1366 DrawLines ( nPoints, Points, pGC, true );
1367 else
1368 XFillPolygon( mrParent.GetXDisplay(),
1369 mrParent.GetDrawable(),
1370 pGC,
1371 &Points[0], nPoints,
1372 Complex, CoordModeOrigin );
1375 bool X11SalGraphicsImpl::drawEPS( tools::Long,tools::Long,tools::Long,tools::Long,void*,sal_uInt32 )
1377 return false;
1380 // draw a poly-polygon
1381 bool X11SalGraphicsImpl::drawPolyPolygon(
1382 const basegfx::B2DHomMatrix& rObjectToDevice,
1383 const basegfx::B2DPolyPolygon& rPolyPolygon,
1384 double fTransparency)
1386 // nothing to do for empty polypolygons
1387 const int nOrigPolyCount = rPolyPolygon.count();
1388 if( nOrigPolyCount <= 0 )
1389 return true;
1391 // nothing to do if everything is transparent
1392 if( (mnBrushColor == SALCOLOR_NONE)
1393 && (mnPenColor == SALCOLOR_NONE) )
1394 return true;
1396 // cannot handle pencolor!=brushcolor yet
1397 if( (mnPenColor != SALCOLOR_NONE)
1398 && (mnPenColor != mnBrushColor) )
1399 return false;
1401 // TODO: remove the env-variable when no longer needed
1402 static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
1403 if( pRenderEnv )
1404 return false;
1406 // Fallback: Transform to DeviceCoordinates
1407 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
1408 aPolyPolygon.transform(rObjectToDevice);
1410 // snap to raster if requested
1411 const bool bSnapToRaster = !mrParent.getAntiAlias();
1412 if( bSnapToRaster )
1413 aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges( aPolyPolygon );
1415 // don't bother with polygons outside of visible area
1416 const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
1417 aPolyPolygon = basegfx::utils::clipPolyPolygonOnRange( aPolyPolygon, aViewRange, true, false );
1418 if( !aPolyPolygon.count() )
1419 return true;
1421 // tessellate the polypolygon into trapezoids
1422 basegfx::B2DTrapezoidVector aB2DTrapVector;
1423 basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aPolyPolygon );
1424 const int nTrapCount = aB2DTrapVector.size();
1425 if( !nTrapCount )
1426 return true;
1427 const bool bDrawn = drawFilledTrapezoids( aB2DTrapVector.data(), nTrapCount, fTransparency );
1428 return bDrawn;
1431 tools::Long X11SalGraphicsImpl::GetGraphicsHeight() const
1433 if( mrParent.m_pFrame )
1434 return mrParent.m_pFrame->maGeometry.nHeight;
1435 else if( mrParent.m_pVDev )
1436 return static_cast< X11SalVirtualDevice* >(mrParent.m_pVDev)->GetHeight();
1437 else
1438 return 0;
1441 bool X11SalGraphicsImpl::drawFilledTrapezoids( const basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency )
1443 if( nTrapCount <= 0 )
1444 return true;
1446 Picture aDstPic = GetXRenderPicture();
1447 // check xrender support for this drawable
1448 if( !aDstPic )
1449 return false;
1451 // convert the B2DTrapezoids into XRender-Trapezoids
1452 std::vector<XTrapezoid> aTrapVector( nTrapCount );
1453 const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps;
1454 for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i )
1456 XTrapezoid& rTrap = aTrapVector[ i ] ;
1458 // set y-coordinates
1459 const double fY1 = pB2DTrap->getTopY();
1460 rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 );
1461 const double fY2 = pB2DTrap->getBottomY();
1462 rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 );
1464 // set x-coordinates
1465 const double fXL1 = pB2DTrap->getTopXLeft();
1466 rTrap.left.p1.x = XDoubleToFixed( fXL1 );
1467 const double fXR1 = pB2DTrap->getTopXRight();
1468 rTrap.right.p1.x = XDoubleToFixed( fXR1 );
1469 const double fXL2 = pB2DTrap->getBottomXLeft();
1470 rTrap.left.p2.x = XDoubleToFixed( fXL2 );
1471 const double fXR2 = pB2DTrap->getBottomXRight();
1472 rTrap.right.p2.x = XDoubleToFixed( fXR2 );
1475 // get xrender Picture for polygon foreground
1476 // TODO: cache it like the target picture which uses GetXRenderPicture()
1477 XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
1478 SalDisplay::RenderEntry& rEntry = mrParent.GetDisplay()->GetRenderEntries( mrParent.m_nXScreen )[ 32 ];
1479 if( !rEntry.m_aPicture )
1481 Display* pXDisplay = mrParent.GetXDisplay();
1483 rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, mrParent.hDrawable_, 1, 1, 32 );
1484 XRenderPictureAttributes aAttr;
1485 aAttr.repeat = int(true);
1487 XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
1488 rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
1491 // set polygon foreground color and opacity
1492 XRenderColor aRenderColor = GetXRenderColor( mnBrushColor , fTransparency );
1493 rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
1495 // set clipping
1496 // TODO: move into GetXRenderPicture?
1497 if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) )
1498 rRenderPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion );
1500 // render the trapezoids
1501 const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
1502 rRenderPeer.CompositeTrapezoids( PictOpOver,
1503 rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, aTrapVector.data(), aTrapVector.size() );
1505 return true;
1508 bool X11SalGraphicsImpl::drawFilledTriangles(
1509 const basegfx::B2DHomMatrix& rObjectToDevice,
1510 const basegfx::triangulator::B2DTriangleVector& rTriangles,
1511 double fTransparency)
1513 if(rTriangles.empty())
1514 return true;
1516 Picture aDstPic = GetXRenderPicture();
1517 // check xrender support for this drawable
1518 if( !aDstPic )
1520 return false;
1523 // prepare transformation for ObjectToDevice coordinate system
1524 basegfx::B2DHomMatrix aObjectToDevice = basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5) * rObjectToDevice;
1526 // convert the Triangles into XRender-Triangles
1527 std::vector<XTriangle> aTriVector(rTriangles.size());
1528 sal_uInt32 nIndex(0);
1530 for(const auto& rCandidate : rTriangles)
1532 const basegfx::B2DPoint aP1(aObjectToDevice * rCandidate.getA());
1533 const basegfx::B2DPoint aP2(aObjectToDevice * rCandidate.getB());
1534 const basegfx::B2DPoint aP3(aObjectToDevice * rCandidate.getC());
1535 XTriangle& rTri(aTriVector[nIndex++]);
1537 rTri.p1.x = XDoubleToFixed(aP1.getX());
1538 rTri.p1.y = XDoubleToFixed(aP1.getY());
1540 rTri.p2.x = XDoubleToFixed(aP2.getX());
1541 rTri.p2.y = XDoubleToFixed(aP2.getY());
1543 rTri.p3.x = XDoubleToFixed(aP3.getX());
1544 rTri.p3.y = XDoubleToFixed(aP3.getY());
1547 // get xrender Picture for polygon foreground
1548 // TODO: cache it like the target picture which uses GetXRenderPicture()
1549 XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
1550 SalDisplay::RenderEntry& rEntry = mrParent.GetDisplay()->GetRenderEntries( mrParent.m_nXScreen )[ 32 ];
1551 if( !rEntry.m_aPicture )
1553 Display* pXDisplay = mrParent.GetXDisplay();
1555 rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, mrParent.hDrawable_, 1, 1, 32 );
1556 XRenderPictureAttributes aAttr;
1557 aAttr.repeat = int(true);
1559 XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
1560 rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
1563 // set polygon foreground color and opacity
1564 XRenderColor aRenderColor = GetXRenderColor( mnBrushColor , fTransparency );
1565 rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
1567 // set clipping
1568 // TODO: move into GetXRenderPicture?
1569 if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) )
1570 rRenderPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion );
1572 // render the trapezoids
1573 const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
1574 rRenderPeer.CompositeTriangles( PictOpOver,
1575 rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, aTriVector.data(), aTriVector.size() );
1577 return true;
1580 namespace {
1582 class SystemDependentData_Triangulation : public basegfx::SystemDependentData
1584 private:
1585 // the triangulation itself
1586 basegfx::triangulator::B2DTriangleVector maTriangles;
1588 // all other values the triangulation is based on and
1589 // need to be compared with to check for data validity
1590 double mfLineWidth;
1591 basegfx::B2DLineJoin meJoin;
1592 css::drawing::LineCap meCap;
1593 double mfMiterMinimumAngle;
1594 std::vector< double > maStroke;
1596 public:
1597 SystemDependentData_Triangulation(
1598 basegfx::SystemDependentDataManager& rSystemDependentDataManager,
1599 const basegfx::triangulator::B2DTriangleVector& rTriangles,
1600 double fLineWidth,
1601 basegfx::B2DLineJoin eJoin,
1602 css::drawing::LineCap eCap,
1603 double fMiterMinimumAngle,
1604 const std::vector< double >* pStroke); // MM01
1606 // read access
1607 const basegfx::triangulator::B2DTriangleVector& getTriangles() const { return maTriangles; }
1608 double getLineWidth() const { return mfLineWidth; }
1609 const basegfx::B2DLineJoin& getJoin() const { return meJoin; }
1610 const css::drawing::LineCap& getCap() const { return meCap; }
1611 double getMiterMinimumAngle() const { return mfMiterMinimumAngle; }
1612 const std::vector< double >& getStroke() const { return maStroke; }
1614 virtual sal_Int64 estimateUsageInBytes() const override;
1619 SystemDependentData_Triangulation::SystemDependentData_Triangulation(
1620 basegfx::SystemDependentDataManager& rSystemDependentDataManager,
1621 const basegfx::triangulator::B2DTriangleVector& rTriangles,
1622 double fLineWidth,
1623 basegfx::B2DLineJoin eJoin,
1624 css::drawing::LineCap eCap,
1625 double fMiterMinimumAngle,
1626 const std::vector< double >* pStroke)
1627 : basegfx::SystemDependentData(rSystemDependentDataManager),
1628 maTriangles(rTriangles),
1629 mfLineWidth(fLineWidth),
1630 meJoin(eJoin),
1631 meCap(eCap),
1632 mfMiterMinimumAngle(fMiterMinimumAngle),
1633 maStroke()
1635 if(nullptr != pStroke)
1637 maStroke = *pStroke;
1641 sal_Int64 SystemDependentData_Triangulation::estimateUsageInBytes() const
1643 sal_Int64 nRetval(0);
1645 if(!maTriangles.empty())
1647 nRetval = maTriangles.size() * sizeof(basegfx::triangulator::B2DTriangle);
1650 return nRetval;
1653 bool X11SalGraphicsImpl::drawPolyLine(
1654 const basegfx::B2DHomMatrix& rObjectToDevice,
1655 const basegfx::B2DPolygon& rPolygon,
1656 double fTransparency,
1657 double fLineWidth,
1658 const std::vector< double >* pStroke, // MM01
1659 basegfx::B2DLineJoin eLineJoin,
1660 css::drawing::LineCap eLineCap,
1661 double fMiterMinimumAngle,
1662 bool bPixelSnapHairline)
1664 // short circuit if there is nothing to do
1665 if(0 == rPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
1667 return true;
1670 // need to check/handle LineWidth when ObjectToDevice transformation is used
1671 const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
1672 basegfx::B2DHomMatrix aObjectToDeviceInv;
1674 // tdf#124848 calculate-back logical LineWidth for a hairline.
1675 // This implementation does not hand over the transformation to
1676 // the graphic sub-system, but the triangulation data is prepared
1677 // view-independent based on the logic LineWidth, so we need to
1678 // know it
1679 if(fLineWidth == 0)
1681 fLineWidth = 1.0;
1683 if(!bObjectToDeviceIsIdentity)
1685 if(aObjectToDeviceInv.isIdentity())
1687 aObjectToDeviceInv = rObjectToDevice;
1688 aObjectToDeviceInv.invert();
1691 fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 0)).getLength();
1695 // try to access buffered data
1696 std::shared_ptr<SystemDependentData_Triangulation> pSystemDependentData_Triangulation(
1697 rPolygon.getSystemDependentData<SystemDependentData_Triangulation>());
1699 // MM01 need to do line dashing as fallback stuff here now
1700 const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
1701 const bool bStrokeUsed(0.0 != fDotDashLength);
1702 assert(!bStrokeUsed || (bStrokeUsed && pStroke));
1704 if(pSystemDependentData_Triangulation)
1706 // MM01 - check on stroke change. Used against not used, or if oth used,
1707 // equal or different? Triangulation geometry creation depends heavily
1708 // on stroke, independent of being transformation independent
1709 const bool bStrokeWasUsed(!pSystemDependentData_Triangulation->getStroke().empty());
1711 if(bStrokeWasUsed != bStrokeUsed
1712 || (bStrokeUsed && *pStroke != pSystemDependentData_Triangulation->getStroke()))
1714 // data invalid, forget
1715 pSystemDependentData_Triangulation.reset();
1719 if(pSystemDependentData_Triangulation)
1721 // check data validity (I)
1722 if(pSystemDependentData_Triangulation->getJoin() != eLineJoin
1723 || pSystemDependentData_Triangulation->getCap() != eLineCap
1724 || pSystemDependentData_Triangulation->getMiterMinimumAngle() != fMiterMinimumAngle)
1726 // data invalid, forget
1727 pSystemDependentData_Triangulation.reset();
1731 if(pSystemDependentData_Triangulation)
1733 // check data validity (II)
1734 if(pSystemDependentData_Triangulation->getLineWidth() != fLineWidth)
1736 // sometimes small inconsistencies, use a percentage tolerance
1737 const double fFactor(basegfx::fTools::equalZero(fLineWidth)
1738 ? 0.0
1739 : fabs(1.0 - (pSystemDependentData_Triangulation->getLineWidth() / fLineWidth)));
1740 // compare with 5.0% tolerance
1741 if(basegfx::fTools::more(fFactor, 0.05))
1743 // data invalid, forget
1744 pSystemDependentData_Triangulation.reset();
1749 if(!pSystemDependentData_Triangulation)
1751 // MM01 need to do line dashing as fallback stuff here now
1752 basegfx::B2DPolyPolygon aPolyPolygonLine;
1754 if(bStrokeUsed)
1756 // apply LineStyle
1757 basegfx::utils::applyLineDashing(
1758 rPolygon, // source
1759 *pStroke, // pattern
1760 &aPolyPolygonLine, // target for lines
1761 nullptr, // target for gaps
1762 fDotDashLength); // full length if available
1764 else
1766 // no line dashing, just copy
1767 aPolyPolygonLine.append(rPolygon);
1770 // try to create data
1771 if(bPixelSnapHairline)
1773 // Do NOT transform, but keep device-independent. To
1774 // do so, transform to device for snap, but back again after
1775 if(!bObjectToDeviceIsIdentity)
1777 aPolyPolygonLine.transform(rObjectToDevice);
1780 aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
1782 if(!bObjectToDeviceIsIdentity)
1784 if(aObjectToDeviceInv.isIdentity())
1786 aObjectToDeviceInv = rObjectToDevice;
1787 aObjectToDeviceInv.invert();
1790 aPolyPolygonLine.transform(aObjectToDeviceInv);
1794 basegfx::triangulator::B2DTriangleVector aTriangles;
1796 // MM01 checked/verified for X11 (linux)
1797 for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
1799 const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
1800 // MM01 upps - commit 51b5b93092d6231615de470c62494c24e54828a1 removed
1801 // this *central* geometry-creating lines (!) probably due to aAreaPolyPoly
1802 // *not* being used - that's true, but the work is inside of filling
1803 // aTriangles data (!)
1804 basegfx::utils::createAreaGeometry(
1805 aPolyLine,
1806 0.5 * fLineWidth,
1807 eLineJoin,
1808 eLineCap,
1809 basegfx::deg2rad(12.5),
1810 0.4,
1811 fMiterMinimumAngle,
1812 &aTriangles); // CAUTION! This is *needed* since it creates the data!
1815 if(!aTriangles.empty())
1817 // Add to buffering mechanism
1818 // Add all values the triangulation is based off, too, to check for
1819 // validity (see above)
1820 pSystemDependentData_Triangulation = rPolygon.addOrReplaceSystemDependentData<SystemDependentData_Triangulation>(
1821 ImplGetSystemDependentDataManager(),
1822 aTriangles,
1823 fLineWidth,
1824 eLineJoin,
1825 eLineCap,
1826 fMiterMinimumAngle,
1827 pStroke);
1831 if(!pSystemDependentData_Triangulation)
1833 return false;
1836 // temporarily adjust brush color to pen color
1837 // since the line is drawn as an area-polygon
1838 const Color aKeepBrushColor = mnBrushColor;
1839 mnBrushColor = mnPenColor;
1841 // create the area-polygon for the line
1842 const bool bDrawnOk(
1843 drawFilledTriangles(
1844 rObjectToDevice,
1845 pSystemDependentData_Triangulation->getTriangles(),
1846 fTransparency));
1848 // restore the original brush GC
1849 mnBrushColor = aKeepBrushColor;
1850 return bDrawnOk;
1853 Color X11SalGraphicsImpl::getPixel( tools::Long nX, tools::Long nY )
1855 if( mrParent.bWindow_ && !mrParent.bVirDev_ )
1857 XWindowAttributes aAttrib;
1859 XGetWindowAttributes( mrParent.GetXDisplay(), mrParent.GetDrawable(), &aAttrib );
1860 if( aAttrib.map_state != IsViewable )
1862 SAL_WARN( "vcl", "X11SalGraphics::GetPixel drawable not viewable" );
1863 return 0;
1867 XImage *pXImage = XGetImage( mrParent.GetXDisplay(),
1868 mrParent.GetDrawable(),
1869 nX, nY,
1870 1, 1,
1871 AllPlanes,
1872 ZPixmap );
1873 if( !pXImage )
1875 SAL_WARN( "vcl", "X11SalGraphics::GetPixel !XGetImage()" );
1876 return 0;
1879 XColor aXColor;
1881 aXColor.pixel = XGetPixel( pXImage, 0, 0 );
1882 XDestroyImage( pXImage );
1884 return mrParent.GetColormap().GetColor( aXColor.pixel );
1887 std::shared_ptr<SalBitmap> X11SalGraphicsImpl::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY )
1889 bool bFakeWindowBG = false;
1891 // normalize
1892 if( nDX < 0 )
1894 nX += nDX;
1895 nDX = -nDX;
1897 if ( nDY < 0 )
1899 nY += nDY;
1900 nDY = -nDY;
1903 if( mrParent.bWindow_ && !mrParent.bVirDev_ )
1905 XWindowAttributes aAttrib;
1907 XGetWindowAttributes( mrParent.GetXDisplay(), mrParent.GetDrawable(), &aAttrib );
1908 if( aAttrib.map_state != IsViewable )
1909 bFakeWindowBG = true;
1910 else
1912 tools::Long nOrgDX = nDX, nOrgDY = nDY;
1914 // clip to window size
1915 if ( nX < 0 )
1917 nDX += nX;
1918 nX = 0;
1920 if ( nY < 0 )
1922 nDY += nY;
1923 nY = 0;
1925 if( nX + nDX > aAttrib.width )
1926 nDX = aAttrib.width - nX;
1927 if( nY + nDY > aAttrib.height )
1928 nDY = aAttrib.height - nY;
1930 // inside ?
1931 if( nDX <= 0 || nDY <= 0 )
1933 bFakeWindowBG = true;
1934 nDX = nOrgDX;
1935 nDY = nOrgDY;
1940 std::shared_ptr<X11SalBitmap> pSalBitmap = std::make_shared<X11SalBitmap>();
1941 sal_uInt16 nBitCount = GetBitCount();
1943 if( &mrParent.GetDisplay()->GetColormap( mrParent.m_nXScreen ) != &mrParent.GetColormap() )
1944 nBitCount = 1;
1946 if( ! bFakeWindowBG )
1947 pSalBitmap->ImplCreateFromDrawable( mrParent.GetDrawable(), mrParent.m_nXScreen, nBitCount, nX, nY, nDX, nDY );
1948 else
1949 pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) );
1951 return pSalBitmap;
1954 sal_uInt16 X11SalGraphicsImpl::GetBitCount() const
1956 return mrParent.GetVisual().GetDepth();
1959 tools::Long X11SalGraphicsImpl::GetGraphicsWidth() const
1961 if( mrParent.m_pFrame )
1962 return mrParent.m_pFrame->maGeometry.nWidth;
1963 else if( mrParent.m_pVDev )
1964 return static_cast< X11SalVirtualDevice* >(mrParent.m_pVDev)->GetWidth();
1965 else
1966 return 0;
1969 bool X11SalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, const Gradient& /*rGradient*/)
1971 return false;
1974 bool X11SalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, SalGradient const & /*rGradient*/)
1976 return false;
1979 bool X11SalGraphicsImpl::supportsOperation(OutDevSupportType eType) const
1981 bool bRet = false;
1982 switch (eType)
1984 case OutDevSupportType::TransparentRect:
1985 case OutDevSupportType::B2DDraw:
1987 XRenderPeer& rPeer = XRenderPeer::GetInstance();
1988 const SalDisplay* pSalDisp = mrParent.GetDisplay();
1989 const SalVisual& rSalVis = pSalDisp->GetVisual(mrParent.GetScreenNumber());
1991 Visual* pDstXVisual = rSalVis.GetVisual();
1992 XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat(pDstXVisual);
1993 if (pDstVisFmt)
1994 bRet = true;
1996 break;
1997 default:
1998 break;
2000 return bRet;
2003 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */