update dev300-m58
[ooovba.git] / vcl / unx / source / gdi / salgdi.cxx
blobabbf97ef9c1da79d9d18272f109d4fcf8ce148d6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
31 #include "Xproto.h"
33 #include "salunx.h"
34 #include "saldata.hxx"
35 #include "saldisp.hxx"
36 #include "salgdi.h"
37 #include "salframe.h"
38 #include "salvd.h"
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"
55 #include <vector>
56 #include <queue>
57 #include <set>
59 // -=-= SalPolyLine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
60 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
61 #define STATIC_POINTS 64
63 class SalPolyLine
65 XPoint Points_[STATIC_POINTS];
66 XPoint *pFirst_;
67 public:
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_; }
93 #undef STATIC_POINTS
94 // -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
95 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
96 X11SalGraphics::X11SalGraphics()
98 m_pFrame = NULL;
99 m_pVDev = NULL;
100 m_pDeleteColormap = NULL;
101 hDrawable_ = None;
102 m_aRenderPicture = 0;
103 m_pRenderFormat = NULL;
105 pClipRegion_ = NULL;
106 pPaintRegion_ = NULL;
108 pPenGC_ = NULL;
109 nPenPixel_ = 0;
110 nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
112 pFontGC_ = NULL;
113 for( int i = 0; i < MAX_FALLBACK; ++i )
115 mXFont[i] = NULL;
116 mpServerFont[i] = NULL;
119 nTextPixel_ = 0;
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;
126 #endif
128 pBrushGC_ = NULL;
129 nBrushPixel_ = 0;
130 nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
131 hBrush_ = None;
133 pMonoGC_ = NULL;
134 pCopyGC_ = NULL;
135 pMaskGC_ = NULL;
136 pInvertGC_ = NULL;
137 pInvert50GC_ = NULL;
138 pStippleGC_ = NULL;
139 pTrackingGC_ = NULL;
141 bWindow_ = FALSE;
142 bPrinter_ = FALSE;
143 bVirDev_ = FALSE;
144 bPenGC_ = FALSE;
145 bFontGC_ = FALSE;
146 bBrushGC_ = FALSE;
147 bMonoGC_ = FALSE;
148 bCopyGC_ = FALSE;
149 bInvertGC_ = FALSE;
150 bInvert50GC_ = FALSE;
151 bStippleGC_ = FALSE;
152 bTrackingGC_ = FALSE;
153 bXORMode_ = FALSE;
154 bDitherBrush_ = FALSE;
157 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
158 X11SalGraphics::~X11SalGraphics()
160 ReleaseFonts();
161 freeResources();
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 )
197 return;
199 // free screen specific resources if needed
200 if( nScreen != m_nScreen )
202 freeResources();
203 m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap( nScreen );
204 m_nScreen = nScreen;
207 hDrawable_ = aDrawable;
208 SetXRenderFormat( NULL );
209 if( m_aRenderPicture )
211 XRenderPeer::GetInstance().FreePicture( m_aRenderPicture );
212 m_aRenderPicture = 0;
215 if( hDrawable_ )
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;
228 m_nScreen = nScreen;
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_ );
236 #else
237 m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen);
238 m_nScreen = nScreen;
239 SetDrawable( aTarget, nScreen );
240 #endif
242 bWindow_ = TRUE;
243 m_pFrame = pFrame;
244 m_pVDev = NULL;
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();
258 int n = 0;
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;
269 if( 0 == n )
270 XSetClipMask( pDisplay, pGC, None );
271 else if( 1 == n )
272 XSetRegion( pDisplay, pGC, Regions[0] );
273 else
275 XLIB_Region pTmpRegion = XCreateRegion();
276 XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
277 // if( 3 == n )
278 // XIntersectRegion( Regions[2], pTmpRegion, pTmpRegion );
279 XSetRegion( pDisplay, pGC, pTmpRegion );
280 XDestroyRegion( pTmpRegion );
284 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
285 GC X11SalGraphics::SelectPen()
287 Display *pDisplay = GetXDisplay();
289 if( !pPenGC_ )
291 XGCValues values;
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,
298 &values );
301 if( !bPenGC_ )
303 if( nPenColor_ != SALCOLOR_NONE )
304 XSetForeground( pDisplay, pPenGC_, nPenPixel_ );
305 XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy );
306 SetClipRegion( pPenGC_ );
307 bPenGC_ = TRUE;
310 return pPenGC_;
313 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
314 GC X11SalGraphics::SelectBrush()
316 Display *pDisplay = GetXDisplay();
318 DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" );
320 if( !pBrushGC_ )
322 XGCValues values;
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,
330 &values );
333 if( !bBrushGC_ )
335 if( !bDitherBrush_ )
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)) );
342 #else
343 if( bPrinter_ )
344 XSetTile( pDisplay, pBrushGC_, None );
345 #endif
347 else
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_ );
360 bBrushGC_ = TRUE;
363 return pBrushGC_;
366 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
367 GC X11SalGraphics::GetTrackingGC()
369 const char dash_list[2] = {2, 2};
371 if( !pTrackingGC_ )
373 XGCValues values;
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,
385 &values );
386 XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 );
389 if( !bTrackingGC_ )
391 SetClipRegion( pTrackingGC_ );
392 bTrackingGC_ = TRUE;
395 return pTrackingGC_;
398 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
399 void X11SalGraphics::DrawLines( ULONG nPoints,
400 const SalPolyLine &rPoints,
401 GC pGC,
402 bool bClose
405 // errechne wie viele Linien XWindow auf einmal zeichnen kann
406 ULONG nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
407 / sizeof(xPoint);
408 if( nMaxLines > nPoints ) nMaxLines = nPoints;
410 // gebe alle Linien aus, die XWindows zeichnen kann.
411 ULONG n;
412 for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
413 XDrawLines( GetXDisplay(),
414 GetDrawable(),
415 pGC,
416 &rPoints[n],
417 nMaxLines,
418 CoordModeOrigin );
420 if( n < nPoints )
421 XDrawLines( GetXDisplay(),
422 GetDrawable(),
423 pGC,
424 &rPoints[n],
425 nPoints - n,
426 CoordModeOrigin );
427 if( bClose )
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
436 #define P_DELTA 51
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 )
455 return FALSE;
457 char pBits[64];
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(),
482 ZPixmap,
483 0, // offset
484 pBits, // data
485 8, 8, // width & height
486 8, // bitmap_pad
487 0 ); // (default) bytes_per_line
489 if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile )
491 if (hBrush_)
492 XFreePixmap (GetXDisplay(), hBrush_);
493 hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
495 else
496 if( !hBrush_ )
497 hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
499 // put the ximage to the pixmap
500 XPutImage( GetXDisplay(),
501 hBrush_,
502 GetDisplay()->GetCopyGC( m_nScreen ),
503 pImage,
504 0, 0, // Source
505 0, 0, // Destination
506 8, 8 ); // width & height
508 // destroy image-frame but not palette-data
509 pImage->data = NULL;
510 XDestroyImage( pImage );
512 return TRUE;
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 );
525 rDPIY = 96;
527 else if ( rDPIY > 200 )
529 rDPIX = Divide( rDPIX * 200, rDPIY );
530 rDPIY = 200;
533 // #i12705# equalize x- and y-resolution if they are close enough
534 if( rDPIX != rDPIY )
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%
540 #ifdef DEBUG
541 printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
542 rDPIX,rDPIY,rDPIY,rDPIY);
543 #endif
544 rDPIX = rDPIY; // y-resolution is more trustworthy
549 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
550 USHORT X11SalGraphics::GetBitCount() // const
552 return GetVisual().GetDepth();
555 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
556 long X11SalGraphics::GetGraphicsWidth() const
558 if( m_pFrame )
559 return m_pFrame->maGeometry.nWidth;
560 else if( m_pVDev )
561 return m_pVDev->GetWidth();
562 else
563 return 0;
566 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
567 long X11SalGraphics::GetGraphicsHeight() const
569 if( m_pFrame )
570 return m_pFrame->maGeometry.nHeight;
571 else if( m_pVDev )
572 return m_pVDev->GetHeight();
573 else
574 return 0;
577 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
578 void X11SalGraphics::ResetClipRegion()
580 if( pClipRegion_ )
582 bPenGC_ = FALSE;
583 bFontGC_ = FALSE;
584 bBrushGC_ = FALSE;
585 bMonoGC_ = FALSE;
586 bCopyGC_ = FALSE;
587 bInvertGC_ = FALSE;
588 bInvert50GC_ = FALSE;
589 bStippleGC_ = FALSE;
590 bTrackingGC_ = FALSE;
592 XDestroyRegion( pClipRegion_ );
593 pClipRegion_ = NULL;
597 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
598 void X11SalGraphics::BeginSetClipRegion( ULONG )
600 if( pClipRegion_ )
601 XDestroyRegion( pClipRegion_ );
602 pClipRegion_ = XCreateRegion();
605 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
606 BOOL X11SalGraphics::unionClipRegion( long nX, long nY, long nDX, long nDY )
608 if (!nDX || !nDY)
609 return TRUE;
611 XRectangle aRect;
612 aRect.x = (short)nX;
613 aRect.y = (short)nY;
614 aRect.width = (unsigned short)nDX;
615 aRect.height = (unsigned short)nDY;
617 XUnionRectWithRegion( &aRect, pClipRegion_, pClipRegion_ );
619 return TRUE;
622 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
623 bool X11SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
625 // TODO: implement and advertise OutDevSupport_B2DClip support
626 return false;
629 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
630 void X11SalGraphics::EndSetClipRegion()
632 bPenGC_ = FALSE;
633 bFontGC_ = FALSE;
634 bBrushGC_ = FALSE;
635 bMonoGC_ = FALSE;
636 bCopyGC_ = FALSE;
637 bInvertGC_ = FALSE;
638 bInvert50GC_ = FALSE;
639 bStippleGC_ = FALSE;
640 bTrackingGC_ = FALSE;
642 if( XEmptyRegion( pClipRegion_ ) )
644 XDestroyRegion( pClipRegion_ );
645 pClipRegion_= NULL;
649 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
650 void X11SalGraphics::SetLineColor()
652 if( nPenColor_ != SALCOLOR_NONE )
654 nPenColor_ = SALCOLOR_NONE;
655 bPenGC_ = FALSE;
659 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
660 void X11SalGraphics::SetLineColor( SalColor nSalColor )
662 if( nPenColor_ != nSalColor )
664 nPenColor_ = nSalColor;
665 nPenPixel_ = GetPixel( nSalColor );
666 bPenGC_ = FALSE;
670 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
671 void X11SalGraphics::SetFillColor()
673 if( nBrushColor_ != SALCOLOR_NONE )
675 bDitherBrush_ = FALSE;
676 nBrushColor_ = SALCOLOR_NONE;
677 bBrushGC_ = FALSE;
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);
708 bBrushGC_ = FALSE;
712 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
713 void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
715 switch( nROPColor )
717 case SAL_ROP_0 : // 0
718 nPenPixel_ = (Pixel)0;
719 break;
720 case SAL_ROP_1 : // 1
721 nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
722 break;
723 case SAL_ROP_INVERT : // 2
724 nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
725 break;
727 nPenColor_ = GetColormap().GetColor( nPenPixel_ );
728 bPenGC_ = FALSE;
731 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
732 void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
734 switch( nROPColor )
736 case SAL_ROP_0 : // 0
737 nBrushPixel_ = (Pixel)0;
738 break;
739 case SAL_ROP_1 : // 1
740 nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
741 break;
742 case SAL_ROP_INVERT : // 2
743 nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
744 break;
746 bDitherBrush_ = FALSE;
747 nBrushColor_ = GetColormap().GetColor( nBrushPixel_ );
748 bBrushGC_ = FALSE;
751 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
752 void X11SalGraphics::SetXORMode( bool bSet, bool )
754 if( !bXORMode_ == bSet )
756 bXORMode_ = bSet;
757 bPenGC_ = FALSE;
758 bBrushGC_ = FALSE;
759 bMonoGC_ = FALSE;
760 bCopyGC_ = FALSE;
761 bInvertGC_ = FALSE;
762 bInvert50GC_ = FALSE;
763 bStippleGC_ = 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;
786 bPenGC_ = False;
788 else
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 );
815 else
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(),
827 GetDrawable(),
828 SelectBrush(),
829 nX, nY, nDX, nDY );
831 // Beschreibung DrawRect verkehrt, deshalb -1
832 if( nPenColor_ != SALCOLOR_NONE )
833 XDrawRectangle( GetXDisplay(),
834 GetDrawable(),
835 SelectPen(),
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 )
859 if( nPoints == 0 )
860 return;
862 if( nPoints < 3 )
864 if( !bXORMode_ )
866 if( 1 == nPoints )
867 drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
868 else
869 drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
870 pPtAry[1].mnX, pPtAry[1].mnY );
872 return;
875 SalPolyLine Points( nPoints, pPtAry );
877 nPoints++;
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.
886 if( nPoints == 5 &&
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
893 bool bLeft = false;
894 bool bRight = false;
895 for(unsigned int i = 0; i < nPoints; i++ )
897 if( Points[i].x < 0 )
898 bLeft = true;
899 else
900 bRight= true;
902 if( bLeft && ! bRight )
903 return;
904 if( bLeft && bRight )
906 for( unsigned int i = 0; i < nPoints; i++ )
907 if( Points[i].x < 0 )
908 Points[i].x = 0;
912 if( nBrushColor_ != SALCOLOR_NONE )
913 XFillPolygon( GetXDisplay(),
914 GetDrawable(),
915 SelectBrush(),
916 &Points[0], nPoints,
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 )
930 ULONG i, n;
931 XLIB_Region pXRegA = NULL;
933 for( i = 0; i < nPoly; i++ ) {
934 n = pPoints[i];
935 SalPolyLine Points( n, pPtAry[i] );
936 if( n > 2 )
938 XLIB_Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
939 if( !pXRegA )
940 pXRegA = pXRegB;
941 else
943 XXorRegion( pXRegA, pXRegB, pXRegA );
944 XDestroyRegion( pXRegB );
949 if( pXRegA )
951 XRectangle aXRect;
952 XClipBox( pXRegA, &aXRect );
954 GC pGC = SelectBrush();
955 SetClipRegion( pGC, pXRegA ); // ??? doppelt
956 XDestroyRegion( pXRegA );
957 bBrushGC_ = FALSE;
959 XFillRectangle( GetXDisplay(),
960 GetDrawable(),
961 pGC,
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* )
975 return sal_False;
978 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
980 sal_Bool X11SalGraphics::drawPolygonBezier( ULONG, const SalPoint*, const BYTE* )
982 return sal_False;
985 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
987 sal_Bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
988 const SalPoint* const*, const BYTE* const* )
990 return sal_False;
993 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
995 void X11SalGraphics::invert( ULONG nPoints,
996 const SalPoint* pPtAry,
997 SalInvert nFlags )
999 SalPolyLine Points ( nPoints, pPtAry );
1001 GC pGC;
1002 if( SAL_INVERT_50 & nFlags )
1003 pGC = GetInvert50GC();
1004 else
1005 if ( SAL_INVERT_TRACKFRAME & nFlags )
1006 pGC = GetTrackingGC();
1007 else
1008 pGC = GetInvertGC();
1010 if( SAL_INVERT_TRACKFRAME & nFlags )
1011 DrawLines ( nPoints, Points, pGC, true );
1012 else
1013 XFillPolygon( GetXDisplay(),
1014 GetDrawable(),
1015 pGC,
1016 &Points[0], nPoints,
1017 Complex, CoordModeOrigin );
1020 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1022 BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,ULONG )
1024 return FALSE;
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 )
1042 return 0;
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 );
1051 #if 0
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_ );
1056 #endif
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;
1075 return aRes;
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);
1103 if( n1 != n2 )
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);
1111 if( n3 != n4 )
1112 return ((n3 < n4) == bAbove);
1115 // both segments overlap
1116 return false;
1119 struct HalfTrapezoid
1121 // assumptions:
1122 // maLine.p1.y <= mnY < maLine.p2.y
1123 XLineFixed maLine;
1124 XFixed mnY;
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
1137 return !bIsTopLeft;
1141 typedef std::priority_queue< HalfTrapezoid, std::vector<HalfTrapezoid>, HalfTrapCompare > HTQueueBase;
1142 // we need a priority queue with a reserve() to prevent countless reallocations
1143 class HTQueue
1144 : public HTQueueBase
1146 public:
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;
1156 public:
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;
1168 public:
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 )
1184 return TRUE;
1186 // nothing to do if everything is transparent
1187 if( (nBrushColor_ == SALCOLOR_NONE)
1188 && (nPenColor_ == SALCOLOR_NONE) )
1189 return TRUE;
1191 // cannot handle pencolor!=brushcolor yet
1192 if( (nPenColor_ != SALCOLOR_NONE)
1193 && (nPenColor_ != nBrushColor_) )
1194 return FALSE;
1196 // TODO: remove the env-variable when no longer needed
1197 static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
1198 if( pRenderEnv )
1199 return FALSE;
1201 // check xrender support for trapezoids
1202 XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
1203 if( !rRenderPeer.AreTrapezoidsSupported() )
1204 return FALSE;
1205 Picture aDstPic = GetXRenderPicture();
1206 // check xrender support for this drawable
1207 if( !aDstPic )
1208 return FALSE;
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 ) )
1215 return true;
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 );
1231 if( bNeedViewClip )
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 )
1238 continue;
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;
1261 HTQueue aHTQueue;
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() );
1293 else
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 )
1301 continue;
1302 // ignore vertical segments
1303 if( aNewXPF.y == aOldXPF.y )
1304 continue;
1306 // construct HalfTrapezoid as topdown segment
1307 HalfTrapezoid aHT;
1308 if( aNewXPF.y < aOldXPF.y )
1310 aHT.maLine.p1 = aNewXPF;
1311 aHT.maLine.p2 = aOldXPF;
1313 else
1315 aHT.maLine.p2 = aNewXPF;
1316 aHT.maLine.p1 = aOldXPF;
1319 aHT.mnY = aHT.maLine.p1.y;
1321 #if 0 // ignore clipped HalfTrapezoids
1322 if( aHT.mnY < 0 )
1323 aHT.mnY = 0;
1324 else if( aHT.mnY > 10000 )
1325 continue;
1326 #endif
1328 // queue up the HalfTrapezoid
1329 aHTQueue.push( aHT );
1334 if( aHTQueue.empty() )
1335 return TRUE;
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;
1357 #if 0
1358 // ignore empty trapezoids
1359 if( aTrapezoid.bottom <= aTrapezoid.top )
1360 continue;
1361 #endif
1363 aHTQueue.pop();
1364 if( aHTQueue.empty() ) // TODO: assert
1365 break;
1366 const HalfTrapezoid& rRight = aHTQueue.top();
1367 aTrapezoid.right = rRight.maLine;
1368 aHTQueue.pop();
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;
1379 for(;;)
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() )
1385 break;
1386 --aActiveTrapsIt;
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 );
1399 continue;
1402 // check if there is horizontal overlap
1403 // aTrapezoid.left==rLeftTrap.right is allowed though
1404 if( !IsLeftOf( aTrapezoid.left, rLeftTrap.right ) )
1405 break;
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
1424 HalfTrapezoid aHT;
1425 aHT.mnY = aTrapezoid.top;
1426 aHT.maLine = aTrapezoid.left;
1427 aHTQueue.push( aHT );
1428 aHT.maLine = aTrapezoid.right;
1429 aHTQueue.push( aHT );
1431 bSplit = true;
1432 break;
1435 // keep or forget the resulting full Trapezoid
1436 if( bSplit )
1437 aTrapVector.pop_back();
1438 else
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 )
1452 break;
1453 // the reference Trapezoid can no longer be split
1454 aVerticalTraps.erase( aVerticalTraps.begin() );
1456 // recycle its sides that were not fully resolved
1457 HalfTrapezoid aHT;
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 );
1490 // set clipping
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() );
1500 return TRUE;
1503 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1505 bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin)
1507 // #i101491#
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)
1513 return false;
1515 const XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
1516 if( !rRenderPeer.AreTrapezoidsSupported() )
1517 return false;
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);
1560 if( !bDrawOk )
1561 break;
1564 // restore the original brush GC
1565 nBrushColor_ = aKeepBrushColor;
1566 return bDrawOk;
1569 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=