1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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 ) \
57 XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
59 rPosAry.mnDestWidth, rPosAry.mnDestHeight, \
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
;
71 std::vector
<XPoint
> Points_
;
73 SalPolyLine(sal_uLong nPoints
, const Point
*p
)
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
89 XPoint
&operator[](sal_uLong n
)
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
);
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
):
124 mnBrushColor( 0xFF, 0xFF, 0XFF ),
134 mbDitherBrush(false),
137 mnPenColor( 0x00, 0x00, 0x00 ),
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
)
169 // get the matching xrender target for drawable
170 mrParent
.m_aXRenderPicture
= rRenderPeer
.CreatePicture( mrParent
.hDrawable_
, pXRenderFormat
, 0, nullptr );
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
)
188 XFreeGC( pDisplay
, rGC
);
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
)
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();
230 mpCopyGC
= CreateGC( mrParent
.GetDrawable() );
234 mrParent
.SetClipRegion( mpCopyGC
);
240 GC
X11SalGraphicsImpl::GetTrackingGC()
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
,
257 const char dash_list
[2] = {2, 2};
258 XSetDashes( mrParent
.GetXDisplay(), mpTrackingGC
, 0, dash_list
, 2 );
263 mrParent
.SetClipRegion( mpTrackingGC
);
270 GC
X11SalGraphicsImpl::GetInvertGC()
273 mpInvertGC
= CreateGC( mrParent
.GetDrawable(),
281 mrParent
.SetClipRegion( mpInvertGC
);
287 GC
X11SalGraphicsImpl::GetInvert50GC()
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
=
309 values
.fill_style
= FillStippled
;
310 values
.stipple
= mrParent
.GetDisplay()->GetInvert50( mrParent
.m_nXScreen
);
312 mpInvert50GC
= XCreateGC( mrParent
.GetXDisplay(), mrParent
.GetDrawable(),
319 mrParent
.SetClipRegion( mpInvert50GC
);
325 inline GC
X11SalGraphicsImpl::GetStippleGC()
328 mpStippleGC
= CreateGC( mrParent
.GetDrawable(),
335 XSetFunction( mrParent
.GetXDisplay(), mpStippleGC
, mbXORMode
? GXxor
: GXcopy
);
336 mrParent
.SetClipRegion( mpStippleGC
);
343 GC
X11SalGraphicsImpl::SelectBrush()
345 Display
*pDisplay
= mrParent
.GetXDisplay();
347 SAL_WARN_IF( mnBrushColor
== SALCOLOR_NONE
, "vcl", "Brush Transparent" );
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
,
365 XSetFillStyle ( pDisplay
, mpBrushGC
, FillSolid
);
366 XSetForeground( pDisplay
, mpBrushGC
, mnBrushPixel
);
370 XSetFillStyle ( pDisplay
, mpBrushGC
, FillTiled
);
371 XSetTile ( pDisplay
, mpBrushGC
, mrParent
.hBrush_
);
373 XSetFunction ( pDisplay
, mpBrushGC
, mbXORMode
? GXxor
: GXcopy
);
374 mrParent
.SetClipRegion( mpBrushGC
);
382 GC
X11SalGraphicsImpl::SelectPen()
384 Display
*pDisplay
= mrParent
.GetXDisplay();
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
,
400 if( mnPenColor
!= SALCOLOR_NONE
)
401 XSetForeground( pDisplay
, mpPenGC
, mnPenPixel
);
402 XSetFunction ( pDisplay
, mpPenGC
, mbXORMode
? GXxor
: GXcopy
);
403 mrParent
.SetClipRegion( mpPenGC
);
410 void X11SalGraphicsImpl::DrawLines(sal_uInt32 nPoints
,
411 const SalPolyLine
&rPoints
,
415 // calculate how many lines XWindow can draw in one go
416 sal_uLong nMaxLines
= (mrParent
.GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq
))
418 if( nMaxLines
> nPoints
) nMaxLines
= nPoints
;
420 // print all lines that XWindows can draw
422 for( n
= 0; nPoints
- n
> nMaxLines
; n
+= nMaxLines
- 1 )
423 XDrawLines( mrParent
.GetXDisplay(),
424 mrParent
.GetDrawable(),
426 const_cast<XPoint
*>(&rPoints
[n
]),
431 XDrawLines( mrParent
.GetXDisplay(),
432 mrParent
.GetDrawable(),
434 const_cast<XPoint
*>(&rPoints
[n
]),
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
)
451 if( rPosAry
.mnSrcWidth
<= 0
452 || rPosAry
.mnSrcHeight
<= 0
453 || rPosAry
.mnDestWidth
<= 0
454 || rPosAry
.mnDestHeight
<= 0 )
460 if( pSrcGraphics
== &mrParent
)
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
473 n
= 1; // printer or other display
475 else if( pSrcGraphics
->bVirDev_
)
477 n
= 1; // window or compatible virtual device
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(),
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();
514 XSetGraphicsExposures( mrParent
.GetXDisplay(),
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
,
527 rPosAry
.mnSrcHeight
));
531 SAL_WARN( "vcl", "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()" );
535 SalTwoRect
aPosAry( rPosAry
);
539 drawBitmap( aPosAry
, *xDDB
);
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
);
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
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
) );
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
,
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
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
,
668 rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
,
670 DBG_TESTTRANS( aBG
);
672 // #105055# Disable XOR temporarily
673 bool bOldXORMode( mbXORMode
);
676 // copy pixmap #2 (result) to background
677 XCopyArea( pXDisp
, aBG
, aDrawable
, GetCopyGC(),
679 rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
,
680 rPosAry
.mnDestX
, rPosAry
.mnDestY
);
682 DBG_TESTTRANS( aBG
);
684 mbXORMode
= bOldXORMode
;
686 XFreeGC( pXDisp
, aTmpGC
);
690 drawBitmap( rPosAry
, rSalBitmap
);
693 XFreePixmap( pXDisp
, aFG
);
696 XFreePixmap( pXDisp
, aBG
);
699 bool X11SalGraphicsImpl::blendBitmap( const SalTwoRect
&,
705 bool X11SalGraphicsImpl::blendAlphaBitmap( const SalTwoRect
&,
706 const SalBitmap
&, const SalBitmap
&, const SalBitmap
& )
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 )
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() )
723 // horizontal mirroring not implemented yet
724 if( rTR
.mnDestWidth
< 0 )
727 // stretched conversion is not implemented yet
728 if( rTR
.mnDestWidth
!= rTR
.mnSrcWidth
)
730 if( rTR
.mnDestHeight
!= rTR
.mnSrcHeight
)
733 // create destination picture
734 Picture aDstPic
= GetXRenderPicture();
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
);
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() )
756 Pixmap aSrcPM
= pSrcDDB
->ImplGetPixmap();
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
);
767 Picture aSrcPic
= rPeer
.CreatePicture( aSrcPM
, pSrcVisFmt
, 0, nullptr );
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
);
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
)
798 char* pCDst
= reinterpret_cast<char*>(pLDst
);
799 for( int i
= nImageSize
& (sizeof(long)-1); --i
>= 0; ++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 );
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
);
817 if( pAlphaBits
!= reinterpret_cast<char*>(pAlphaBuffer
->mpBits
) )
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
);
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
);
843 bool X11SalGraphicsImpl::drawTransformedBitmap(
844 const basegfx::B2DPoint
&,
845 const basegfx::B2DPoint
&,
846 const basegfx::B2DPoint
&,
850 // here direct support for transformed bitmaps can be implemented
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
)
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 )
866 Picture aDstPic
= GetXRenderPicture();
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
,
883 void X11SalGraphicsImpl::drawMask( const SalTwoRect
& rPosAry
,
884 const SalBitmap
&rSalBitmap
,
887 const SalDisplay
* pSalDisp
= mrParent
.GetDisplay();
888 Display
* pXDisp
= pSalDisp
->GetDisplay();
889 Drawable
aDrawable( mrParent
.GetDrawable() );
890 Pixmap
aStipple( limitXCreatePixmap( pXDisp
, aDrawable
,
892 rPosAry
.mnDestHeight
, 1 ) );
896 SalTwoRect
aTwoRect( rPosAry
); aTwoRect
.mnDestX
= aTwoRect
.mnDestY
= 0;
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
,
918 rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
919 XFreePixmap( pXDisp
, aStipple
);
923 drawBitmap( rPosAry
, rSalBitmap
);
926 void X11SalGraphicsImpl::ResetClipRegion()
928 if( !mrParent
.mpClipRegion
)
935 mbInvert50GC
= 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());
958 const tools::Long
nH(rectangle
.GetHeight());
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 )
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 );
988 // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
991 // done, invalidate GCs
996 mbInvert50GC
= false;
998 mbTrackingGC
= false;
1000 if( XEmptyRegion( mrParent
.mpClipRegion
) )
1002 XDestroyRegion( mrParent
.mpClipRegion
);
1003 mrParent
.mpClipRegion
= nullptr;
1008 void X11SalGraphicsImpl::SetLineColor()
1010 if( mnPenColor
!= SALCOLOR_NONE
)
1012 mnPenColor
= SALCOLOR_NONE
;
1017 void X11SalGraphicsImpl::SetLineColor( Color nColor
)
1019 if( mnPenColor
!= nColor
)
1021 mnPenColor
= nColor
;
1022 mnPenPixel
= mrParent
.GetPixel( nColor
);
1027 void X11SalGraphicsImpl::SetFillColor()
1029 if( mnBrushColor
!= SALCOLOR_NONE
)
1031 mbDitherBrush
= false;
1032 mnBrushColor
= SALCOLOR_NONE
;
1037 void X11SalGraphicsImpl::SetFillColor( Color nColor
)
1039 if( mnBrushColor
== nColor
)
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
);
1067 void X11SalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor
)
1071 case SalROPColor::N0
: // 0
1072 mnPenPixel
= Pixel(0);
1074 case SalROPColor::N1
: // 1
1075 mnPenPixel
= static_cast<Pixel
>(1 << mrParent
.GetVisual().GetDepth()) - 1;
1077 case SalROPColor::Invert
: // 2
1078 mnPenPixel
= static_cast<Pixel
>(1 << mrParent
.GetVisual().GetDepth()) - 1;
1081 mnPenColor
= mrParent
.GetColormap().GetColor( mnPenPixel
);
1085 void X11SalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor
)
1089 case SalROPColor::N0
: // 0
1090 mnBrushPixel
= Pixel(0);
1092 case SalROPColor::N1
: // 1
1093 mnBrushPixel
= static_cast<Pixel
>(1 << mrParent
.GetVisual().GetDepth()) - 1;
1095 case SalROPColor::Invert
: // 2
1096 mnBrushPixel
= static_cast<Pixel
>(1 << mrParent
.GetVisual().GetDepth()) - 1;
1099 mbDitherBrush
= false;
1100 mnBrushColor
= mrParent
.GetColormap().GetColor( mnBrushPixel
);
1104 void X11SalGraphicsImpl::SetXORMode( bool bSet
, bool )
1106 if (mbXORMode
!= bSet
)
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
)
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
;
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(),
1171 // description DrawRect is wrong; thus -1
1172 if( mnPenColor
!= SALCOLOR_NONE
)
1173 XDrawRectangle( mrParent
.GetXDisplay(),
1174 mrParent
.GetDrawable(),
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
)
1204 drawPixel( pPtAry
[0].getX(), pPtAry
[0].getY() );
1206 drawLine( pPtAry
[0].getX(), pPtAry
[0].getY(),
1207 pPtAry
[1].getX(), pPtAry
[1].getY() );
1212 SalPolyLine
Points( nPoints
, pPtAry
);
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.
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
1231 bool bRight
= false;
1232 for(unsigned int i
= 0; i
< nPoints
; i
++ )
1234 if( Points
[i
].x
< 0 )
1239 if( bLeft
&& ! bRight
)
1241 if( bLeft
&& bRight
)
1243 for( unsigned int i
= 0; i
< nPoints
; i
++ )
1244 if( Points
[i
].x
< 0 )
1249 if( mnBrushColor
!= SALCOLOR_NONE
)
1250 XFillPolygon( mrParent
.GetXDisplay(),
1251 mrParent
.GetDrawable(),
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
)
1267 Region pXRegA
= nullptr;
1269 for( i
= 0; i
< nPoly
; i
++ ) {
1271 SalPolyLine
Points( n
, pPtAry
[i
] );
1274 Region pXRegB
= XPolygonRegion( &Points
[0], n
+1, WindingRule
);
1279 XXorRegion( pXRegA
, pXRegB
, pXRegA
);
1280 XDestroyRegion( pXRegB
);
1288 XClipBox( pXRegA
, &aXRect
);
1290 GC pGC
= SelectBrush();
1291 mrParent
.SetClipRegion( pGC
, pXRegA
); // ??? twice
1292 XDestroyRegion( pXRegA
);
1295 XFillRectangle( mrParent
.GetXDisplay(),
1296 mrParent
.GetDrawable(),
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
* )
1312 bool X11SalGraphicsImpl::drawPolygonBezier( sal_uInt32
, const Point
*, const PolyFlags
* )
1317 bool X11SalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32
, const sal_uInt32
*,
1318 const Point
* const*, const PolyFlags
* const* )
1323 void X11SalGraphicsImpl::invert( tools::Long nX
,
1330 if( SalInvert::N50
& nFlags
)
1332 pGC
= GetInvert50GC();
1333 XFillRectangle( mrParent
.GetXDisplay(), mrParent
.GetDrawable(), pGC
, nX
, nY
, nDX
, nDY
);
1337 if ( SalInvert::TrackFrame
& nFlags
)
1339 pGC
= GetTrackingGC();
1340 XDrawRectangle( mrParent
.GetXDisplay(), mrParent
.GetDrawable(), pGC
, nX
, nY
, nDX
, nDY
);
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
,
1354 SalPolyLine
Points ( nPoints
, pPtAry
);
1357 if( SalInvert::N50
& nFlags
)
1358 pGC
= GetInvert50GC();
1360 if ( SalInvert::TrackFrame
& nFlags
)
1361 pGC
= GetTrackingGC();
1363 pGC
= GetInvertGC();
1365 if( SalInvert::TrackFrame
& nFlags
)
1366 DrawLines ( nPoints
, Points
, pGC
, true );
1368 XFillPolygon( mrParent
.GetXDisplay(),
1369 mrParent
.GetDrawable(),
1371 &Points
[0], nPoints
,
1372 Complex
, CoordModeOrigin
);
1375 bool X11SalGraphicsImpl::drawEPS( tools::Long
,tools::Long
,tools::Long
,tools::Long
,void*,sal_uInt32
)
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 )
1391 // nothing to do if everything is transparent
1392 if( (mnBrushColor
== SALCOLOR_NONE
)
1393 && (mnPenColor
== SALCOLOR_NONE
) )
1396 // cannot handle pencolor!=brushcolor yet
1397 if( (mnPenColor
!= SALCOLOR_NONE
)
1398 && (mnPenColor
!= mnBrushColor
) )
1401 // TODO: remove the env-variable when no longer needed
1402 static const char* pRenderEnv
= getenv( "SAL_DISABLE_RENDER_POLY" );
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();
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() )
1421 // tessellate the polypolygon into trapezoids
1422 basegfx::B2DTrapezoidVector aB2DTrapVector
;
1423 basegfx::utils::trapezoidSubdivide( aB2DTrapVector
, aPolyPolygon
);
1424 const int nTrapCount
= aB2DTrapVector
.size();
1427 const bool bDrawn
= drawFilledTrapezoids( aB2DTrapVector
.data(), nTrapCount
, fTransparency
);
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();
1441 bool X11SalGraphicsImpl::drawFilledTrapezoids( const basegfx::B2DTrapezoid
* pB2DTraps
, int nTrapCount
, double fTransparency
)
1443 if( nTrapCount
<= 0 )
1446 Picture aDstPic
= GetXRenderPicture();
1447 // check xrender support for this drawable
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 );
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() );
1508 bool X11SalGraphicsImpl::drawFilledTriangles(
1509 const basegfx::B2DHomMatrix
& rObjectToDevice
,
1510 const basegfx::triangulator::B2DTriangleVector
& rTriangles
,
1511 double fTransparency
)
1513 if(rTriangles
.empty())
1516 Picture aDstPic
= GetXRenderPicture();
1517 // check xrender support for this drawable
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 );
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() );
1582 class SystemDependentData_Triangulation
: public basegfx::SystemDependentData
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
1591 basegfx::B2DLineJoin meJoin
;
1592 css::drawing::LineCap meCap
;
1593 double mfMiterMinimumAngle
;
1594 std::vector
< double > maStroke
;
1597 SystemDependentData_Triangulation(
1598 basegfx::SystemDependentDataManager
& rSystemDependentDataManager
,
1599 const basegfx::triangulator::B2DTriangleVector
& rTriangles
,
1601 basegfx::B2DLineJoin eJoin
,
1602 css::drawing::LineCap eCap
,
1603 double fMiterMinimumAngle
,
1604 const std::vector
< double >* pStroke
); // MM01
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
,
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
),
1632 mfMiterMinimumAngle(fMiterMinimumAngle
),
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
);
1653 bool X11SalGraphicsImpl::drawPolyLine(
1654 const basegfx::B2DHomMatrix
& rObjectToDevice
,
1655 const basegfx::B2DPolygon
& rPolygon
,
1656 double fTransparency
,
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)
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
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
)
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
;
1757 basegfx::utils::applyLineDashing(
1759 *pStroke
, // pattern
1760 &aPolyPolygonLine
, // target for lines
1761 nullptr, // target for gaps
1762 fDotDashLength
); // full length if available
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(
1809 basegfx::deg2rad(12.5),
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(),
1831 if(!pSystemDependentData_Triangulation
)
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(
1845 pSystemDependentData_Triangulation
->getTriangles(),
1848 // restore the original brush GC
1849 mnBrushColor
= aKeepBrushColor
;
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" );
1867 XImage
*pXImage
= XGetImage( mrParent
.GetXDisplay(),
1868 mrParent
.GetDrawable(),
1875 SAL_WARN( "vcl", "X11SalGraphics::GetPixel !XGetImage()" );
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;
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;
1912 tools::Long nOrgDX
= nDX
, nOrgDY
= nDY
;
1914 // clip to window size
1925 if( nX
+ nDX
> aAttrib
.width
)
1926 nDX
= aAttrib
.width
- nX
;
1927 if( nY
+ nDY
> aAttrib
.height
)
1928 nDY
= aAttrib
.height
- nY
;
1931 if( nDX
<= 0 || nDY
<= 0 )
1933 bFakeWindowBG
= true;
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() )
1946 if( ! bFakeWindowBG
)
1947 pSalBitmap
->ImplCreateFromDrawable( mrParent
.GetDrawable(), mrParent
.m_nXScreen
, nBitCount
, nX
, nY
, nDX
, nDY
);
1949 pSalBitmap
->Create( Size( nDX
, nDY
), (nBitCount
> 8) ? 24 : nBitCount
, BitmapPalette( nBitCount
> 8 ? nBitCount
: 0 ) );
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();
1969 bool X11SalGraphicsImpl::drawGradient(const tools::PolyPolygon
& /*rPolygon*/, const Gradient
& /*rGradient*/)
1974 bool X11SalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon
const & /*rPolyPolygon*/, SalGradient
const & /*rGradient*/)
1979 bool X11SalGraphicsImpl::supportsOperation(OutDevSupportType eType
) const
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
);
2003 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */