Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <config_graphite.h>
21 :
22 : #include <vector>
23 : #include <queue>
24 : #include <set>
25 :
26 : #include <prex.h>
27 : #include <X11/Xproto.h>
28 : #include <postx.h>
29 :
30 : #include "tools/debug.hxx"
31 :
32 : #include "basegfx/polygon/b2dpolygon.hxx"
33 : #include "basegfx/polygon/b2dpolypolygon.hxx"
34 : #include "basegfx/polygon/b2dpolypolygontools.hxx"
35 : #include "basegfx/polygon/b2dpolygontools.hxx"
36 : #include "basegfx/polygon/b2dpolygonclipper.hxx"
37 : #include "basegfx/polygon/b2dlinegeometry.hxx"
38 : #include "basegfx/matrix/b2dhommatrix.hxx"
39 : #include "basegfx/matrix/b2dhommatrixtools.hxx"
40 : #include "basegfx/polygon/b2dpolypolygoncutter.hxx"
41 : #include "basegfx/polygon/b2dtrapezoid.hxx"
42 :
43 : #include "vcl/jobdata.hxx"
44 :
45 : #include "unx/salunx.h"
46 : #include "unx/saldata.hxx"
47 : #include "unx/saldisp.hxx"
48 : #include "unx/salgdi.h"
49 : #include "unx/salframe.h"
50 : #include "unx/salvd.h"
51 : #include <unx/x11/xlimits.hxx>
52 :
53 : #include "generic/printergfx.hxx"
54 : #include "xrender_peer.hxx"
55 :
56 : #define STATIC_POINTS 64
57 :
58 : class SalPolyLine
59 : {
60 : XPoint Points_[STATIC_POINTS];
61 : XPoint *pFirst_;
62 : public:
63 : inline SalPolyLine( sal_uLong nPoints, const SalPoint *p );
64 : inline ~SalPolyLine();
65 0 : inline XPoint &operator [] ( sal_uLong n ) const
66 0 : { return pFirst_[n]; }
67 : };
68 :
69 0 : inline SalPolyLine::SalPolyLine( sal_uLong nPoints, const SalPoint *p )
70 0 : : pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
71 : {
72 0 : for( sal_uLong i = 0; i < nPoints; i++ )
73 : {
74 0 : pFirst_[i].x = (short)p[i].mnX;
75 0 : pFirst_[i].y = (short)p[i].mnY;
76 : }
77 0 : pFirst_[nPoints] = pFirst_[0]; // close polyline
78 0 : }
79 :
80 0 : inline SalPolyLine::~SalPolyLine()
81 0 : { if( pFirst_ != Points_ ) delete [] pFirst_; }
82 :
83 : #undef STATIC_POINTS
84 :
85 0 : X11SalGraphics::X11SalGraphics()
86 0 : : m_nXScreen( 0 )
87 : {
88 0 : m_pFrame = NULL;
89 0 : m_pVDev = NULL;
90 0 : m_pColormap = NULL;
91 0 : m_pDeleteColormap = NULL;
92 0 : hDrawable_ = None;
93 0 : m_aXRenderPicture = 0;
94 0 : m_pXRenderFormat = NULL;
95 :
96 0 : mpClipRegion = NULL;
97 0 : pPaintRegion_ = NULL;
98 :
99 0 : pPenGC_ = NULL;
100 0 : nPenPixel_ = 0;
101 0 : nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
102 :
103 0 : pFontGC_ = NULL;
104 0 : for( int i = 0; i < MAX_FALLBACK; ++i )
105 0 : mpServerFont[i] = NULL;
106 :
107 0 : nTextPixel_ = 0;
108 0 : nTextColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
109 :
110 : #if ENABLE_GRAPHITE
111 : // check if graphite fonts have been disabled
112 0 : static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" );
113 0 : bDisableGraphite_ = pDisableGraphiteStr ? (pDisableGraphiteStr[0]!='0') : false;
114 : #endif
115 :
116 0 : pBrushGC_ = NULL;
117 0 : nBrushPixel_ = 0;
118 0 : nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
119 0 : hBrush_ = None;
120 :
121 0 : pMonoGC_ = NULL;
122 0 : pCopyGC_ = NULL;
123 0 : pMaskGC_ = NULL;
124 0 : pInvertGC_ = NULL;
125 0 : pInvert50GC_ = NULL;
126 0 : pStippleGC_ = NULL;
127 0 : pTrackingGC_ = NULL;
128 :
129 0 : bWindow_ = false;
130 0 : bPrinter_ = false;
131 0 : bVirDev_ = false;
132 0 : bPenGC_ = false;
133 0 : bFontGC_ = false;
134 0 : bBrushGC_ = false;
135 0 : bMonoGC_ = false;
136 0 : bCopyGC_ = false;
137 0 : bInvertGC_ = false;
138 0 : bInvert50GC_ = false;
139 0 : bStippleGC_ = false;
140 0 : bTrackingGC_ = false;
141 0 : bXORMode_ = false;
142 0 : bDitherBrush_ = false;
143 0 : }
144 :
145 0 : X11SalGraphics::~X11SalGraphics()
146 : {
147 0 : ReleaseFonts();
148 0 : freeResources();
149 0 : }
150 :
151 0 : void X11SalGraphics::freeResources()
152 : {
153 0 : Display *pDisplay = GetXDisplay();
154 :
155 : DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" );
156 0 : if( mpClipRegion ) XDestroyRegion( mpClipRegion ), mpClipRegion = None;
157 :
158 0 : if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None;
159 0 : if( pPenGC_ ) XFreeGC( pDisplay, pPenGC_ ), pPenGC_ = None;
160 0 : if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None;
161 0 : if( pBrushGC_ ) XFreeGC( pDisplay, pBrushGC_ ), pBrushGC_ = None;
162 0 : if( pMonoGC_ ) XFreeGC( pDisplay, pMonoGC_ ), pMonoGC_ = None;
163 0 : if( pCopyGC_ ) XFreeGC( pDisplay, pCopyGC_ ), pCopyGC_ = None;
164 0 : if( pMaskGC_ ) XFreeGC( pDisplay, pMaskGC_ ), pMaskGC_ = None;
165 0 : if( pInvertGC_ ) XFreeGC( pDisplay, pInvertGC_ ), pInvertGC_ = None;
166 0 : if( pInvert50GC_ ) XFreeGC( pDisplay, pInvert50GC_ ), pInvert50GC_ = None;
167 0 : if( pStippleGC_ ) XFreeGC( pDisplay, pStippleGC_ ), pStippleGC_ = None;
168 0 : if( pTrackingGC_ ) XFreeGC( pDisplay, pTrackingGC_ ), pTrackingGC_ = None;
169 0 : if( m_pDeleteColormap )
170 0 : delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL;
171 :
172 0 : if( m_aXRenderPicture )
173 0 : XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture ), m_aXRenderPicture = 0;
174 :
175 0 : bPenGC_ = bFontGC_ = bBrushGC_ = bMonoGC_ = bCopyGC_ = bInvertGC_ = bInvert50GC_ = bStippleGC_ = bTrackingGC_ = false;
176 0 : }
177 :
178 0 : void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen )
179 : {
180 : // shortcut if nothing changed
181 0 : if( hDrawable_ == aDrawable )
182 0 : return;
183 :
184 : // free screen specific resources if needed
185 0 : if( nXScreen != m_nXScreen )
186 : {
187 0 : freeResources();
188 0 : m_pColormap = &GetGenericData()->GetSalDisplay()->GetColormap( nXScreen );
189 0 : m_nXScreen = nXScreen;
190 : }
191 :
192 0 : hDrawable_ = aDrawable;
193 0 : SetXRenderFormat( NULL );
194 0 : if( m_aXRenderPicture )
195 : {
196 0 : XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
197 0 : m_aXRenderPicture = 0;
198 : }
199 :
200 0 : if( hDrawable_ )
201 : {
202 0 : nPenPixel_ = GetPixel( nPenColor_ );
203 0 : nTextPixel_ = GetPixel( nTextColor_ );
204 0 : nBrushPixel_ = GetPixel( nBrushColor_ );
205 : }
206 : }
207 :
208 0 : void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
209 : SalX11Screen nXScreen )
210 : {
211 0 : m_pColormap = &GetGenericData()->GetSalDisplay()->GetColormap(nXScreen);
212 0 : m_nXScreen = nXScreen;
213 0 : SetDrawable( aTarget, nXScreen );
214 :
215 0 : bWindow_ = true;
216 0 : m_pFrame = pFrame;
217 0 : m_pVDev = NULL;
218 0 : }
219 :
220 0 : void X11SalGraphics::DeInit()
221 : {
222 0 : SetDrawable( None, m_nXScreen );
223 0 : }
224 :
225 0 : void X11SalGraphics::SetClipRegion( GC pGC, XLIB_Region pXReg ) const
226 : {
227 0 : Display *pDisplay = GetXDisplay();
228 :
229 0 : int n = 0;
230 : XLIB_Region Regions[3];
231 :
232 0 : if( mpClipRegion )
233 0 : Regions[n++] = mpClipRegion;
234 :
235 0 : if( pXReg && !XEmptyRegion( pXReg ) )
236 0 : Regions[n++] = pXReg;
237 :
238 0 : if( 0 == n )
239 0 : XSetClipMask( pDisplay, pGC, None );
240 0 : else if( 1 == n )
241 0 : XSetRegion( pDisplay, pGC, Regions[0] );
242 : else
243 : {
244 0 : XLIB_Region pTmpRegion = XCreateRegion();
245 0 : XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
246 :
247 0 : XSetRegion( pDisplay, pGC, pTmpRegion );
248 0 : XDestroyRegion( pTmpRegion );
249 : }
250 0 : }
251 :
252 0 : GC X11SalGraphics::SelectPen()
253 : {
254 0 : Display *pDisplay = GetXDisplay();
255 :
256 0 : if( !pPenGC_ )
257 : {
258 : XGCValues values;
259 0 : values.subwindow_mode = ClipByChildren;
260 0 : values.fill_rule = EvenOddRule; // Pict import/ Gradient
261 0 : values.graphics_exposures = False;
262 :
263 : pPenGC_ = XCreateGC( pDisplay, hDrawable_,
264 : GCSubwindowMode | GCFillRule | GCGraphicsExposures,
265 0 : &values );
266 : }
267 :
268 0 : if( !bPenGC_ )
269 : {
270 0 : if( nPenColor_ != SALCOLOR_NONE )
271 0 : XSetForeground( pDisplay, pPenGC_, nPenPixel_ );
272 0 : XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy );
273 0 : SetClipRegion( pPenGC_ );
274 0 : bPenGC_ = true;
275 : }
276 :
277 0 : return pPenGC_;
278 : }
279 :
280 0 : GC X11SalGraphics::SelectBrush()
281 : {
282 0 : Display *pDisplay = GetXDisplay();
283 :
284 : DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" );
285 :
286 0 : if( !pBrushGC_ )
287 : {
288 : XGCValues values;
289 0 : values.subwindow_mode = ClipByChildren;
290 0 : values.fill_rule = EvenOddRule; // Pict import/ Gradient
291 0 : values.graphics_exposures = False;
292 :
293 : pBrushGC_ = XCreateGC( pDisplay, hDrawable_,
294 : GCSubwindowMode | GCFillRule | GCGraphicsExposures,
295 0 : &values );
296 : }
297 :
298 0 : if( !bBrushGC_ )
299 : {
300 0 : if( !bDitherBrush_ )
301 : {
302 0 : XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
303 0 : XSetForeground( pDisplay, pBrushGC_, nBrushPixel_ );
304 0 : if( bPrinter_ )
305 0 : XSetTile( pDisplay, pBrushGC_, None );
306 : }
307 : else
308 : {
309 : // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't always reflect
310 : // changes of the tile. PROPERTY_BUG_Tile doesn't fix this !
311 0 : if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile)
312 0 : XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
313 :
314 0 : XSetFillStyle ( pDisplay, pBrushGC_, FillTiled );
315 0 : XSetTile ( pDisplay, pBrushGC_, hBrush_ );
316 : }
317 0 : XSetFunction ( pDisplay, pBrushGC_, bXORMode_ ? GXxor : GXcopy );
318 0 : SetClipRegion( pBrushGC_ );
319 :
320 0 : bBrushGC_ = true;
321 : }
322 :
323 0 : return pBrushGC_;
324 : }
325 :
326 0 : GC X11SalGraphics::GetTrackingGC()
327 : {
328 0 : const char dash_list[2] = {2, 2};
329 :
330 0 : if( !pTrackingGC_ )
331 : {
332 : XGCValues values;
333 :
334 0 : values.graphics_exposures = False;
335 0 : values.foreground = m_pColormap->GetBlackPixel()
336 0 : ^ m_pColormap->GetWhitePixel();
337 0 : values.function = GXxor;
338 0 : values.line_width = 1;
339 0 : values.line_style = LineOnOffDash;
340 :
341 : pTrackingGC_ = XCreateGC( GetXDisplay(), GetDrawable(),
342 : GCGraphicsExposures | GCForeground | GCFunction
343 : | GCLineWidth | GCLineStyle,
344 0 : &values );
345 0 : XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 );
346 : }
347 :
348 0 : if( !bTrackingGC_ )
349 : {
350 0 : SetClipRegion( pTrackingGC_ );
351 0 : bTrackingGC_ = true;
352 : }
353 :
354 0 : return pTrackingGC_;
355 : }
356 :
357 0 : void X11SalGraphics::DrawLines( sal_uLong nPoints,
358 : const SalPolyLine &rPoints,
359 : GC pGC,
360 : bool bClose
361 : )
362 : {
363 : // calculate how many lines XWindow can draw in one go
364 0 : sal_uLong nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
365 0 : / sizeof(xPoint);
366 0 : if( nMaxLines > nPoints ) nMaxLines = nPoints;
367 :
368 : // print all lines that XWindows can draw
369 : sal_uLong n;
370 0 : for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
371 : XDrawLines( GetXDisplay(),
372 : GetDrawable(),
373 : pGC,
374 0 : &rPoints[n],
375 : nMaxLines,
376 0 : CoordModeOrigin );
377 :
378 0 : if( n < nPoints )
379 : XDrawLines( GetXDisplay(),
380 : GetDrawable(),
381 : pGC,
382 0 : &rPoints[n],
383 0 : nPoints - n,
384 0 : CoordModeOrigin );
385 0 : if( bClose )
386 : {
387 0 : if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y )
388 0 : drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y );
389 : }
390 0 : }
391 :
392 : // Calculate a dither-pixmap and make a brush of it
393 : #define P_DELTA 51
394 : #define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
395 :
396 0 : bool X11SalGraphics::GetDitherPixmap( SalColor nSalColor )
397 : {
398 : static const short nOrdDither8Bit[ 8 ][ 8 ] =
399 : {
400 : { 0, 38, 9, 48, 2, 40, 12, 50},
401 : {25, 12, 35, 22, 28, 15, 37, 24},
402 : { 6, 44, 3, 41, 8, 47, 5, 44},
403 : {32, 19, 28, 16, 34, 21, 31, 18},
404 : { 1, 40, 11, 49, 0, 39, 10, 48},
405 : {27, 14, 36, 24, 26, 13, 36, 23},
406 : { 8, 46, 4, 43, 7, 45, 4, 42},
407 : {33, 20, 30, 17, 32, 20, 29, 16}
408 : };
409 :
410 : // test for correct depth (8bit)
411 0 : if( GetColormap().GetVisual().GetDepth() != 8 )
412 0 : return false;
413 :
414 : char pBits[64];
415 0 : char *pBitsPtr = pBits;
416 :
417 : // Set the pallette-entries for the dithering tile
418 0 : sal_uInt8 nSalColorRed = SALCOLOR_RED ( nSalColor );
419 0 : sal_uInt8 nSalColorGreen = SALCOLOR_GREEN ( nSalColor );
420 0 : sal_uInt8 nSalColorBlue = SALCOLOR_BLUE ( nSalColor );
421 :
422 0 : for( int nY = 0; nY < 8; nY++ )
423 : {
424 0 : for( int nX = 0; nX < 8; nX++ )
425 : {
426 0 : short nMagic = nOrdDither8Bit[nY][nX];
427 0 : sal_uInt8 nR = P_DELTA * DMAP( nSalColorRed, nMagic );
428 0 : sal_uInt8 nG = P_DELTA * DMAP( nSalColorGreen, nMagic );
429 0 : sal_uInt8 nB = P_DELTA * DMAP( nSalColorBlue, nMagic );
430 :
431 0 : *pBitsPtr++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR, nG, nB ) );
432 : }
433 : }
434 :
435 : // create the tile as ximage and an according pixmap -> caching
436 : XImage *pImage = XCreateImage( GetXDisplay(),
437 0 : GetColormap().GetXVisual(),
438 : 8,
439 : ZPixmap,
440 : 0, // offset
441 : pBits, // data
442 : 8, 8, // width & height
443 : 8, // bitmap_pad
444 0 : 0 ); // (default) bytes_per_line
445 :
446 0 : if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile )
447 : {
448 0 : if (hBrush_)
449 0 : XFreePixmap (GetXDisplay(), hBrush_);
450 0 : hBrush_ = limitXCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
451 : }
452 0 : else if( !hBrush_ )
453 0 : hBrush_ = limitXCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
454 :
455 : // put the ximage to the pixmap
456 : XPutImage( GetXDisplay(),
457 : hBrush_,
458 : GetDisplay()->GetCopyGC( m_nXScreen ),
459 : pImage,
460 : 0, 0, // Source
461 : 0, 0, // Destination
462 0 : 8, 8 ); // width & height
463 :
464 : // destroy image-frame but not palette-data
465 0 : pImage->data = NULL;
466 0 : XDestroyImage( pImage );
467 :
468 0 : return true;
469 : }
470 :
471 0 : void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
472 : {
473 0 : const SalDisplay *pDisplay = GetDisplay();
474 0 : if (!pDisplay)
475 : {
476 : OSL_TRACE("Null display");
477 0 : rDPIX = rDPIY = 96;
478 0 : return;
479 : }
480 :
481 0 : rDPIX = pDisplay->GetResolution().A();
482 0 : rDPIY = pDisplay->GetResolution().B();
483 :
484 0 : if ( rDPIY > 200 )
485 : {
486 0 : rDPIX = Divide( rDPIX * 200, rDPIY );
487 0 : rDPIY = 200;
488 : }
489 :
490 : // #i12705# equalize x- and y-resolution if they are close enough
491 0 : if( rDPIX != rDPIY )
492 : {
493 : // different x- and y- resolutions are usually artifacts of
494 : // a wrongly calculated screen size.
495 : #ifdef DEBUG
496 : printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
497 : rDPIX,rDPIY,rDPIY,rDPIY);
498 : #endif
499 0 : rDPIX = rDPIY; // y-resolution is more trustworthy
500 : }
501 : }
502 :
503 0 : sal_uInt16 X11SalGraphics::GetBitCount() const
504 : {
505 0 : return GetVisual().GetDepth();
506 : }
507 :
508 0 : long X11SalGraphics::GetGraphicsWidth() const
509 : {
510 0 : if( m_pFrame )
511 0 : return m_pFrame->maGeometry.nWidth;
512 0 : else if( m_pVDev )
513 0 : return m_pVDev->GetWidth();
514 : else
515 0 : return 0;
516 : }
517 :
518 0 : long X11SalGraphics::GetGraphicsHeight() const
519 : {
520 0 : if( m_pFrame )
521 0 : return m_pFrame->maGeometry.nHeight;
522 0 : else if( m_pVDev )
523 0 : return m_pVDev->GetHeight();
524 : else
525 0 : return 0;
526 : }
527 :
528 0 : void X11SalGraphics::ResetClipRegion()
529 : {
530 0 : if( mpClipRegion )
531 : {
532 0 : bPenGC_ = false;
533 0 : bFontGC_ = false;
534 0 : bBrushGC_ = false;
535 0 : bMonoGC_ = false;
536 0 : bCopyGC_ = false;
537 0 : bInvertGC_ = false;
538 0 : bInvert50GC_ = false;
539 0 : bStippleGC_ = false;
540 0 : bTrackingGC_ = false;
541 :
542 0 : XDestroyRegion( mpClipRegion );
543 0 : mpClipRegion = NULL;
544 : }
545 0 : }
546 :
547 0 : bool X11SalGraphics::setClipRegion( const Region& i_rClip )
548 : {
549 0 : if( mpClipRegion )
550 0 : XDestroyRegion( mpClipRegion );
551 0 : mpClipRegion = XCreateRegion();
552 :
553 0 : RectangleVector aRectangles;
554 0 : i_rClip.GetRegionRectangles(aRectangles);
555 :
556 0 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
557 : {
558 0 : const long nW(aRectIter->GetWidth());
559 :
560 0 : if(nW)
561 : {
562 0 : const long nH(aRectIter->GetHeight());
563 :
564 0 : if(nH)
565 : {
566 : XRectangle aRect;
567 :
568 0 : aRect.x = (short)aRectIter->Left();
569 0 : aRect.y = (short)aRectIter->Top();
570 0 : aRect.width = (unsigned short)nW;
571 0 : aRect.height = (unsigned short)nH;
572 0 : XUnionRectWithRegion(&aRect, mpClipRegion, mpClipRegion);
573 : }
574 : }
575 : }
576 :
577 : //ImplRegionInfo aInfo;
578 : //long nX, nY, nW, nH;
579 : //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
580 : //while( bRegionRect )
581 : //{
582 : // if ( nW && nH )
583 : // {
584 : // XRectangle aRect;
585 : // aRect.x = (short)nX;
586 : // aRect.y = (short)nY;
587 : // aRect.width = (unsigned short)nW;
588 : // aRect.height = (unsigned short)nH;
589 :
590 : // XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion );
591 : // }
592 : // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
593 : //}
594 :
595 : // done, invalidate GCs
596 0 : bPenGC_ = false;
597 0 : bFontGC_ = false;
598 0 : bBrushGC_ = false;
599 0 : bMonoGC_ = false;
600 0 : bCopyGC_ = false;
601 0 : bInvertGC_ = false;
602 0 : bInvert50GC_ = false;
603 0 : bStippleGC_ = false;
604 0 : bTrackingGC_ = false;
605 :
606 0 : if( XEmptyRegion( mpClipRegion ) )
607 : {
608 0 : XDestroyRegion( mpClipRegion );
609 0 : mpClipRegion= NULL;
610 : }
611 0 : return true;
612 : }
613 :
614 0 : void X11SalGraphics::SetLineColor()
615 : {
616 0 : if( nPenColor_ != SALCOLOR_NONE )
617 : {
618 0 : nPenColor_ = SALCOLOR_NONE;
619 0 : bPenGC_ = false;
620 : }
621 0 : }
622 :
623 0 : void X11SalGraphics::SetLineColor( SalColor nSalColor )
624 : {
625 0 : if( nPenColor_ != nSalColor )
626 : {
627 0 : nPenColor_ = nSalColor;
628 0 : nPenPixel_ = GetPixel( nSalColor );
629 0 : bPenGC_ = false;
630 : }
631 0 : }
632 :
633 0 : void X11SalGraphics::SetFillColor()
634 : {
635 0 : if( nBrushColor_ != SALCOLOR_NONE )
636 : {
637 0 : bDitherBrush_ = false;
638 0 : nBrushColor_ = SALCOLOR_NONE;
639 0 : bBrushGC_ = false;
640 : }
641 0 : }
642 :
643 0 : void X11SalGraphics::SetFillColor( SalColor nSalColor )
644 : {
645 0 : if( nBrushColor_ != nSalColor )
646 : {
647 0 : bDitherBrush_ = false;
648 0 : nBrushColor_ = nSalColor;
649 0 : nBrushPixel_ = GetPixel( nSalColor );
650 0 : if( TrueColor != GetColormap().GetVisual().GetClass()
651 0 : && GetColormap().GetColor( nBrushPixel_ ) != nBrushColor_
652 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black
653 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue
654 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green
655 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan
656 0 : && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red
657 0 : && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta
658 0 : && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown
659 0 : && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray
660 0 : && nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray
661 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue
662 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green
663 0 : && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan
664 0 : && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red
665 0 : && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta
666 0 : && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown
667 0 : && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) )
668 0 : bDitherBrush_ = GetDitherPixmap(nSalColor);
669 0 : bBrushGC_ = false;
670 : }
671 0 : }
672 :
673 0 : void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
674 : {
675 0 : switch( nROPColor )
676 : {
677 : case SAL_ROP_0 : // 0
678 0 : nPenPixel_ = (Pixel)0;
679 0 : break;
680 : case SAL_ROP_1 : // 1
681 0 : nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
682 0 : break;
683 : case SAL_ROP_INVERT : // 2
684 0 : nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
685 0 : break;
686 : }
687 0 : nPenColor_ = GetColormap().GetColor( nPenPixel_ );
688 0 : bPenGC_ = false;
689 0 : }
690 :
691 0 : void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
692 : {
693 0 : switch( nROPColor )
694 : {
695 : case SAL_ROP_0 : // 0
696 0 : nBrushPixel_ = (Pixel)0;
697 0 : break;
698 : case SAL_ROP_1 : // 1
699 0 : nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
700 0 : break;
701 : case SAL_ROP_INVERT : // 2
702 0 : nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
703 0 : break;
704 : }
705 0 : bDitherBrush_ = false;
706 0 : nBrushColor_ = GetColormap().GetColor( nBrushPixel_ );
707 0 : bBrushGC_ = false;
708 0 : }
709 :
710 0 : void X11SalGraphics::SetXORMode( bool bSet, bool )
711 : {
712 0 : if( !bXORMode_ == bSet )
713 : {
714 0 : bXORMode_ = bSet;
715 0 : bPenGC_ = false;
716 0 : bFontGC_ = false;
717 0 : bBrushGC_ = false;
718 0 : bMonoGC_ = false;
719 0 : bCopyGC_ = false;
720 0 : bInvertGC_ = false;
721 0 : bInvert50GC_ = false;
722 0 : bStippleGC_ = false;
723 0 : bTrackingGC_ = false;
724 : }
725 0 : }
726 :
727 0 : void X11SalGraphics::drawPixel( long nX, long nY )
728 : {
729 0 : if( nPenColor_ != SALCOLOR_NONE )
730 0 : XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX, nY );
731 0 : }
732 :
733 0 : void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
734 : {
735 0 : if( nSalColor != SALCOLOR_NONE )
736 : {
737 0 : Display *pDisplay = GetXDisplay();
738 :
739 0 : if( (nPenColor_ == SALCOLOR_NONE) && !bPenGC_ )
740 : {
741 0 : SetLineColor( nSalColor );
742 0 : XDrawPoint( pDisplay, GetDrawable(), SelectPen(), nX, nY );
743 0 : nPenColor_ = SALCOLOR_NONE;
744 0 : bPenGC_ = False;
745 : }
746 : else
747 : {
748 0 : GC pGC = SelectPen();
749 :
750 0 : if( nSalColor != nPenColor_ )
751 0 : XSetForeground( pDisplay, pGC, GetPixel( nSalColor ) );
752 :
753 0 : XDrawPoint( pDisplay, GetDrawable(), pGC, nX, nY );
754 :
755 0 : if( nSalColor != nPenColor_ )
756 0 : XSetForeground( pDisplay, pGC, nPenPixel_ );
757 : }
758 : }
759 0 : }
760 :
761 0 : void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
762 : {
763 0 : if( nPenColor_ != SALCOLOR_NONE )
764 : {
765 0 : if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine )
766 : {
767 0 : GC aGC = SelectPen();
768 0 : XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX1, (int)nY1);
769 0 : XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX2, (int)nY2);
770 0 : XDrawLine (GetXDisplay(), GetDrawable(), aGC, nX1, nY1, nX2, nY2 );
771 : }
772 : else
773 : XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(),
774 0 : nX1, nY1, nX2, nY2 );
775 : }
776 0 : }
777 :
778 0 : void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
779 : {
780 0 : if( nBrushColor_ != SALCOLOR_NONE )
781 : {
782 : XFillRectangle( GetXDisplay(),
783 : GetDrawable(),
784 : SelectBrush(),
785 0 : nX, nY, nDX, nDY );
786 : }
787 : // description DrawRect is wrong; thus -1
788 0 : if( nPenColor_ != SALCOLOR_NONE )
789 : XDrawRectangle( GetXDisplay(),
790 : GetDrawable(),
791 : SelectPen(),
792 0 : nX, nY, nDX-1, nDY-1 );
793 0 : }
794 :
795 0 : void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry )
796 : {
797 0 : drawPolyLine( nPoints, pPtAry, false );
798 0 : }
799 :
800 0 : void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry, bool bClose )
801 : {
802 0 : if( nPenColor_ != SALCOLOR_NONE )
803 : {
804 0 : SalPolyLine Points( nPoints, pPtAry );
805 :
806 0 : DrawLines( nPoints, Points, SelectPen(), bClose );
807 : }
808 0 : }
809 :
810 0 : void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
811 : {
812 0 : if( nPoints == 0 )
813 0 : return;
814 :
815 0 : if( nPoints < 3 )
816 : {
817 0 : if( !bXORMode_ )
818 : {
819 0 : if( 1 == nPoints )
820 0 : drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
821 : else
822 : drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
823 0 : pPtAry[1].mnX, pPtAry[1].mnY );
824 : }
825 0 : return;
826 : }
827 :
828 0 : SalPolyLine Points( nPoints, pPtAry );
829 :
830 0 : nPoints++;
831 :
832 : /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
833 : * do not draw the visible part of a polygon
834 : * if it overlaps to the left of screen 0,y.
835 : * This happens to be the case in the gradient drawn in the
836 : * menubar background. workaround for the special case of
837 : * of a rectangle overlapping to the left.
838 : */
839 0 : if( nPoints == 5 &&
840 0 : Points[ 0 ].x == Points[ 1 ].x &&
841 0 : Points[ 1 ].y == Points[ 2 ].y &&
842 0 : Points[ 2 ].x == Points[ 3 ].x &&
843 0 : Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y
844 : )
845 : {
846 0 : bool bLeft = false;
847 0 : bool bRight = false;
848 0 : for(unsigned int i = 0; i < nPoints; i++ )
849 : {
850 0 : if( Points[i].x < 0 )
851 0 : bLeft = true;
852 : else
853 0 : bRight= true;
854 : }
855 0 : if( bLeft && ! bRight )
856 0 : return;
857 0 : if( bLeft && bRight )
858 : {
859 0 : for( unsigned int i = 0; i < nPoints; i++ )
860 0 : if( Points[i].x < 0 )
861 0 : Points[i].x = 0;
862 : }
863 : }
864 :
865 0 : if( nBrushColor_ != SALCOLOR_NONE )
866 : XFillPolygon( GetXDisplay(),
867 : GetDrawable(),
868 : SelectBrush(),
869 0 : &Points[0], nPoints,
870 0 : Complex, CoordModeOrigin );
871 :
872 0 : if( nPenColor_ != SALCOLOR_NONE )
873 0 : DrawLines( nPoints, Points, SelectPen(), true );
874 : }
875 :
876 0 : void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
877 : const sal_uInt32 *pPoints,
878 : PCONSTSALPOINT *pPtAry )
879 : {
880 0 : if( nBrushColor_ != SALCOLOR_NONE )
881 : {
882 : sal_uInt32 i, n;
883 0 : XLIB_Region pXRegA = NULL;
884 :
885 0 : for( i = 0; i < nPoly; i++ ) {
886 0 : n = pPoints[i];
887 0 : SalPolyLine Points( n, pPtAry[i] );
888 0 : if( n > 2 )
889 : {
890 0 : XLIB_Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
891 0 : if( !pXRegA )
892 0 : pXRegA = pXRegB;
893 : else
894 : {
895 0 : XXorRegion( pXRegA, pXRegB, pXRegA );
896 0 : XDestroyRegion( pXRegB );
897 : }
898 : }
899 0 : }
900 :
901 0 : if( pXRegA )
902 : {
903 : XRectangle aXRect;
904 0 : XClipBox( pXRegA, &aXRect );
905 :
906 0 : GC pGC = SelectBrush();
907 0 : SetClipRegion( pGC, pXRegA ); // ??? twice
908 0 : XDestroyRegion( pXRegA );
909 0 : bBrushGC_ = false;
910 :
911 : XFillRectangle( GetXDisplay(),
912 : GetDrawable(),
913 : pGC,
914 0 : aXRect.x, aXRect.y, aXRect.width, aXRect.height );
915 : }
916 : }
917 :
918 0 : if( nPenColor_ != SALCOLOR_NONE )
919 0 : for( sal_uInt32 i = 0; i < nPoly; i++ )
920 0 : drawPolyLine( pPoints[i], pPtAry[i], true );
921 0 : }
922 :
923 0 : bool X11SalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const sal_uInt8* )
924 : {
925 0 : return false;
926 : }
927 :
928 0 : bool X11SalGraphics::drawPolygonBezier( sal_uInt32, const SalPoint*, const sal_uInt8* )
929 : {
930 0 : return false;
931 : }
932 :
933 0 : bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
934 : const SalPoint* const*, const sal_uInt8* const* )
935 : {
936 0 : return false;
937 : }
938 :
939 0 : void X11SalGraphics::invert( sal_uInt32 nPoints,
940 : const SalPoint* pPtAry,
941 : SalInvert nFlags )
942 : {
943 0 : SalPolyLine Points ( nPoints, pPtAry );
944 :
945 : GC pGC;
946 0 : if( SAL_INVERT_50 & nFlags )
947 0 : pGC = GetInvert50GC();
948 : else
949 0 : if ( SAL_INVERT_TRACKFRAME & nFlags )
950 0 : pGC = GetTrackingGC();
951 : else
952 0 : pGC = GetInvertGC();
953 :
954 0 : if( SAL_INVERT_TRACKFRAME & nFlags )
955 0 : DrawLines ( nPoints, Points, pGC, true );
956 : else
957 : XFillPolygon( GetXDisplay(),
958 : GetDrawable(),
959 : pGC,
960 0 : &Points[0], nPoints,
961 0 : Complex, CoordModeOrigin );
962 0 : }
963 :
964 0 : bool X11SalGraphics::drawEPS( long,long,long,long,void*,sal_uLong )
965 : {
966 0 : return false;
967 : }
968 :
969 0 : XID X11SalGraphics::GetXRenderPicture()
970 : {
971 0 : XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
972 :
973 0 : if( !m_aXRenderPicture )
974 : {
975 : // check xrender support for matching visual
976 0 : XRenderPictFormat* pXRenderFormat = GetXRenderFormat();
977 0 : if( !pXRenderFormat )
978 0 : return 0;
979 : // get the matching xrender target for drawable
980 0 : m_aXRenderPicture = rRenderPeer.CreatePicture( hDrawable_, pXRenderFormat, 0, NULL );
981 : }
982 :
983 : {
984 : // reset clip region
985 : // TODO: avoid clip reset if already done
986 : XRenderPictureAttributes aAttr;
987 0 : aAttr.clip_mask = None;
988 0 : rRenderPeer.ChangePicture( m_aXRenderPicture, CPClipMask, &aAttr );
989 : }
990 :
991 0 : return m_aXRenderPicture;
992 : }
993 :
994 0 : XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const
995 : {
996 0 : if( m_pXRenderFormat == NULL )
997 0 : m_pXRenderFormat = XRenderPeer::GetInstance().FindVisualFormat( GetVisual().visual );
998 0 : return m_pXRenderFormat;
999 : }
1000 :
1001 0 : SystemGraphicsData X11SalGraphics::GetGraphicsData() const
1002 : {
1003 0 : SystemGraphicsData aRes;
1004 :
1005 0 : aRes.nSize = sizeof(aRes);
1006 0 : aRes.pDisplay = GetXDisplay();
1007 0 : aRes.hDrawable = hDrawable_;
1008 0 : aRes.pVisual = GetVisual().visual;
1009 0 : aRes.nScreen = m_nXScreen.getXScreen();
1010 0 : aRes.nDepth = GetBitCount();
1011 0 : aRes.aColormap = GetColormap().GetXColormap();
1012 0 : aRes.pXRenderFormat = m_pXRenderFormat;
1013 0 : return aRes;
1014 : }
1015 :
1016 : // draw a poly-polygon
1017 0 : bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
1018 : {
1019 : // nothing to do for empty polypolygons
1020 0 : const int nOrigPolyCount = rOrigPolyPoly.count();
1021 0 : if( nOrigPolyCount <= 0 )
1022 0 : return true;
1023 :
1024 : // nothing to do if everything is transparent
1025 0 : if( (nBrushColor_ == SALCOLOR_NONE)
1026 0 : && (nPenColor_ == SALCOLOR_NONE) )
1027 0 : return true;
1028 :
1029 : // cannot handle pencolor!=brushcolor yet
1030 0 : if( (nPenColor_ != SALCOLOR_NONE)
1031 0 : && (nPenColor_ != nBrushColor_) )
1032 0 : return false;
1033 :
1034 : // TODO: remove the env-variable when no longer needed
1035 0 : static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
1036 0 : if( pRenderEnv )
1037 0 : return false;
1038 :
1039 : // snap to raster if requested
1040 0 : basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly;
1041 0 : const bool bSnapToRaster = !getAntiAliasB2DDraw();
1042 0 : if( bSnapToRaster )
1043 0 : aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly );
1044 :
1045 : // don't bother with polygons outside of visible area
1046 0 : const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
1047 0 : aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false );
1048 0 : if( !aPolyPoly.count() )
1049 0 : return true;
1050 :
1051 : // tesselate the polypolygon into trapezoids
1052 0 : basegfx::B2DTrapezoidVector aB2DTrapVector;
1053 0 : basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly );
1054 0 : const int nTrapCount = aB2DTrapVector.size();
1055 0 : if( !nTrapCount )
1056 0 : return true;
1057 0 : const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
1058 0 : return bDrawn;
1059 : }
1060 :
1061 0 : bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency )
1062 : {
1063 0 : if( nTrapCount <= 0 )
1064 0 : return true;
1065 :
1066 0 : Picture aDstPic = GetXRenderPicture();
1067 : // check xrender support for this drawable
1068 0 : if( !aDstPic )
1069 0 : return false;
1070 :
1071 : // convert the B2DTrapezoids into XRender-Trapezoids
1072 : typedef std::vector<XTrapezoid> TrapezoidVector;
1073 0 : TrapezoidVector aTrapVector( nTrapCount );
1074 0 : const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps;
1075 0 : for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i )
1076 : {
1077 0 : XTrapezoid& rTrap = aTrapVector[ i ] ;
1078 :
1079 : // set y-coordinates
1080 0 : const double fY1 = pB2DTrap->getTopY();
1081 0 : rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 );
1082 0 : const double fY2 = pB2DTrap->getBottomY();
1083 0 : rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 );
1084 :
1085 : // set x-coordinates
1086 0 : const double fXL1 = pB2DTrap->getTopXLeft();
1087 0 : rTrap.left.p1.x = XDoubleToFixed( fXL1 );
1088 0 : const double fXR1 = pB2DTrap->getTopXRight();
1089 0 : rTrap.right.p1.x = XDoubleToFixed( fXR1 );
1090 0 : const double fXL2 = pB2DTrap->getBottomXLeft();
1091 0 : rTrap.left.p2.x = XDoubleToFixed( fXL2 );
1092 0 : const double fXR2 = pB2DTrap->getBottomXRight();
1093 0 : rTrap.right.p2.x = XDoubleToFixed( fXR2 );
1094 : }
1095 :
1096 : // get xrender Picture for polygon foreground
1097 : // TODO: cache it like the target picture which uses GetXRenderPicture()
1098 0 : XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
1099 0 : SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nXScreen )[ 32 ];
1100 0 : if( !rEntry.m_aPicture )
1101 : {
1102 0 : Display* pXDisplay = GetXDisplay();
1103 :
1104 0 : rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, hDrawable_, 1, 1, 32 );
1105 : XRenderPictureAttributes aAttr;
1106 0 : aAttr.repeat = int(true);
1107 :
1108 0 : XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
1109 0 : rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
1110 : }
1111 :
1112 : // set polygon foreground color and opacity
1113 0 : XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency );
1114 0 : rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
1115 :
1116 : // set clipping
1117 : // TODO: move into GetXRenderPicture?
1118 0 : if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
1119 0 : rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
1120 :
1121 : // render the trapezoids
1122 0 : const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
1123 : rRenderPeer.CompositeTrapezoids( PictOpOver,
1124 0 : rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() );
1125 :
1126 0 : return true;
1127 : }
1128 :
1129 0 : bool X11SalGraphics::drawPolyLine(
1130 : const ::basegfx::B2DPolygon& rPolygon,
1131 : double fTransparency,
1132 : const ::basegfx::B2DVector& rLineWidth,
1133 : basegfx::B2DLineJoin eLineJoin,
1134 : com::sun::star::drawing::LineCap eLineCap)
1135 : {
1136 0 : const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
1137 :
1138 : // #i101491#
1139 0 : if( !bIsHairline && (rPolygon.count() > 1000) )
1140 : {
1141 : // the used basegfx::tools::createAreaGeometry is simply too
1142 : // expensive with very big polygons; fallback to caller (who
1143 : // should use ImplLineConverter normally)
1144 : // AW: ImplLineConverter had to be removed since it does not even
1145 : // know LineJoins, so the fallback will now prepare the line geometry
1146 : // the same way.
1147 0 : return false;
1148 : }
1149 :
1150 : // temporarily adjust brush color to pen color
1151 : // since the line is drawn as an area-polygon
1152 0 : const SalColor aKeepBrushColor = nBrushColor_;
1153 0 : nBrushColor_ = nPenColor_;
1154 :
1155 : // #i11575#desc5#b adjust B2D tesselation result to raster positions
1156 0 : basegfx::B2DPolygon aPolygon = rPolygon;
1157 0 : const double fHalfWidth = 0.5 * rLineWidth.getX();
1158 :
1159 : // #i122456# This is probably thought to happen to align hairlines to pixel positions, so
1160 : // it should be a 0.5 translation, not more. It will definitely go wrong with fat lines
1161 0 : aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5) );
1162 :
1163 : // shortcut for hairline drawing to improve performance
1164 0 : bool bDrawnOk = true;
1165 0 : if( bIsHairline )
1166 : {
1167 : // hairlines can benefit from a simplified tesselation
1168 : // e.g. for hairlines the linejoin style can be ignored
1169 0 : basegfx::B2DTrapezoidVector aB2DTrapVector;
1170 0 : basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() );
1171 :
1172 : // draw tesselation result
1173 0 : const int nTrapCount = aB2DTrapVector.size();
1174 0 : if( nTrapCount > 0 )
1175 0 : bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
1176 :
1177 : // restore the original brush GC
1178 0 : nBrushColor_ = aKeepBrushColor;
1179 0 : return bDrawnOk;
1180 : }
1181 :
1182 : // get the area polygon for the line polygon
1183 0 : if( (rLineWidth.getX() != rLineWidth.getY())
1184 0 : && !basegfx::fTools::equalZero( rLineWidth.getY() ) )
1185 : {
1186 : // prepare for createAreaGeometry() with anisotropic linewidth
1187 0 : aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY()));
1188 : }
1189 :
1190 : // create the area-polygon for the line
1191 0 : const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) );
1192 :
1193 0 : if( (rLineWidth.getX() != rLineWidth.getY())
1194 0 : && !basegfx::fTools::equalZero( rLineWidth.getX() ) )
1195 : {
1196 : // postprocess createAreaGeometry() for anisotropic linewidth
1197 0 : aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX()));
1198 : }
1199 :
1200 : // draw each area polypolygon component individually
1201 : // to emulate the polypolygon winding rule "non-zero"
1202 0 : const int nPolyCount = aAreaPolyPoly.count();
1203 0 : for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
1204 : {
1205 0 : const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) );
1206 0 : bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency );
1207 0 : if( !bDrawnOk )
1208 0 : break;
1209 0 : }
1210 :
1211 : // restore the original brush GC
1212 0 : nBrushColor_ = aKeepBrushColor;
1213 0 : return bDrawnOk;
1214 0 : }
1215 :
1216 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|