1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
34 #include "saldata.hxx"
35 #include "saldisp.hxx"
39 #include "xrender_peer.hxx"
41 #include "vcl/printergfx.hxx"
42 #include "vcl/jobdata.hxx"
44 #include "tools/debug.hxx"
46 #include "basegfx/polygon/b2dpolygon.hxx"
47 #include "basegfx/polygon/b2dpolypolygon.hxx"
48 #include "basegfx/polygon/b2dpolypolygontools.hxx"
49 #include "basegfx/polygon/b2dpolygontools.hxx"
50 #include "basegfx/polygon/b2dpolygonclipper.hxx"
51 #include "basegfx/polygon/b2dlinegeometry.hxx"
52 #include "basegfx/matrix/b2dhommatrix.hxx"
53 #include "basegfx/polygon/b2dpolypolygoncutter.hxx"
59 // -=-= SalPolyLine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
60 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
61 #define STATIC_POINTS 64
65 XPoint Points_
[STATIC_POINTS
];
68 inline SalPolyLine( ULONG nPoints
);
69 inline SalPolyLine( ULONG nPoints
, const SalPoint
*p
);
70 inline ~SalPolyLine();
71 inline XPoint
&operator [] ( ULONG n
) const
72 { return pFirst_
[n
]; }
75 inline SalPolyLine::SalPolyLine( ULONG nPoints
)
76 : pFirst_( nPoints
+1 > STATIC_POINTS
? new XPoint
[nPoints
+1] : Points_
)
79 inline SalPolyLine::SalPolyLine( ULONG nPoints
, const SalPoint
*p
)
80 : pFirst_( nPoints
+1 > STATIC_POINTS
? new XPoint
[nPoints
+1] : Points_
)
82 for( ULONG i
= 0; i
< nPoints
; i
++ )
84 pFirst_
[i
].x
= (short)p
[i
].mnX
;
85 pFirst_
[i
].y
= (short)p
[i
].mnY
;
87 pFirst_
[nPoints
] = pFirst_
[0]; // close polyline
90 inline SalPolyLine::~SalPolyLine()
91 { if( pFirst_
!= Points_
) delete [] pFirst_
; }
94 // -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
95 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
96 X11SalGraphics::X11SalGraphics()
100 m_pDeleteColormap
= NULL
;
102 m_aRenderPicture
= 0;
103 m_pRenderFormat
= NULL
;
106 pPaintRegion_
= NULL
;
110 nPenColor_
= MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
113 for( int i
= 0; i
< MAX_FALLBACK
; ++i
)
116 mpServerFont
[i
] = NULL
;
120 nTextColor_
= MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
122 #ifdef ENABLE_GRAPHITE
123 // check if graphite fonts have been disabled
124 static const char* pDisableGraphiteStr
= getenv( "SAL_DISABLE_GRAPHITE" );
125 bDisableGraphite_
= pDisableGraphiteStr
? (pDisableGraphiteStr
[0]!='0') : FALSE
;
130 nBrushColor_
= MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
150 bInvert50GC_
= FALSE
;
152 bTrackingGC_
= FALSE
;
154 bDitherBrush_
= FALSE
;
157 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
158 X11SalGraphics::~X11SalGraphics()
164 // -=-= SalGraphics / X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
166 void X11SalGraphics::freeResources()
168 Display
*pDisplay
= GetXDisplay();
170 DBG_ASSERT( !pPaintRegion_
, "pPaintRegion_" );
171 if( pClipRegion_
) XDestroyRegion( pClipRegion_
), pClipRegion_
= None
;
173 if( hBrush_
) XFreePixmap( pDisplay
, hBrush_
), hBrush_
= None
;
174 if( pPenGC_
) XFreeGC( pDisplay
, pPenGC_
), pPenGC_
= None
;
175 if( pFontGC_
) XFreeGC( pDisplay
, pFontGC_
), pFontGC_
= None
;
176 if( pBrushGC_
) XFreeGC( pDisplay
, pBrushGC_
), pBrushGC_
= None
;
177 if( pMonoGC_
) XFreeGC( pDisplay
, pMonoGC_
), pMonoGC_
= None
;
178 if( pCopyGC_
) XFreeGC( pDisplay
, pCopyGC_
), pCopyGC_
= None
;
179 if( pMaskGC_
) XFreeGC( pDisplay
, pMaskGC_
), pMaskGC_
= None
;
180 if( pInvertGC_
) XFreeGC( pDisplay
, pInvertGC_
), pInvertGC_
= None
;
181 if( pInvert50GC_
) XFreeGC( pDisplay
, pInvert50GC_
), pInvert50GC_
= None
;
182 if( pStippleGC_
) XFreeGC( pDisplay
, pStippleGC_
), pStippleGC_
= None
;
183 if( pTrackingGC_
) XFreeGC( pDisplay
, pTrackingGC_
), pTrackingGC_
= None
;
184 if( m_pDeleteColormap
)
185 delete m_pDeleteColormap
, m_pColormap
= m_pDeleteColormap
= NULL
;
187 if( m_aRenderPicture
)
188 XRenderPeer::GetInstance().FreePicture( m_aRenderPicture
), m_aRenderPicture
= 0;
190 bPenGC_
= bFontGC_
= bBrushGC_
= bMonoGC_
= bCopyGC_
= bInvertGC_
= bInvert50GC_
= bStippleGC_
= bTrackingGC_
= false;
193 void X11SalGraphics::SetDrawable( Drawable aDrawable
, int nScreen
)
195 // shortcut if nothing changed
196 if( hDrawable_
== aDrawable
)
199 // free screen specific resources if needed
200 if( nScreen
!= m_nScreen
)
203 m_pColormap
= &GetX11SalData()->GetDisplay()->GetColormap( nScreen
);
207 hDrawable_
= aDrawable
;
208 SetXRenderFormat( NULL
);
209 if( m_aRenderPicture
)
211 XRenderPeer::GetInstance().FreePicture( m_aRenderPicture
);
212 m_aRenderPicture
= 0;
217 nPenPixel_
= GetPixel( nPenColor_
);
218 nTextPixel_
= GetPixel( nTextColor_
);
219 nBrushPixel_
= GetPixel( nBrushColor_
);
223 void X11SalGraphics::Init( SalFrame
*pFrame
, Drawable aTarget
, int nScreen
)
225 #if 0 // TODO: use SetDrawable() instead
226 m_pColormap
= &GetX11SalData()->GetDisplay()->GetColormap(nScreen
);
227 hDrawable_
= aTarget
;
229 SetXRenderFormat( NULL
);
230 if( m_aRenderPicture
)
231 XRenderPeer::GetInstance().FreePicture( m_aRenderPicture
), m_aRenderPicture
= 0;
233 nPenPixel_
= GetPixel( nPenColor_
);
234 nTextPixel_
= GetPixel( nTextColor_
);
235 nBrushPixel_
= GetPixel( nBrushColor_
);
237 m_pColormap
= &GetX11SalData()->GetDisplay()->GetColormap(nScreen
);
239 SetDrawable( aTarget
, nScreen
);
247 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
248 void X11SalGraphics::DeInit()
250 SetDrawable( None
, m_nScreen
);
253 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
254 void X11SalGraphics::SetClipRegion( GC pGC
, XLIB_Region pXReg
) const
256 Display
*pDisplay
= GetXDisplay();
259 XLIB_Region Regions
[3];
261 if( pClipRegion_
/* && !XEmptyRegion( pClipRegion_ ) */ )
262 Regions
[n
++] = pClipRegion_
;
263 // if( pPaintRegion_ /* && !XEmptyRegion( pPaintRegion_ ) */ )
264 // Regions[n++] = pPaintRegion_;
266 if( pXReg
&& !XEmptyRegion( pXReg
) )
267 Regions
[n
++] = pXReg
;
270 XSetClipMask( pDisplay
, pGC
, None
);
272 XSetRegion( pDisplay
, pGC
, Regions
[0] );
275 XLIB_Region pTmpRegion
= XCreateRegion();
276 XIntersectRegion( Regions
[0], Regions
[1], pTmpRegion
);
278 // XIntersectRegion( Regions[2], pTmpRegion, pTmpRegion );
279 XSetRegion( pDisplay
, pGC
, pTmpRegion
);
280 XDestroyRegion( pTmpRegion
);
284 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
285 GC
X11SalGraphics::SelectPen()
287 Display
*pDisplay
= GetXDisplay();
292 values
.subwindow_mode
= ClipByChildren
;
293 values
.fill_rule
= EvenOddRule
; // Pict import/ Gradient
294 values
.graphics_exposures
= False
;
296 pPenGC_
= XCreateGC( pDisplay
, hDrawable_
,
297 GCSubwindowMode
| GCFillRule
| GCGraphicsExposures
,
303 if( nPenColor_
!= SALCOLOR_NONE
)
304 XSetForeground( pDisplay
, pPenGC_
, nPenPixel_
);
305 XSetFunction ( pDisplay
, pPenGC_
, bXORMode_
? GXxor
: GXcopy
);
306 SetClipRegion( pPenGC_
);
313 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
314 GC
X11SalGraphics::SelectBrush()
316 Display
*pDisplay
= GetXDisplay();
318 DBG_ASSERT( nBrushColor_
!= SALCOLOR_NONE
, "Brush Transparent" );
323 // values.subwindow_mode = IncludeInferiors;
324 values
.subwindow_mode
= ClipByChildren
;
325 values
.fill_rule
= EvenOddRule
; // Pict import/ Gradient
326 values
.graphics_exposures
= False
;
328 pBrushGC_
= XCreateGC( pDisplay
, hDrawable_
,
329 GCSubwindowMode
| GCFillRule
| GCGraphicsExposures
,
337 XSetFillStyle ( pDisplay
, pBrushGC_
, FillSolid
);
338 XSetForeground( pDisplay
, pBrushGC_
, nBrushPixel_
);
339 #if defined(_USE_PRINT_EXTENSION_)
340 XSetBackground( pDisplay
, pBrushGC_
,
341 WhitePixel(pDisplay
, DefaultScreen(pDisplay
)) );
344 XSetTile( pDisplay
, pBrushGC_
, None
);
349 // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't allways reflect
350 // changes of the tile. PROPERTY_BUG_Tile doesn't fix this !
351 if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile
)
352 XSetFillStyle ( pDisplay
, pBrushGC_
, FillSolid
);
354 XSetFillStyle ( pDisplay
, pBrushGC_
, FillTiled
);
355 XSetTile ( pDisplay
, pBrushGC_
, hBrush_
);
357 XSetFunction ( pDisplay
, pBrushGC_
, bXORMode_
? GXxor
: GXcopy
);
358 SetClipRegion( pBrushGC_
);
366 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
367 GC
X11SalGraphics::GetTrackingGC()
369 const char dash_list
[2] = {2, 2};
375 values
.graphics_exposures
= False
;
376 values
.foreground
= m_pColormap
->GetBlackPixel()
377 ^ m_pColormap
->GetWhitePixel();
378 values
.function
= GXxor
;
379 values
.line_width
= 1;
380 values
.line_style
= LineOnOffDash
;
382 pTrackingGC_
= XCreateGC( GetXDisplay(), GetDrawable(),
383 GCGraphicsExposures
| GCForeground
| GCFunction
384 | GCLineWidth
| GCLineStyle
,
386 XSetDashes( GetXDisplay(), pTrackingGC_
, 0, dash_list
, 2 );
391 SetClipRegion( pTrackingGC_
);
398 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
399 void X11SalGraphics::DrawLines( ULONG nPoints
,
400 const SalPolyLine
&rPoints
,
405 // errechne wie viele Linien XWindow auf einmal zeichnen kann
406 ULONG nMaxLines
= (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq
))
408 if( nMaxLines
> nPoints
) nMaxLines
= nPoints
;
410 // gebe alle Linien aus, die XWindows zeichnen kann.
412 for( n
= 0; nPoints
- n
> nMaxLines
; n
+= nMaxLines
- 1 )
413 XDrawLines( GetXDisplay(),
421 XDrawLines( GetXDisplay(),
429 if( rPoints
[nPoints
-1].x
!= rPoints
[0].x
|| rPoints
[nPoints
-1].y
!= rPoints
[0].y
)
430 drawLine( rPoints
[nPoints
-1].x
, rPoints
[nPoints
-1].y
, rPoints
[0].x
, rPoints
[0].y
);
434 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
435 // Dithern: Calculate a dither-pixmap and make a brush of it
437 #define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
439 BOOL
X11SalGraphics::GetDitherPixmap( SalColor nSalColor
)
441 static const short nOrdDither8Bit
[ 8 ][ 8 ] =
443 { 0, 38, 9, 48, 2, 40, 12, 50},
444 {25, 12, 35, 22, 28, 15, 37, 24},
445 { 6, 44, 3, 41, 8, 47, 5, 44},
446 {32, 19, 28, 16, 34, 21, 31, 18},
447 { 1, 40, 11, 49, 0, 39, 10, 48},
448 {27, 14, 36, 24, 26, 13, 36, 23},
449 { 8, 46, 4, 43, 7, 45, 4, 42},
450 {33, 20, 30, 17, 32, 20, 29, 16}
453 // test for correct depth (8bit)
454 if( GetColormap().GetVisual().GetDepth() != 8 )
458 char *pBitsPtr
= pBits
;
460 // Set the pallette-entries for the dithering tile
461 UINT8 nSalColorRed
= SALCOLOR_RED ( nSalColor
);
462 UINT8 nSalColorGreen
= SALCOLOR_GREEN ( nSalColor
);
463 UINT8 nSalColorBlue
= SALCOLOR_BLUE ( nSalColor
);
465 for( int nY
= 0; nY
< 8; nY
++ )
467 for( int nX
= 0; nX
< 8; nX
++ )
469 short nMagic
= nOrdDither8Bit
[nY
][nX
];
470 UINT8 nR
= P_DELTA
* DMAP( nSalColorRed
, nMagic
);
471 UINT8 nG
= P_DELTA
* DMAP( nSalColorGreen
, nMagic
);
472 UINT8 nB
= P_DELTA
* DMAP( nSalColorBlue
, nMagic
);
474 *pBitsPtr
++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR
, nG
, nB
) );
478 // create the tile as ximage and an according pixmap -> caching
479 XImage
*pImage
= XCreateImage( GetXDisplay(),
480 GetColormap().GetXVisual(),
485 8, 8, // width & height
487 0 ); // (default) bytes_per_line
489 if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile
)
492 XFreePixmap (GetXDisplay(), hBrush_
);
493 hBrush_
= XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
497 hBrush_
= XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
499 // put the ximage to the pixmap
500 XPutImage( GetXDisplay(),
502 GetDisplay()->GetCopyGC( m_nScreen
),
506 8, 8 ); // width & height
508 // destroy image-frame but not palette-data
510 XDestroyImage( pImage
);
515 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
516 void X11SalGraphics::GetResolution( sal_Int32
&rDPIX
, sal_Int32
&rDPIY
) // const
518 const SalDisplay
*pDisplay
= GetDisplay();
520 rDPIX
= pDisplay
->GetResolution().A();
521 rDPIY
= pDisplay
->GetResolution().B();
522 if( !pDisplay
->GetExactResolution() && rDPIY
< 96 )
524 rDPIX
= Divide( rDPIX
* 96, rDPIY
);
527 else if ( rDPIY
> 200 )
529 rDPIX
= Divide( rDPIX
* 200, rDPIY
);
533 // #i12705# equalize x- and y-resolution if they are close enough
536 // different x- and y- resolutions are usually artifacts of
537 // a wrongly calculated screen size.
538 //if( (13*rDPIX >= 10*rDPIY) && (13*rDPIY >= 10*rDPIX) ) //+-30%
541 printf("Forcing Resolution from %" SAL_PRIdINT32
"x%" SAL_PRIdINT32
" to %" SAL_PRIdINT32
"x%" SAL_PRIdINT32
"\n",
542 rDPIX
,rDPIY
,rDPIY
,rDPIY
);
544 rDPIX
= rDPIY
; // y-resolution is more trustworthy
549 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
550 USHORT
X11SalGraphics::GetBitCount() // const
552 return GetVisual().GetDepth();
555 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
556 long X11SalGraphics::GetGraphicsWidth() const
559 return m_pFrame
->maGeometry
.nWidth
;
561 return m_pVDev
->GetWidth();
566 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
567 long X11SalGraphics::GetGraphicsHeight() const
570 return m_pFrame
->maGeometry
.nHeight
;
572 return m_pVDev
->GetHeight();
577 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
578 void X11SalGraphics::ResetClipRegion()
588 bInvert50GC_
= FALSE
;
590 bTrackingGC_
= FALSE
;
592 XDestroyRegion( pClipRegion_
);
597 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
598 void X11SalGraphics::BeginSetClipRegion( ULONG
)
601 XDestroyRegion( pClipRegion_
);
602 pClipRegion_
= XCreateRegion();
605 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
606 BOOL
X11SalGraphics::unionClipRegion( long nX
, long nY
, long nDX
, long nDY
)
614 aRect
.width
= (unsigned short)nDX
;
615 aRect
.height
= (unsigned short)nDY
;
617 XUnionRectWithRegion( &aRect
, pClipRegion_
, pClipRegion_
);
622 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
623 bool X11SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon
& )
625 // TODO: implement and advertise OutDevSupport_B2DClip support
629 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
630 void X11SalGraphics::EndSetClipRegion()
638 bInvert50GC_
= FALSE
;
640 bTrackingGC_
= FALSE
;
642 if( XEmptyRegion( pClipRegion_
) )
644 XDestroyRegion( pClipRegion_
);
649 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
650 void X11SalGraphics::SetLineColor()
652 if( nPenColor_
!= SALCOLOR_NONE
)
654 nPenColor_
= SALCOLOR_NONE
;
659 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
660 void X11SalGraphics::SetLineColor( SalColor nSalColor
)
662 if( nPenColor_
!= nSalColor
)
664 nPenColor_
= nSalColor
;
665 nPenPixel_
= GetPixel( nSalColor
);
670 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
671 void X11SalGraphics::SetFillColor()
673 if( nBrushColor_
!= SALCOLOR_NONE
)
675 bDitherBrush_
= FALSE
;
676 nBrushColor_
= SALCOLOR_NONE
;
681 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
682 void X11SalGraphics::SetFillColor( SalColor nSalColor
)
684 if( nBrushColor_
!= nSalColor
)
686 bDitherBrush_
= FALSE
;
687 nBrushColor_
= nSalColor
;
688 nBrushPixel_
= GetPixel( nSalColor
);
689 if( TrueColor
!= GetColormap().GetVisual().GetClass()
690 && GetColormap().GetColor( nBrushPixel_
) != nBrushColor_
691 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black
692 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue
693 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green
694 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan
695 && nSalColor
!= MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red
696 && nSalColor
!= MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta
697 && nSalColor
!= MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown
698 && nSalColor
!= MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray
699 && nSalColor
!= MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray
700 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue
701 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green
702 && nSalColor
!= MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan
703 && nSalColor
!= MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red
704 && nSalColor
!= MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta
705 && nSalColor
!= MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown
706 && nSalColor
!= MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) )
707 bDitherBrush_
= GetDitherPixmap(nSalColor
);
712 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
713 void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor
)
717 case SAL_ROP_0
: // 0
718 nPenPixel_
= (Pixel
)0;
720 case SAL_ROP_1
: // 1
721 nPenPixel_
= (Pixel
)(1 << GetVisual().GetDepth()) - 1;
723 case SAL_ROP_INVERT
: // 2
724 nPenPixel_
= (Pixel
)(1 << GetVisual().GetDepth()) - 1;
727 nPenColor_
= GetColormap().GetColor( nPenPixel_
);
731 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
732 void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor
)
736 case SAL_ROP_0
: // 0
737 nBrushPixel_
= (Pixel
)0;
739 case SAL_ROP_1
: // 1
740 nBrushPixel_
= (Pixel
)(1 << GetVisual().GetDepth()) - 1;
742 case SAL_ROP_INVERT
: // 2
743 nBrushPixel_
= (Pixel
)(1 << GetVisual().GetDepth()) - 1;
746 bDitherBrush_
= FALSE
;
747 nBrushColor_
= GetColormap().GetColor( nBrushPixel_
);
751 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
752 void X11SalGraphics::SetXORMode( bool bSet
, bool )
754 if( !bXORMode_
== bSet
)
762 bInvert50GC_
= FALSE
;
764 bTrackingGC_
= FALSE
;
768 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
769 void X11SalGraphics::drawPixel( long nX
, long nY
)
771 if( nPenColor_
!= SALCOLOR_NONE
)
772 XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX
, nY
);
775 void X11SalGraphics::drawPixel( long nX
, long nY
, SalColor nSalColor
)
777 if( nSalColor
!= SALCOLOR_NONE
)
779 Display
*pDisplay
= GetXDisplay();
781 if( (nPenColor_
== SALCOLOR_NONE
) && !bPenGC_
)
783 SetLineColor( nSalColor
);
784 XDrawPoint( pDisplay
, GetDrawable(), SelectPen(), nX
, nY
);
785 nPenColor_
= SALCOLOR_NONE
;
790 GC pGC
= SelectPen();
792 if( nSalColor
!= nPenColor_
)
793 XSetForeground( pDisplay
, pGC
, GetPixel( nSalColor
) );
795 XDrawPoint( pDisplay
, GetDrawable(), pGC
, nX
, nY
);
797 if( nSalColor
!= nPenColor_
)
798 XSetForeground( pDisplay
, pGC
, nPenPixel_
);
803 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
804 void X11SalGraphics::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
806 if( nPenColor_
!= SALCOLOR_NONE
)
808 if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine
)
810 GC aGC
= SelectPen();
811 XDrawPoint (GetXDisplay(), GetDrawable(), aGC
, (int)nX1
, (int)nY1
);
812 XDrawPoint (GetXDisplay(), GetDrawable(), aGC
, (int)nX2
, (int)nY2
);
813 XDrawLine (GetXDisplay(), GetDrawable(), aGC
, nX1
, nY1
, nX2
, nY2
);
816 XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(),
817 nX1
, nY1
, nX2
, nY2
);
821 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
822 void X11SalGraphics::drawRect( long nX
, long nY
, long nDX
, long nDY
)
824 if( nBrushColor_
!= SALCOLOR_NONE
)
826 XFillRectangle( GetXDisplay(),
831 // Beschreibung DrawRect verkehrt, deshalb -1
832 if( nPenColor_
!= SALCOLOR_NONE
)
833 XDrawRectangle( GetXDisplay(),
836 nX
, nY
, nDX
-1, nDY
-1 );
839 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
840 void X11SalGraphics::drawPolyLine( ULONG nPoints
, const SalPoint
*pPtAry
)
842 drawPolyLine( nPoints
, pPtAry
, false );
845 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
846 void X11SalGraphics::drawPolyLine( ULONG nPoints
, const SalPoint
*pPtAry
, bool bClose
)
848 if( nPenColor_
!= 0xFFFFFFFF )
850 SalPolyLine
Points( nPoints
, pPtAry
);
852 DrawLines( nPoints
, Points
, SelectPen(), bClose
);
856 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
857 void X11SalGraphics::drawPolygon( ULONG nPoints
, const SalPoint
* pPtAry
)
867 drawPixel( pPtAry
[0].mnX
, pPtAry
[0].mnY
);
869 drawLine( pPtAry
[0].mnX
, pPtAry
[0].mnY
,
870 pPtAry
[1].mnX
, pPtAry
[1].mnY
);
875 SalPolyLine
Points( nPoints
, pPtAry
);
879 /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
880 * do not draw the visible part of a polygon
881 * if it overlaps to the left of screen 0,y.
882 * This happens to be the case in the gradient drawn in the
883 * menubar background. workaround for the special case of
884 * of a rectangle overlapping to the left.
887 Points
[ 0 ].x
== Points
[ 1 ].x
&&
888 Points
[ 1 ].y
== Points
[ 2 ].y
&&
889 Points
[ 2 ].x
== Points
[ 3 ].x
&&
890 Points
[ 0 ].x
== Points
[ 4 ].x
&& Points
[ 0 ].y
== Points
[ 4 ].y
895 for(unsigned int i
= 0; i
< nPoints
; i
++ )
897 if( Points
[i
].x
< 0 )
902 if( bLeft
&& ! bRight
)
904 if( bLeft
&& bRight
)
906 for( unsigned int i
= 0; i
< nPoints
; i
++ )
907 if( Points
[i
].x
< 0 )
912 if( nBrushColor_
!= SALCOLOR_NONE
)
913 XFillPolygon( GetXDisplay(),
917 Complex
, CoordModeOrigin
);
919 if( nPenColor_
!= 0xFFFFFFFF )
920 DrawLines( nPoints
, Points
, SelectPen(), true );
923 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
924 void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly
,
925 const sal_uInt32
*pPoints
,
926 PCONSTSALPOINT
*pPtAry
)
928 if( nBrushColor_
!= SALCOLOR_NONE
)
931 XLIB_Region pXRegA
= NULL
;
933 for( i
= 0; i
< nPoly
; i
++ ) {
935 SalPolyLine
Points( n
, pPtAry
[i
] );
938 XLIB_Region pXRegB
= XPolygonRegion( &Points
[0], n
+1, WindingRule
);
943 XXorRegion( pXRegA
, pXRegB
, pXRegA
);
944 XDestroyRegion( pXRegB
);
952 XClipBox( pXRegA
, &aXRect
);
954 GC pGC
= SelectBrush();
955 SetClipRegion( pGC
, pXRegA
); // ??? doppelt
956 XDestroyRegion( pXRegA
);
959 XFillRectangle( GetXDisplay(),
962 aXRect
.x
, aXRect
.y
, aXRect
.width
, aXRect
.height
);
966 if( nPenColor_
!= SALCOLOR_NONE
)
967 for( ULONG i
= 0; i
< nPoly
; i
++ )
968 drawPolyLine( pPoints
[i
], pPtAry
[i
], true );
971 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
973 sal_Bool
X11SalGraphics::drawPolyLineBezier( ULONG
, const SalPoint
*, const BYTE
* )
978 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
980 sal_Bool
X11SalGraphics::drawPolygonBezier( ULONG
, const SalPoint
*, const BYTE
* )
985 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
987 sal_Bool
X11SalGraphics::drawPolyPolygonBezier( sal_uInt32
, const sal_uInt32
*,
988 const SalPoint
* const*, const BYTE
* const* )
993 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
995 void X11SalGraphics::invert( ULONG nPoints
,
996 const SalPoint
* pPtAry
,
999 SalPolyLine
Points ( nPoints
, pPtAry
);
1002 if( SAL_INVERT_50
& nFlags
)
1003 pGC
= GetInvert50GC();
1005 if ( SAL_INVERT_TRACKFRAME
& nFlags
)
1006 pGC
= GetTrackingGC();
1008 pGC
= GetInvertGC();
1010 if( SAL_INVERT_TRACKFRAME
& nFlags
)
1011 DrawLines ( nPoints
, Points
, pGC
, true );
1013 XFillPolygon( GetXDisplay(),
1016 &Points
[0], nPoints
,
1017 Complex
, CoordModeOrigin
);
1020 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1022 BOOL
X11SalGraphics::drawEPS( long,long,long,long,void*,ULONG
)
1027 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1029 XID
X11SalGraphics::GetXRenderPicture()
1031 if( !m_aRenderPicture
)
1033 // check xrender support for matching visual
1034 // find a XRenderPictFormat compatible with the Drawable
1035 XRenderPeer
& rRenderPeer
= XRenderPeer::GetInstance();
1036 XRenderPictFormat
* pVisualFormat
= static_cast<XRenderPictFormat
*>(GetXRenderFormat());
1037 if( !pVisualFormat
)
1039 Visual
* pVisual
= GetDisplay()->GetVisual( m_nScreen
).GetVisual();
1040 pVisualFormat
= rRenderPeer
.FindVisualFormat( pVisual
);
1041 if( !pVisualFormat
)
1043 // cache the XRenderPictFormat
1044 SetXRenderFormat( static_cast<void*>(pVisualFormat
) );
1047 // get the matching xrender target for drawable
1048 m_aRenderPicture
= rRenderPeer
.CreatePicture( hDrawable_
, pVisualFormat
, 0, NULL
);
1052 // setup clipping so the callers don't have to do it themselves
1053 // TODO: avoid clipping if already set correctly
1054 if( pClipRegion_
&& !XEmptyRegion( pClipRegion_
) )
1055 rRenderPeer
.SetPictureClipRegion( aDstPic
, pClipRegion_
);
1058 return m_aRenderPicture
;
1061 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1063 SystemGraphicsData
X11SalGraphics::GetGraphicsData() const
1065 SystemGraphicsData aRes
;
1067 aRes
.nSize
= sizeof(aRes
);
1068 aRes
.pDisplay
= GetXDisplay();
1069 aRes
.hDrawable
= hDrawable_
;
1070 aRes
.pVisual
= GetDisplay()->GetVisual( m_nScreen
).GetVisual();
1071 aRes
.nScreen
= m_nScreen
;
1072 aRes
.nDepth
= GetDisplay()->GetVisual( m_nScreen
).GetDepth();
1073 aRes
.aColormap
= GetDisplay()->GetColormap( m_nScreen
).GetXColormap();
1074 aRes
.pRenderFormat
= m_pRenderFormat
;
1078 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1080 // B2DPolygon support methods
1082 namespace { // anonymous namespace to prevent export
1083 // the methods and structures here are used by the
1084 // B2DPolyPolygon->RenderTrapezoid conversion algorithm
1086 // compare two line segments
1087 // assumption: both segments point downward
1088 // assumption: they must have at least some y-overlap
1089 // assumption: rA.p1.y <= rB.p1.y
1090 bool IsLeftOf( const XLineFixed
& rA
, const XLineFixed
& rB
)
1092 bool bAbove
= (rA
.p1
.y
<= rB
.p1
.y
);
1093 const XLineFixed
& rU
= bAbove
? rA
: rB
;
1094 const XLineFixed
& rL
= bAbove
? rB
: rA
;
1096 const XFixed aXDiff
= rU
.p2
.x
- rU
.p1
.x
;
1097 const XFixed aYDiff
= rU
.p2
.y
- rU
.p1
.y
;
1099 if( (rU
.p1
.y
!= rL
.p1
.y
) || (rU
.p1
.x
!= rL
.p1
.x
) )
1101 const sal_Int64 n1
= (sal_Int64
)aXDiff
* (rL
.p1
.y
- rU
.p1
.y
);
1102 const sal_Int64 n2
= (sal_Int64
)aYDiff
* (rL
.p1
.x
- rU
.p1
.x
);
1104 return ((n1
< n2
) == bAbove
);
1107 if( (rU
.p2
.y
!= rL
.p2
.y
) || (rU
.p2
.x
!= rL
.p2
.x
) )
1109 const sal_Int64 n3
= (sal_Int64
)aXDiff
* (rL
.p2
.y
- rU
.p1
.y
);
1110 const sal_Int64 n4
= (sal_Int64
)aYDiff
* (rL
.p2
.x
- rU
.p1
.x
);
1112 return ((n3
< n4
) == bAbove
);
1115 // both segments overlap
1119 struct HalfTrapezoid
1122 // maLine.p1.y <= mnY < maLine.p2.y
1127 struct HalfTrapCompare
1129 bool operator()( const HalfTrapezoid
& rA
, const HalfTrapezoid
& rB
) const
1131 bool bIsTopLeft
= false;
1132 if( rA
.mnY
!= rB
.mnY
) // sort top-first if possible
1133 bIsTopLeft
= (rA
.mnY
< rB
.mnY
);
1134 else // else sort left-first
1135 bIsTopLeft
= IsLeftOf( rA
.maLine
, rB
.maLine
);
1136 // adjust to priority_queue sorting convention
1141 typedef std::priority_queue
< HalfTrapezoid
, std::vector
<HalfTrapezoid
>, HalfTrapCompare
> HTQueueBase
;
1142 // we need a priority queue with a reserve() to prevent countless reallocations
1144 : public HTQueueBase
1147 void reserve( size_t n
) { c
.reserve( n
); }
1148 int capacity() { return c
.capacity(); }
1151 typedef std::vector
<XTrapezoid
> TrapezoidVector
;
1153 class TrapezoidXCompare
1155 const TrapezoidVector
& mrVector
;
1157 TrapezoidXCompare( const TrapezoidVector
& rVector
)
1158 : mrVector( rVector
) {}
1159 bool operator()( int nA
, int nB
) const
1160 { return IsLeftOf( mrVector
[nA
].left
, mrVector
[nB
].left
); }
1163 typedef std::multiset
< int, TrapezoidXCompare
> ActiveTrapSet
;
1165 class TrapezoidYCompare
1167 const TrapezoidVector
& mrVector
;
1169 TrapezoidYCompare( const TrapezoidVector
& rVector
)
1170 : mrVector( rVector
) {}
1171 bool operator()( int nA
, int nB
) const
1172 { return (mrVector
[nA
].bottom
< mrVector
[nB
].bottom
); }
1175 typedef std::multiset
< int, TrapezoidYCompare
> VerticalTrapSet
;
1176 } // end of anonymous namespace
1178 // draw a poly-polygon
1179 bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon
& rOrigPolyPoly
, double fTransparency
)
1181 // nothing to do for empty polypolygons
1182 const int nOrigPolyCount
= rOrigPolyPoly
.count();
1183 if( nOrigPolyCount
<= 0 )
1186 // nothing to do if everything is transparent
1187 if( (nBrushColor_
== SALCOLOR_NONE
)
1188 && (nPenColor_
== SALCOLOR_NONE
) )
1191 // cannot handle pencolor!=brushcolor yet
1192 if( (nPenColor_
!= SALCOLOR_NONE
)
1193 && (nPenColor_
!= nBrushColor_
) )
1196 // TODO: remove the env-variable when no longer needed
1197 static const char* pRenderEnv
= getenv( "SAL_DISABLE_RENDER_POLY" );
1201 // check xrender support for trapezoids
1202 XRenderPeer
& rRenderPeer
= XRenderPeer::GetInstance();
1203 if( !rRenderPeer
.AreTrapezoidsSupported() )
1205 Picture aDstPic
= GetXRenderPicture();
1206 // check xrender support for this drawable
1210 // don't bother with polygons outside of visible area
1211 const basegfx::B2DRange
aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
1212 const basegfx::B2DRange aPolyRange
= basegfx::tools::getRange( rOrigPolyPoly
);
1213 const bool bNeedViewClip
= !aPolyRange
.isInside( aViewRange
);
1214 if( !aPolyRange
.overlaps( aViewRange
) )
1217 // convert the polypolygon to trapezoids
1219 // prepare the polypolygon for the algorithm below:
1220 // - clip it against the view range
1221 // - make sure it contains no self-intersections
1222 // while we are at it guess the number of involved polygon points
1223 int nHTQueueReserve
= 0;
1224 basegfx::B2DPolyPolygon aGoodPolyPoly
;
1225 for( int nOrigPolyIdx
= 0; nOrigPolyIdx
< nOrigPolyCount
; ++nOrigPolyIdx
)
1227 const ::basegfx::B2DPolygon aOuterPolygon
= rOrigPolyPoly
.getB2DPolygon( nOrigPolyIdx
);
1229 // render-trapezoids should be inside the view => clip polygon against view range
1230 basegfx::B2DPolyPolygon
aClippedPolygon( aOuterPolygon
);
1233 aClippedPolygon
= basegfx::tools::clipPolygonOnRange( aOuterPolygon
, aViewRange
, true, false );
1234 DBG_ASSERT( aClippedPolygon
.count(), "polygon confirmed to overlap with view should not get here" );
1236 const int nClippedPolyCount
= aClippedPolygon
.count();
1237 if( !nClippedPolyCount
)
1240 // #i103259# polypoly.solveCrossover() fails to remove self-intersections
1241 // but polygon.solveCrossover() works. Use it to build the intersection-free polypolygon
1242 // TODO: if the self-intersection prevention is too expensive make the trap-algorithm tolerate intersections
1243 for( int nClippedPolyIdx
= 0; nClippedPolyIdx
< nClippedPolyCount
; ++nClippedPolyIdx
)
1245 ::basegfx::B2DPolygon aUnsolvedPolygon
= aClippedPolygon
.getB2DPolygon( nClippedPolyIdx
);
1246 basegfx::B2DPolyPolygon
aSolvedPolyPoly( basegfx::tools::solveCrossovers( aUnsolvedPolygon
) );
1247 const int nSolvedPolyCount
= aSolvedPolyPoly
.count();
1248 for( int nSolvedPolyIdx
= 0; nSolvedPolyIdx
< nSolvedPolyCount
; ++nSolvedPolyIdx
)
1250 // build the intersection-free polypolygon one by one
1251 const ::basegfx::B2DPolygon aSolvedPolygon
= aSolvedPolyPoly
.getB2DPolygon( nSolvedPolyIdx
);
1252 aGoodPolyPoly
.append( aSolvedPolygon
);
1253 // and while we are at it use the conviently available point count to guess the number of needed half-traps
1254 const int nPointCount
= aSolvedPolygon
.count();
1255 nHTQueueReserve
+= aSolvedPolygon
.areControlPointsUsed() ? 8 * nPointCount
: nPointCount
;
1259 // #i100922# try to prevent priority-queue reallocations by reservering enough
1260 nHTQueueReserve
= ((4*nHTQueueReserve
) | 0x1FFF) + 1;
1262 aHTQueue
.reserve( nHTQueueReserve
);
1264 // first convert the B2DPolyPolygon to HalfTrapezoids
1265 const int nGoodPolyCount
= aGoodPolyPoly
.count();
1266 for( int nGoodPolyIdx
= 0; nGoodPolyIdx
< nGoodPolyCount
; ++nGoodPolyIdx
)
1268 ::basegfx::B2DPolygon aInnerPolygon
= aGoodPolyPoly
.getB2DPolygon( nGoodPolyIdx
);
1270 // render-trapezoids have linear edges => get rid of bezier segments
1271 if( aInnerPolygon
.areControlPointsUsed() )
1272 aInnerPolygon
= ::basegfx::tools::adaptiveSubdivideByDistance( aInnerPolygon
, 0.125 );
1274 const int nPointCount
= aInnerPolygon
.count();
1275 if( nPointCount
>= 3 )
1277 // convert polygon point pairs to HalfTrapezoids
1278 // connect the polygon point with the first one if needed
1279 XPointFixed aOldXPF
= { 0, 0 };
1280 XPointFixed aNewXPF
;
1281 for( int nPointIdx
= 0; nPointIdx
<= nPointCount
; ++nPointIdx
, aOldXPF
= aNewXPF
)
1283 // auto-close the polygon if needed
1284 const int k
= (nPointIdx
< nPointCount
) ? nPointIdx
: 0;
1285 const ::basegfx::B2DPoint
& aPoint
= aInnerPolygon
.getB2DPoint( k
);
1287 // convert the B2DPoint into XRENDER units
1288 if(getAntiAliasB2DDraw())
1290 aNewXPF
.x
= XDoubleToFixed( aPoint
.getX() );
1291 aNewXPF
.y
= XDoubleToFixed( aPoint
.getY() );
1295 aNewXPF
.x
= XDoubleToFixed( basegfx::fround( aPoint
.getX() ) );
1296 aNewXPF
.y
= XDoubleToFixed( basegfx::fround( aPoint
.getY() ) );
1299 // check if enough data is available for a new HalfTrapezoid
1300 if( nPointIdx
== 0 )
1302 // ignore vertical segments
1303 if( aNewXPF
.y
== aOldXPF
.y
)
1306 // construct HalfTrapezoid as topdown segment
1308 if( aNewXPF
.y
< aOldXPF
.y
)
1310 aHT
.maLine
.p1
= aNewXPF
;
1311 aHT
.maLine
.p2
= aOldXPF
;
1315 aHT
.maLine
.p2
= aNewXPF
;
1316 aHT
.maLine
.p1
= aOldXPF
;
1319 aHT
.mnY
= aHT
.maLine
.p1
.y
;
1321 #if 0 // ignore clipped HalfTrapezoids
1324 else if( aHT
.mnY
> 10000 )
1328 // queue up the HalfTrapezoid
1329 aHTQueue
.push( aHT
);
1334 if( aHTQueue
.empty() )
1337 // then convert the HalfTrapezoids into full Trapezoids
1338 TrapezoidVector aTrapVector
;
1339 aTrapVector
.reserve( aHTQueue
.size() * 2 ); // just a guess
1341 TrapezoidXCompare
aTrapXCompare( aTrapVector
);
1342 ActiveTrapSet
aActiveTraps( aTrapXCompare
);
1344 TrapezoidYCompare
aTrapYCompare( aTrapVector
);
1345 VerticalTrapSet
aVerticalTraps( aTrapYCompare
);
1347 while( !aHTQueue
.empty() )
1349 XTrapezoid aTrapezoid
;
1351 // convert a HalfTrapezoid pair
1352 const HalfTrapezoid
& rLeft
= aHTQueue
.top();
1353 aTrapezoid
.top
= rLeft
.mnY
;
1354 aTrapezoid
.bottom
= rLeft
.maLine
.p2
.y
;
1355 aTrapezoid
.left
= rLeft
.maLine
;
1358 // ignore empty trapezoids
1359 if( aTrapezoid
.bottom
<= aTrapezoid
.top
)
1364 if( aHTQueue
.empty() ) // TODO: assert
1366 const HalfTrapezoid
& rRight
= aHTQueue
.top();
1367 aTrapezoid
.right
= rRight
.maLine
;
1370 aTrapezoid
.bottom
= aTrapezoid
.left
.p2
.y
;
1371 if( aTrapezoid
.bottom
> aTrapezoid
.right
.p2
.y
)
1372 aTrapezoid
.bottom
= aTrapezoid
.right
.p2
.y
;
1374 // keep the full Trapezoid candidate
1375 aTrapVector
.push_back( aTrapezoid
);
1377 // unless it splits an older trapezoid
1378 bool bSplit
= false;
1381 // check if the new trapezoid overlaps with an old trapezoid
1382 ActiveTrapSet::iterator aActiveTrapsIt
1383 = aActiveTraps
.upper_bound( aTrapVector
.size()-1 );
1384 if( aActiveTrapsIt
== aActiveTraps
.begin() )
1388 XTrapezoid
& rLeftTrap
= aTrapVector
[ *aActiveTrapsIt
];
1390 // in the ActiveTrapSet there are still trapezoids where
1391 // a vertical overlap with new trapezoids is no longer possible
1392 // they could have been removed in the verticaltraps loop below
1393 // but this would have been expensive and is not needed as we can
1394 // simply ignore them now and remove them from the ActiveTrapSet
1395 // so they won't bother us in the future
1396 if( rLeftTrap
.bottom
<= aTrapezoid
.top
)
1398 aActiveTraps
.erase( aActiveTrapsIt
);
1402 // check if there is horizontal overlap
1403 // aTrapezoid.left==rLeftTrap.right is allowed though
1404 if( !IsLeftOf( aTrapezoid
.left
, rLeftTrap
.right
) )
1407 // split the old trapezoid and keep its upper part
1408 // find the old trapezoids entry in the VerticalTrapSet and remove it
1409 typedef std::pair
<VerticalTrapSet::iterator
, VerticalTrapSet::iterator
> VTSPair
;
1410 VTSPair aVTSPair
= aVerticalTraps
.equal_range( *aActiveTrapsIt
);
1411 VerticalTrapSet::iterator aVTSit
= aVTSPair
.first
;
1412 for(; (aVTSit
!= aVTSPair
.second
) && (*aVTSit
!= *aActiveTrapsIt
); ++aVTSit
) ;
1413 if( aVTSit
!= aVTSPair
.second
)
1414 aVerticalTraps
.erase( aVTSit
);
1415 // then update the old trapezoid's bottom
1416 rLeftTrap
.bottom
= aTrapezoid
.top
;
1417 // enter the updated old trapzoid in VerticalTrapSet
1418 aVerticalTraps
.insert( aVerticalTraps
.begin(), *aActiveTrapsIt
);
1419 // the old trapezoid is no longer active
1420 aActiveTraps
.erase( aActiveTrapsIt
);
1422 // the trapezoid causing the split has become obsolete
1423 // so its both sides have to be re-queued
1425 aHT
.mnY
= aTrapezoid
.top
;
1426 aHT
.maLine
= aTrapezoid
.left
;
1427 aHTQueue
.push( aHT
);
1428 aHT
.maLine
= aTrapezoid
.right
;
1429 aHTQueue
.push( aHT
);
1435 // keep or forget the resulting full Trapezoid
1437 aTrapVector
.pop_back();
1440 aActiveTraps
.insert( aTrapVector
.size()-1 );
1441 aVerticalTraps
.insert( aTrapVector
.size()-1 );
1444 // mark trapezoids that can no longer be split as inactive
1445 // and recycle their sides which were not fully resolved
1446 static const XFixed nMaxTop
= +0x7FFFFFFF;
1447 XFixed nNewTop
= aHTQueue
.empty() ? nMaxTop
: aHTQueue
.top().mnY
;
1448 while( !aVerticalTraps
.empty() )
1450 const XTrapezoid
& rOldTrap
= aTrapVector
[ *aVerticalTraps
.begin() ];
1451 if( nNewTop
< rOldTrap
.bottom
)
1453 // the reference Trapezoid can no longer be split
1454 aVerticalTraps
.erase( aVerticalTraps
.begin() );
1456 // recycle its sides that were not fully resolved
1458 aHT
.mnY
= rOldTrap
.bottom
;
1459 if( rOldTrap
.left
.p2
.y
> rOldTrap
.bottom
)
1461 aHT
.maLine
= rOldTrap
.left
;
1462 aHTQueue
.push( aHT
);
1464 if( rOldTrap
.right
.p2
.y
> rOldTrap
.bottom
)
1466 aHT
.maLine
= rOldTrap
.right
;
1467 aHTQueue
.push( aHT
);
1472 // create xrender Picture for polygon foreground
1473 SalDisplay::RenderEntry
& rEntry
= GetDisplay()->GetRenderEntries( m_nScreen
)[ 32 ];
1474 if( !rEntry
.m_aPicture
)
1476 Display
* pXDisplay
= GetXDisplay();
1478 rEntry
.m_aPixmap
= ::XCreatePixmap( pXDisplay
, hDrawable_
, 1, 1, 32 );
1479 XRenderPictureAttributes aAttr
;
1480 aAttr
.repeat
= true;
1482 XRenderPictFormat
* pXRPF
= rRenderPeer
.FindStandardFormat( PictStandardARGB32
);
1483 rEntry
.m_aPicture
= rRenderPeer
.CreatePicture( rEntry
.m_aPixmap
, pXRPF
, CPRepeat
, &aAttr
);
1486 // set polygon foreground color and opacity
1487 XRenderColor aRenderColor
= GetXRenderColor( nBrushColor_
, fTransparency
);
1488 rRenderPeer
.FillRectangle( PictOpSrc
, rEntry
.m_aPicture
, &aRenderColor
, 0, 0, 1, 1 );
1491 // TODO: move into GetXRenderPicture?
1492 if( pClipRegion_
&& !XEmptyRegion( pClipRegion_
) )
1493 rRenderPeer
.SetPictureClipRegion( aDstPic
, pClipRegion_
);
1495 // render the trapezoids
1496 const XRenderPictFormat
* pMaskFormat
= rRenderPeer
.GetStandardFormatA8();
1497 rRenderPeer
.CompositeTrapezoids( PictOpOver
,
1498 rEntry
.m_aPicture
, aDstPic
, pMaskFormat
, 0, 0, &aTrapVector
[0], aTrapVector
.size() );
1503 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1505 bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon
& rPolygon
, const ::basegfx::B2DVector
& rLineWidth
, basegfx::B2DLineJoin eLineJoin
)
1508 if(rPolygon
.count() > 1000)
1510 // the used basegfx::tools::createAreaGeometry is simply too
1511 // expensive with very big polygons; fallback to caller (who
1512 // should use ImplLineConverter normally)
1515 const XRenderPeer
& rRenderPeer
= XRenderPeer::GetInstance();
1516 if( !rRenderPeer
.AreTrapezoidsSupported() )
1519 // get the area polygon for the line polygon
1520 basegfx::B2DPolygon aPolygon
= rPolygon
;
1521 if( (rLineWidth
.getX() != rLineWidth
.getY())
1522 && !basegfx::fTools::equalZero( rLineWidth
.getY() ) )
1524 // prepare for createAreaGeometry() with anisotropic linewidth
1525 basegfx::B2DHomMatrix aAnisoMatrix
;
1526 aAnisoMatrix
.scale( 1.0, rLineWidth
.getX() / rLineWidth
.getY() );
1527 aPolygon
.transform( aAnisoMatrix
);
1530 // AW: reSegment no longer needed; new createAreaGeometry will remove exteme positions
1531 // and create bezier polygons
1532 //if( aPolygon.areControlPointsUsed() )
1533 // aPolygon = basegfx::tools::reSegmentPolygonEdges( aPolygon, 8, true, false );
1534 //const basegfx::B2DPolyPolygon aAreaPolyPoly = basegfx::tools::createAreaGeometryForSimplePolygon(
1535 // aPolygon, 0.5*rLineWidth.getX(), eLineJoin );
1536 const basegfx::B2DPolyPolygon
aAreaPolyPoly(basegfx::tools::createAreaGeometry(aPolygon
, 0.5*rLineWidth
.getX(), eLineJoin
));
1538 if( (rLineWidth
.getX() != rLineWidth
.getY())
1539 && !basegfx::fTools::equalZero( rLineWidth
.getX() ) )
1541 // postprocess createAreaGeometry() for anisotropic linewidth
1542 basegfx::B2DHomMatrix aAnisoMatrix
;
1543 aAnisoMatrix
.scale( 1.0, rLineWidth
.getY() / rLineWidth
.getX() );
1544 aPolygon
.transform( aAnisoMatrix
);
1547 // temporarily adjust brush color to pen color
1548 // since the line is drawn as an area-polygon
1549 const SalColor aKeepBrushColor
= nBrushColor_
;
1550 nBrushColor_
= nPenColor_
;
1552 // draw each area polypolygon component individually
1553 // to emulate the polypolygon winding rule "non-zero"
1554 bool bDrawOk
= true;
1555 const int nPolyCount
= aAreaPolyPoly
.count();
1556 for( int nPolyIdx
= 0; nPolyIdx
< nPolyCount
; ++nPolyIdx
)
1558 const ::basegfx::B2DPolyPolygon
aOnePoly( aAreaPolyPoly
.getB2DPolygon( nPolyIdx
) );
1559 bDrawOk
= drawPolyPolygon( aOnePoly
, 0.0);
1564 // restore the original brush GC
1565 nBrushColor_
= aKeepBrushColor
;
1569 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=