1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/debug.hxx>
22 #include <tools/line.hxx>
23 #include <tools/poly.hxx>
25 #include <vcl/gradient.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/gdimtf.hxx>
28 #include <vcl/salbtype.hxx>
29 #include <vcl/hatch.hxx>
30 #include <vcl/window.hxx>
31 #include <vcl/virdev.hxx>
32 #include <vcl/outdev.hxx>
34 #include "pdfwriter_impl.hxx"
37 #include "salframe.hxx"
40 #include "outdata.hxx"
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <basegfx/polygon/b2dpolypolygon.hxx>
44 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #define HATCH_MAXPOINTS 1024
47 #define GRADIENT_DEFAULT_STEPCOUNT 0
49 extern "C" int SAL_CALL
ImplHatchCmpFnc( const void* p1
, const void* p2
)
51 const long nX1
= ( (Point
*) p1
)->X();
52 const long nX2
= ( (Point
*) p2
)->X();
53 const long nY1
= ( (Point
*) p1
)->Y();
54 const long nY2
= ( (Point
*) p2
)->Y();
56 return ( nX1
> nX2
? 1 : nX1
== nX2
? nY1
> nY2
? 1: nY1
== nY2
? 0 : -1 : -1 );
59 DBG_NAMEEX( OutputDevice
)
60 DBG_NAMEEX( Gradient
)
62 void OutputDevice::ImplDrawPolygon( const Polygon
& rPoly
, const PolyPolygon
* pClipPolyPoly
)
65 ImplDrawPolyPolygon( rPoly
, pClipPolyPoly
);
68 sal_uInt16 nPoints
= rPoly
.GetSize();
73 const SalPoint
* pPtAry
= (const SalPoint
*)rPoly
.GetConstPointAry();
74 mpGraphics
->DrawPolygon( nPoints
, pPtAry
, this );
78 void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon
& rPolyPoly
, const PolyPolygon
* pClipPolyPoly
)
80 PolyPolygon
* pPolyPoly
;
84 pPolyPoly
= new PolyPolygon
;
85 rPolyPoly
.GetIntersection( *pClipPolyPoly
, *pPolyPoly
);
88 pPolyPoly
= (PolyPolygon
*) &rPolyPoly
;
90 if( pPolyPoly
->Count() == 1 )
92 const Polygon rPoly
= pPolyPoly
->GetObject( 0 );
93 sal_uInt16 nSize
= rPoly
.GetSize();
97 const SalPoint
* pPtAry
= (const SalPoint
*)rPoly
.GetConstPointAry();
98 mpGraphics
->DrawPolygon( nSize
, pPtAry
, this );
101 else if( pPolyPoly
->Count() )
103 sal_uInt16 nCount
= pPolyPoly
->Count();
104 sal_uInt32
* pPointAry
= new sal_uInt32
[nCount
];
105 PCONSTSALPOINT
* pPointAryAry
= new PCONSTSALPOINT
[nCount
];
109 const Polygon
& rPoly
= pPolyPoly
->GetObject( i
);
110 sal_uInt16 nSize
= rPoly
.GetSize();
113 pPointAry
[i
] = nSize
;
114 pPointAryAry
[i
] = (PCONSTSALPOINT
)rPoly
.GetConstPointAry();
123 mpGraphics
->DrawPolygon( *pPointAry
, *pPointAryAry
, this );
125 mpGraphics
->DrawPolyPolygon( nCount
, pPointAry
, pPointAryAry
, this );
128 delete[] pPointAryAry
;
135 inline sal_uInt8
ImplGetGradientColorValue( long nValue
)
139 else if ( nValue
> 0xFF )
142 return (sal_uInt8
)nValue
;
145 void OutputDevice::ImplDrawLinearGradient( const Rectangle
& rRect
,
146 const Gradient
& rGradient
,
147 sal_Bool bMtf
, const PolyPolygon
* pClipPolyPoly
)
149 // rotiertes BoundRect ausrechnen
152 sal_uInt16 nAngle
= rGradient
.GetAngle() % 3600;
154 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
156 // Rand berechnen und Rechteck neu setzen
157 Rectangle aFullRect
= aRect
;
158 long nBorder
= (long)rGradient
.GetBorder() * aRect
.GetHeight() / 100;
160 // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
161 bool bLinear
= (rGradient
.GetStyle() == GradientStyle_LINEAR
);
164 aRect
.Top() += nBorder
;
166 // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
171 aRect
.Top() += nBorder
;
172 aRect
.Bottom() -= nBorder
;
175 // Top darf nicht groesser als Bottom sein
176 aRect
.Top() = std::min( aRect
.Top(), (long)(aRect
.Bottom() - 1) );
178 long nMinRect
= aRect
.GetHeight();
180 // Intensitaeten von Start- und Endfarbe ggf. aendern und
181 // Farbschrittweiten berechnen
183 Color aStartCol
= rGradient
.GetStartColor();
184 Color aEndCol
= rGradient
.GetEndColor();
185 long nStartRed
= aStartCol
.GetRed();
186 long nStartGreen
= aStartCol
.GetGreen();
187 long nStartBlue
= aStartCol
.GetBlue();
188 long nEndRed
= aEndCol
.GetRed();
189 long nEndGreen
= aEndCol
.GetGreen();
190 long nEndBlue
= aEndCol
.GetBlue();
191 nFactor
= rGradient
.GetStartIntensity();
192 nStartRed
= (nStartRed
* nFactor
) / 100;
193 nStartGreen
= (nStartGreen
* nFactor
) / 100;
194 nStartBlue
= (nStartBlue
* nFactor
) / 100;
195 nFactor
= rGradient
.GetEndIntensity();
196 nEndRed
= (nEndRed
* nFactor
) / 100;
197 nEndGreen
= (nEndGreen
* nFactor
) / 100;
198 nEndBlue
= (nEndBlue
* nFactor
) / 100;
199 long nRedSteps
= nEndRed
- nStartRed
;
200 long nGreenSteps
= nEndGreen
- nStartGreen
;
201 long nBlueSteps
= nEndBlue
- nStartBlue
;
202 long nStepCount
= rGradient
.GetSteps();
204 // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
213 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
218 if ( meOutDevType
!= OUTDEV_PRINTER
&& !bMtf
)
220 nInc
= (nMinRect
< 50) ? 2 : 4;
224 // #105998# Use display-equivalent step size calculation
225 nInc
= (nMinRect
< 800) ? 10 : 20;
228 nStepCount
= nMinRect
/ nInc
;
230 // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
231 long nSteps
= std::max( nStepCount
, 2L );
232 long nCalcSteps
= std::abs( nRedSteps
);
233 long nTempSteps
= std::abs( nGreenSteps
);
234 if ( nTempSteps
> nCalcSteps
)
235 nCalcSteps
= nTempSteps
;
236 nTempSteps
= std::abs( nBlueSteps
);
237 if ( nTempSteps
> nCalcSteps
)
238 nCalcSteps
= nTempSteps
;
239 if ( nCalcSteps
< nSteps
)
244 // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
245 if ( !bLinear
&& !(nSteps
& 1) )
248 // Berechnung ueber Double-Addition wegen Genauigkeit
249 double fScanLine
= aRect
.Top();
250 double fScanInc
= (double)aRect
.GetHeight() / (double)nSteps
;
252 // Startfarbe berechnen und setzen
260 // Um 1 erhoeht, um die Border innerhalb der Schleife
261 // zeichnen zu koennen
262 nSteps2
= nSteps
+ 1;
263 nRed
= (sal_uInt8
)nStartRed
;
264 nGreen
= (sal_uInt8
)nStartGreen
;
265 nBlue
= (sal_uInt8
)nStartBlue
;
269 // Um 2 erhoeht, um die Border innerhalb der Schleife
270 // zeichnen zu koennen
271 nSteps2
= nSteps
+ 2;
272 nRed
= (sal_uInt8
)nEndRed
;
273 nGreen
= (sal_uInt8
)nEndGreen
;
274 nBlue
= (sal_uInt8
)nEndBlue
;
275 nStepsHalf
= nSteps
>> 1;
279 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
281 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
283 // Startpolygon erzeugen (== Borderpolygon)
285 Polygon
aTempPoly( 2 );
286 Polygon
aTempPoly2( 2 );
287 /* n#710061 Use overlapping fills to avoid color
288 * leak via gaps in some pdf viewers
290 Point
aOverLap( 0, fScanInc
*.1 );
291 aPoly
[0] = aFullRect
.TopLeft();
292 aPoly
[1] = aFullRect
.TopRight();
293 aPoly
[2] = aRect
.TopRight();
294 aPoly
[3] = aRect
.TopLeft();
295 aPoly
.Rotate( aCenter
, nAngle
);
296 aTempPoly
[0] = aPoly
[3];
297 aTempPoly
[1] = aPoly
[2];
300 // Schleife, um rotierten Verlauf zu fuellen
301 for ( long i
= 0; i
< nSteps2
; i
++ )
303 // berechnetesPolygon ausgeben
305 mpMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
307 ImplDrawPolygon( aPoly
, pClipPolyPoly
);
309 // neues Polygon berechnen
310 aRect
.Top() = (long)(fScanLine
+= fScanInc
);
312 aPoly
[0] = aTempPoly
[0];
313 aPoly
[1] = aTempPoly
[1];
314 // unteren Rand komplett fuellen
317 aTempPoly
[0] = aFullRect
.BottomLeft();
318 aTempPoly
[1] = aFullRect
.BottomRight();
319 aTempPoly2
= aTempPoly
;
323 aTempPoly
[0] = aRect
.TopLeft();
324 aTempPoly
[1] = aRect
.TopRight();
325 aTempPoly2
[0]= aTempPoly
[0] + aOverLap
;
326 aTempPoly2
[1]= aTempPoly
[1] + aOverLap
;
328 aTempPoly2
.Rotate( aCenter
, nAngle
);
329 aTempPoly
.Rotate( aCenter
, nAngle
);
331 aPoly
[2] = aTempPoly2
[1];
332 aPoly
[3] = aTempPoly2
[0];
334 // Farbintensitaeten aendern...
338 nRed
= ImplGetGradientColorValue( nStartRed
+((nRedSteps
*i
)/nSteps2
) );
339 nGreen
= ImplGetGradientColorValue( nStartGreen
+((nGreenSteps
*i
)/nSteps2
) );
340 nBlue
= ImplGetGradientColorValue( nStartBlue
+((nBlueSteps
*i
)/nSteps2
) );
345 // fuer axiale FV muss die letzte Farbe der ersten
347 // #107350# Setting end color one step earlier, as the
348 // last time we get here, we drop out of the loop later
352 nRed
= (sal_uInt8
)nEndRed
;
353 nGreen
= (sal_uInt8
)nEndGreen
;
354 nBlue
= (sal_uInt8
)nEndBlue
;
358 if ( i
<= nStepsHalf
)
360 nRed
= ImplGetGradientColorValue( nEndRed
-((nRedSteps
*i
)/nSteps2
) );
361 nGreen
= ImplGetGradientColorValue( nEndGreen
-((nGreenSteps
*i
)/nSteps2
) );
362 nBlue
= ImplGetGradientColorValue( nEndBlue
-((nBlueSteps
*i
)/nSteps2
) );
364 // genau die Mitte und hoeher
367 long i2
= i
- nStepsHalf
;
368 nRed
= ImplGetGradientColorValue( nStartRed
+((nRedSteps
*i2
)/nSteps2
) );
369 nGreen
= ImplGetGradientColorValue( nStartGreen
+((nGreenSteps
*i2
)/nSteps2
) );
370 nBlue
= ImplGetGradientColorValue( nStartBlue
+((nBlueSteps
*i2
)/nSteps2
) );
376 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
378 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
382 void OutputDevice::ImplDrawComplexGradient( const Rectangle
& rRect
,
383 const Gradient
& rGradient
,
384 sal_Bool bMtf
, const PolyPolygon
* pClipPolyPoly
)
386 // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon
387 // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone,
388 // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander
390 // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker
391 // das Uebereinanderdrucken von Polygonen koennen
392 // Virtuelle Device werden auch ausgeklammert, da einige Treiber
393 // ansonsten zu langsam sind
394 PolyPolygon
* pPolyPoly
;
397 Color
aStartCol( rGradient
.GetStartColor() );
398 Color
aEndCol( rGradient
.GetEndColor() );
399 long nStartRed
= ( (long) aStartCol
.GetRed() * rGradient
.GetStartIntensity() ) / 100;
400 long nStartGreen
= ( (long) aStartCol
.GetGreen() * rGradient
.GetStartIntensity() ) / 100;
401 long nStartBlue
= ( (long) aStartCol
.GetBlue() * rGradient
.GetStartIntensity() ) / 100;
402 long nEndRed
= ( (long) aEndCol
.GetRed() * rGradient
.GetEndIntensity() ) / 100;
403 long nEndGreen
= ( (long) aEndCol
.GetGreen() * rGradient
.GetEndIntensity() ) / 100;
404 long nEndBlue
= ( (long) aEndCol
.GetBlue() * rGradient
.GetEndIntensity() ) / 100;
405 long nRedSteps
= nEndRed
- nStartRed
;
406 long nGreenSteps
= nEndGreen
- nStartGreen
;
407 long nBlueSteps
= nEndBlue
- nStartBlue
;
408 long nStepCount
= rGradient
.GetSteps();
409 sal_uInt16 nAngle
= rGradient
.GetAngle() % 3600;
411 rGradient
.GetBoundRect( rRect
, aRect
, aCenter
);
413 if( (meRasterOp
!= ROP_OVERPAINT
) || (meOutDevType
!= OUTDEV_WINDOW
) || bMtf
)
414 pPolyPoly
= new PolyPolygon( 2 );
418 long nMinRect
= std::min( aRect
.GetWidth(), aRect
.GetHeight() );
420 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
425 if ( meOutDevType
!= OUTDEV_PRINTER
&& !bMtf
)
427 nInc
= ( nMinRect
< 50 ) ? 2 : 4;
431 // #105998# Use display-equivalent step size calculation
432 nInc
= (nMinRect
< 800) ? 10 : 20;
435 nStepCount
= nMinRect
/ nInc
;
438 // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
439 long nSteps
= std::max( nStepCount
, 2L );
440 long nCalcSteps
= std::abs( nRedSteps
);
441 long nTempSteps
= std::abs( nGreenSteps
);
442 if ( nTempSteps
> nCalcSteps
)
443 nCalcSteps
= nTempSteps
;
444 nTempSteps
= std::abs( nBlueSteps
);
445 if ( nTempSteps
> nCalcSteps
)
446 nCalcSteps
= nTempSteps
;
447 if ( nCalcSteps
< nSteps
)
452 // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
454 double fScanLeft
= aRect
.Left();
455 double fScanTop
= aRect
.Top();
456 double fScanRight
= aRect
.Right();
457 double fScanBottom
= aRect
.Bottom();
458 double fScanIncX
= (double) aRect
.GetWidth() / (double) nSteps
* 0.5;
459 double fScanIncY
= (double) aRect
.GetHeight() / (double) nSteps
* 0.5;
461 // all gradients are rendered as nested rectangles which shrink
462 // equally in each dimension - except for 'square' gradients
463 // which shrink to a central vertex but are not per-se square.
464 if( rGradient
.GetStyle() != GradientStyle_SQUARE
)
466 fScanIncY
= std::min( fScanIncY
, fScanIncX
);
467 fScanIncX
= fScanIncY
;
470 sal_uInt8 nRed
= (sal_uInt8
) nStartRed
, nGreen
= (sal_uInt8
) nStartGreen
, nBlue
= (sal_uInt8
) nStartBlue
;
471 bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
474 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
476 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
480 pPolyPoly
->Insert( aPoly
= rRect
);
481 pPolyPoly
->Insert( aPoly
);
485 // extend rect, to avoid missing bounding line
486 Rectangle
aExtRect( rRect
);
488 aExtRect
.Left() -= 1;
490 aExtRect
.Right() += 1;
491 aExtRect
.Bottom() += 1;
493 ImplDrawPolygon( aPoly
= aExtRect
, pClipPolyPoly
);
496 // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben
497 for( long i
= 1; i
< nSteps
; i
++ )
499 // neues Polygon berechnen
500 aRect
.Left() = (long)( fScanLeft
+= fScanIncX
);
501 aRect
.Top() = (long)( fScanTop
+= fScanIncY
);
502 aRect
.Right() = (long)( fScanRight
-= fScanIncX
);
503 aRect
.Bottom() = (long)( fScanBottom
-= fScanIncY
);
505 if( ( aRect
.GetWidth() < 2 ) || ( aRect
.GetHeight() < 2 ) )
508 if( rGradient
.GetStyle() == GradientStyle_RADIAL
|| rGradient
.GetStyle() == GradientStyle_ELLIPTICAL
)
509 aPoly
= Polygon( aRect
.Center(), aRect
.GetWidth() >> 1, aRect
.GetHeight() >> 1 );
511 aPoly
= Polygon( aRect
);
513 aPoly
.Rotate( aCenter
, nAngle
);
515 // Farbe entsprechend anpassen
516 const long nStepIndex
= ( ( pPolyPoly
!= NULL
) ? i
: ( i
+ 1 ) );
517 nRed
= ImplGetGradientColorValue( nStartRed
+ ( ( nRedSteps
* nStepIndex
) / nSteps
) );
518 nGreen
= ImplGetGradientColorValue( nStartGreen
+ ( ( nGreenSteps
* nStepIndex
) / nSteps
) );
519 nBlue
= ImplGetGradientColorValue( nStartBlue
+ ( ( nBlueSteps
* nStepIndex
) / nSteps
) );
521 // entweder langsame PolyPolygon-Ausgaben oder schnelles Polygon-Painting
524 bPaintLastPolygon
= true; // #107349# Paint last polygon only if loop has generated any output
526 pPolyPoly
->Replace( pPolyPoly
->GetObject( 1 ), 0 );
527 pPolyPoly
->Replace( aPoly
, 1 );
530 mpMetaFile
->AddAction( new MetaPolyPolygonAction( *pPolyPoly
) );
532 ImplDrawPolyPolygon( *pPolyPoly
, pClipPolyPoly
);
534 // #107349# Set fill color _after_ geometry painting:
535 // pPolyPoly's geometry is the band from last iteration's
536 // aPoly to current iteration's aPoly. The window outdev
537 // path (see else below), on the other hand, paints the
538 // full aPoly. Thus, here, we're painting the band before
539 // the one painted in the window outdev path below. To get
540 // matching colors, have to delay color setting here.
542 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
544 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
548 // #107349# Set fill color _before_ geometry painting
550 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
552 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
554 ImplDrawPolygon( aPoly
, pClipPolyPoly
);
558 // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes inneres Polygon zeichnen
561 const Polygon
& rPoly
= pPolyPoly
->GetObject( 1 );
563 if( !rPoly
.GetBoundRect().IsEmpty() )
565 // #107349# Paint last polygon with end color only if loop
566 // has generated output. Otherwise, the current
567 // (i.e. start) color is taken, to generate _any_ output.
568 if( bPaintLastPolygon
)
570 nRed
= ImplGetGradientColorValue( nEndRed
);
571 nGreen
= ImplGetGradientColorValue( nEndGreen
);
572 nBlue
= ImplGetGradientColorValue( nEndBlue
);
577 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), sal_True
) );
578 mpMetaFile
->AddAction( new MetaPolygonAction( rPoly
) );
582 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
583 ImplDrawPolygon( rPoly
, pClipPolyPoly
);
591 void OutputDevice::DrawGradient( const Rectangle
& rRect
,
592 const Gradient
& rGradient
)
594 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
595 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
597 if ( mnDrawMode
& DRAWMODE_NOGRADIENT
)
599 else if ( mnDrawMode
& ( DRAWMODE_BLACKGRADIENT
| DRAWMODE_WHITEGRADIENT
| DRAWMODE_SETTINGSGRADIENT
) )
603 if ( mnDrawMode
& DRAWMODE_BLACKGRADIENT
)
604 aColor
= Color( COL_BLACK
);
605 else if ( mnDrawMode
& DRAWMODE_WHITEGRADIENT
)
606 aColor
= Color( COL_WHITE
);
607 else if ( mnDrawMode
& DRAWMODE_SETTINGSGRADIENT
)
608 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
610 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
612 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
613 ( aColor
.GetGreen() >> 1 ) | 0x80,
614 ( aColor
.GetBlue() >> 1 ) | 0x80 );
617 Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
618 SetLineColor( aColor
);
619 SetFillColor( aColor
);
625 Gradient
aGradient( rGradient
);
627 if ( mnDrawMode
& ( DRAWMODE_GRAYGRADIENT
| DRAWMODE_GHOSTEDGRADIENT
) )
629 Color
aStartCol( aGradient
.GetStartColor() );
630 Color
aEndCol( aGradient
.GetEndColor() );
632 if ( mnDrawMode
& DRAWMODE_GRAYGRADIENT
)
634 sal_uInt8 cStartLum
= aStartCol
.GetLuminance(), cEndLum
= aEndCol
.GetLuminance();
635 aStartCol
= Color( cStartLum
, cStartLum
, cStartLum
);
636 aEndCol
= Color( cEndLum
, cEndLum
, cEndLum
);
639 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
641 aStartCol
= Color( ( aStartCol
.GetRed() >> 1 ) | 0x80,
642 ( aStartCol
.GetGreen() >> 1 ) | 0x80,
643 ( aStartCol
.GetBlue() >> 1 ) | 0x80 );
645 aEndCol
= Color( ( aEndCol
.GetRed() >> 1 ) | 0x80,
646 ( aEndCol
.GetGreen() >> 1 ) | 0x80,
647 ( aEndCol
.GetBlue() >> 1 ) | 0x80 );
650 aGradient
.SetStartColor( aStartCol
);
651 aGradient
.SetEndColor( aEndCol
);
655 mpMetaFile
->AddAction( new MetaGradientAction( rRect
, aGradient
) );
657 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
660 // Rechteck in Pixel umrechnen
661 Rectangle
aRect( ImplLogicToDevicePixel( rRect
) );
664 // Wenn Rechteck leer ist, brauchen wir nichts machen
665 if ( !aRect
.IsEmpty() )
667 // Clip Region sichern
668 Push( PUSH_CLIPREGION
);
669 IntersectClipRegion( rRect
);
671 // because we draw with no border line, we have to expand gradient
672 // rect to avoid missing lines on the right and bottom edge
678 // we need a graphics
681 if ( !ImplGetGraphics() )
685 if ( mbInitClipRegion
)
686 ImplInitClipRegion();
688 if ( !mbOutputClipped
)
690 // Gradienten werden ohne Umrandung gezeichnet
691 if ( mbLineColor
|| mbInitLineColor
)
693 mpGraphics
->SetLineColor();
694 mbInitLineColor
= sal_True
;
697 mbInitFillColor
= sal_True
;
699 // calculate step count if necessary
700 if ( !aGradient
.GetSteps() )
701 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
703 if( aGradient
.GetStyle() == GradientStyle_LINEAR
|| aGradient
.GetStyle() == GradientStyle_AXIAL
)
704 ImplDrawLinearGradient( aRect
, aGradient
, sal_False
, NULL
);
706 ImplDrawComplexGradient( aRect
, aGradient
, sal_False
, NULL
);
714 // #i32109#: Make gradient area opaque
715 mpAlphaVDev
->ImplFillOpaqueRectangle( rRect
);
719 void OutputDevice::DrawGradient( const PolyPolygon
& rPolyPoly
,
720 const Gradient
& rGradient
)
722 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
723 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
725 if( mbInitClipRegion
)
726 ImplInitClipRegion();
728 if( mbOutputClipped
)
732 if( !ImplGetGraphics() )
735 if( rPolyPoly
.Count() && rPolyPoly
[ 0 ].GetSize() && !( mnDrawMode
& DRAWMODE_NOGRADIENT
) )
737 if ( mnDrawMode
& ( DRAWMODE_BLACKGRADIENT
| DRAWMODE_WHITEGRADIENT
| DRAWMODE_SETTINGSGRADIENT
) )
741 if ( mnDrawMode
& DRAWMODE_BLACKGRADIENT
)
742 aColor
= Color( COL_BLACK
);
743 else if ( mnDrawMode
& DRAWMODE_WHITEGRADIENT
)
744 aColor
= Color( COL_WHITE
);
745 else if ( mnDrawMode
& DRAWMODE_SETTINGSGRADIENT
)
746 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
748 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
750 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
751 ( aColor
.GetGreen() >> 1 ) | 0x80,
752 ( aColor
.GetBlue() >> 1 ) | 0x80 );
755 Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
756 SetLineColor( aColor
);
757 SetFillColor( aColor
);
758 DrawPolyPolygon( rPolyPoly
);
765 const Rectangle
aRect( rPolyPoly
.GetBoundRect() );
767 mpMetaFile
->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
768 mpMetaFile
->AddAction( new MetaGradientExAction( rPolyPoly
, rGradient
) );
770 if( OUTDEV_PRINTER
== meOutDevType
)
772 Push( PUSH_CLIPREGION
);
773 IntersectClipRegion(Region(rPolyPoly
));
774 DrawGradient( aRect
, rGradient
);
779 const sal_Bool bOldOutput
= IsOutputEnabled();
781 EnableOutput( sal_False
);
782 Push( PUSH_RASTEROP
);
783 SetRasterOp( ROP_XOR
);
784 DrawGradient( aRect
, rGradient
);
785 SetFillColor( COL_BLACK
);
786 SetRasterOp( ROP_0
);
787 DrawPolyPolygon( rPolyPoly
);
788 SetRasterOp( ROP_XOR
);
789 DrawGradient( aRect
, rGradient
);
791 EnableOutput( bOldOutput
);
794 mpMetaFile
->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
797 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
800 Gradient
aGradient( rGradient
);
802 if ( mnDrawMode
& ( DRAWMODE_GRAYGRADIENT
| DRAWMODE_GHOSTEDGRADIENT
) )
804 Color
aStartCol( aGradient
.GetStartColor() );
805 Color
aEndCol( aGradient
.GetEndColor() );
807 if ( mnDrawMode
& DRAWMODE_GRAYGRADIENT
)
809 sal_uInt8 cStartLum
= aStartCol
.GetLuminance(), cEndLum
= aEndCol
.GetLuminance();
810 aStartCol
= Color( cStartLum
, cStartLum
, cStartLum
);
811 aEndCol
= Color( cEndLum
, cEndLum
, cEndLum
);
814 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
816 aStartCol
= Color( ( aStartCol
.GetRed() >> 1 ) | 0x80,
817 ( aStartCol
.GetGreen() >> 1 ) | 0x80,
818 ( aStartCol
.GetBlue() >> 1 ) | 0x80 );
820 aEndCol
= Color( ( aEndCol
.GetRed() >> 1 ) | 0x80,
821 ( aEndCol
.GetGreen() >> 1 ) | 0x80,
822 ( aEndCol
.GetBlue() >> 1 ) | 0x80 );
825 aGradient
.SetStartColor( aStartCol
);
826 aGradient
.SetEndColor( aEndCol
);
829 if( OUTDEV_PRINTER
== meOutDevType
|| ImplGetSVData()->maGDIData
.mbNoXORClipping
)
831 const Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
833 if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
835 // Rechteck in Pixel umrechnen
836 Rectangle
aRect( ImplLogicToDevicePixel( aBoundRect
) );
839 // Wenn Rechteck leer ist, brauchen wir nichts machen
840 if ( !aRect
.IsEmpty() )
842 if( !mpGraphics
&& !ImplGetGraphics() )
845 if( mbInitClipRegion
)
846 ImplInitClipRegion();
848 if( !mbOutputClipped
)
850 PolyPolygon
aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly
) );
852 // Gradienten werden ohne Umrandung gezeichnet
853 if( mbLineColor
|| mbInitLineColor
)
855 mpGraphics
->SetLineColor();
856 mbInitLineColor
= sal_True
;
859 mbInitFillColor
= sal_True
;
861 // calculate step count if necessary
862 if ( !aGradient
.GetSteps() )
863 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
865 if( aGradient
.GetStyle() == GradientStyle_LINEAR
|| aGradient
.GetStyle() == GradientStyle_AXIAL
)
866 ImplDrawLinearGradient( aRect
, aGradient
, sal_False
, &aClipPolyPoly
);
868 ImplDrawComplexGradient( aRect
, aGradient
, sal_False
, &aClipPolyPoly
);
875 const PolyPolygon
aPolyPoly( LogicToPixel( rPolyPoly
) );
876 const Rectangle
aBoundRect( aPolyPoly
.GetBoundRect() );
878 Rectangle
aDstRect( aPoint
, GetOutputSizePixel() );
880 aDstRect
.Intersection( aBoundRect
);
882 if( OUTDEV_WINDOW
== meOutDevType
)
884 const Region
aPaintRgn( ( (Window
*) this )->GetPaintRegion() );
886 if( !aPaintRgn
.IsNull() )
887 aDstRect
.Intersection( LogicToPixel( aPaintRgn
).GetBoundRect() );
890 if( !aDstRect
.IsEmpty() )
892 VirtualDevice
* pVDev
;
893 const Size
aDstSize( aDstRect
.GetSize() );
897 // #110958# Pay attention to alpha VDevs here, otherwise,
898 // background will be wrong: Temp VDev has to have alpha, too.
899 pVDev
= new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 );
903 // nothing special here. Plain VDev
904 pVDev
= new VirtualDevice();
907 if( pVDev
->SetOutputSizePixel( aDstSize
) )
910 const sal_Bool bOldMap
= mbMap
;
912 EnableMapMode( sal_False
);
914 pVDev
->DrawOutDev( Point(), aDstSize
, aDstRect
.TopLeft(), aDstSize
, *this );
915 pVDev
->SetRasterOp( ROP_XOR
);
916 aVDevMap
.SetOrigin( Point( -aDstRect
.Left(), -aDstRect
.Top() ) );
917 pVDev
->SetMapMode( aVDevMap
);
918 pVDev
->DrawGradient( aBoundRect
, aGradient
);
919 pVDev
->SetFillColor( COL_BLACK
);
920 pVDev
->SetRasterOp( ROP_0
);
921 pVDev
->DrawPolyPolygon( aPolyPoly
);
922 pVDev
->SetRasterOp( ROP_XOR
);
923 pVDev
->DrawGradient( aBoundRect
, aGradient
);
924 aVDevMap
.SetOrigin( Point() );
925 pVDev
->SetMapMode( aVDevMap
);
926 DrawOutDev( aDstRect
.TopLeft(), aDstSize
, Point(), aDstSize
, *pVDev
);
928 EnableMapMode( bOldMap
);
937 mpAlphaVDev
->DrawPolyPolygon( rPolyPoly
);
940 void OutputDevice::AddGradientActions( const Rectangle
& rRect
, const Gradient
& rGradient
,
943 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
944 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
946 Rectangle
aRect( rRect
);
950 // Wenn Rechteck leer ist, brauchen wir nichts machen
951 if ( !aRect
.IsEmpty() )
953 Gradient
aGradient( rGradient
);
954 GDIMetaFile
* pOldMtf
= mpMetaFile
;
957 mpMetaFile
->AddAction( new MetaPushAction( PUSH_ALL
) );
958 mpMetaFile
->AddAction( new MetaISectRectClipRegionAction( aRect
) );
959 mpMetaFile
->AddAction( new MetaLineColorAction( Color(), sal_False
) );
961 // because we draw with no border line, we have to expand gradient
962 // rect to avoid missing lines on the right and bottom edge
968 // calculate step count if necessary
969 if ( !aGradient
.GetSteps() )
970 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
972 if( aGradient
.GetStyle() == GradientStyle_LINEAR
|| aGradient
.GetStyle() == GradientStyle_AXIAL
)
973 ImplDrawLinearGradient( aRect
, aGradient
, sal_True
, NULL
);
975 ImplDrawComplexGradient( aRect
, aGradient
, sal_True
, NULL
);
977 mpMetaFile
->AddAction( new MetaPopAction() );
978 mpMetaFile
= pOldMtf
;
982 void OutputDevice::DrawHatch( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
)
984 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
986 Hatch
aHatch( rHatch
);
988 if ( mnDrawMode
& ( DRAWMODE_BLACKLINE
| DRAWMODE_WHITELINE
|
989 DRAWMODE_GRAYLINE
| DRAWMODE_GHOSTEDLINE
|
990 DRAWMODE_SETTINGSLINE
) )
992 Color
aColor( rHatch
.GetColor() );
994 if ( mnDrawMode
& DRAWMODE_BLACKLINE
)
995 aColor
= Color( COL_BLACK
);
996 else if ( mnDrawMode
& DRAWMODE_WHITELINE
)
997 aColor
= Color( COL_WHITE
);
998 else if ( mnDrawMode
& DRAWMODE_GRAYLINE
)
1000 const sal_uInt8 cLum
= aColor
.GetLuminance();
1001 aColor
= Color( cLum
, cLum
, cLum
);
1003 else if( mnDrawMode
& DRAWMODE_SETTINGSLINE
)
1005 aColor
= GetSettings().GetStyleSettings().GetFontColor();
1008 if ( mnDrawMode
& DRAWMODE_GHOSTEDLINE
)
1010 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
1011 ( aColor
.GetGreen() >> 1 ) | 0x80,
1012 ( aColor
.GetBlue() >> 1 ) | 0x80);
1015 aHatch
.SetColor( aColor
);
1019 mpMetaFile
->AddAction( new MetaHatchAction( rPolyPoly
, aHatch
) );
1021 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1024 if( !mpGraphics
&& !ImplGetGraphics() )
1027 if( mbInitClipRegion
)
1028 ImplInitClipRegion();
1030 if( mbOutputClipped
)
1033 if( rPolyPoly
.Count() )
1035 PolyPolygon
aPolyPoly( LogicToPixel( rPolyPoly
) );
1036 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
1037 sal_Bool bOldMap
= mbMap
;
1039 aPolyPoly
.Optimize( POLY_OPTIMIZE_NO_SAME
);
1040 aHatch
.SetDistance( ImplLogicWidthToDevicePixel( aHatch
.GetDistance() ) );
1043 EnableMapMode( sal_False
);
1044 Push( PUSH_LINECOLOR
);
1045 SetLineColor( aHatch
.GetColor() );
1046 ImplInitLineColor();
1047 ImplDrawHatch( aPolyPoly
, aHatch
, sal_False
);
1049 EnableMapMode( bOldMap
);
1050 mpMetaFile
= pOldMetaFile
;
1054 mpAlphaVDev
->DrawHatch( rPolyPoly
, rHatch
);
1057 void OutputDevice::AddHatchActions( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
,
1060 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1062 PolyPolygon
aPolyPoly( rPolyPoly
);
1063 aPolyPoly
.Optimize( POLY_OPTIMIZE_NO_SAME
| POLY_OPTIMIZE_CLOSE
);
1065 if( aPolyPoly
.Count() )
1067 GDIMetaFile
* pOldMtf
= mpMetaFile
;
1070 mpMetaFile
->AddAction( new MetaPushAction( PUSH_ALL
) );
1071 mpMetaFile
->AddAction( new MetaLineColorAction( rHatch
.GetColor(), sal_True
) );
1072 ImplDrawHatch( aPolyPoly
, rHatch
, sal_True
);
1073 mpMetaFile
->AddAction( new MetaPopAction() );
1074 mpMetaFile
= pOldMtf
;
1078 void OutputDevice::ImplDrawHatch( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
, sal_Bool bMtf
)
1080 Rectangle
aRect( rPolyPoly
.GetBoundRect() );
1081 const long nLogPixelWidth
= ImplDevicePixelToLogicWidth( 1 );
1082 const long nWidth
= ImplDevicePixelToLogicWidth( std::max( ImplLogicWidthToDevicePixel( rHatch
.GetDistance() ), 3L ) );
1083 Point
* pPtBuffer
= new Point
[ HATCH_MAXPOINTS
];
1084 Point aPt1
, aPt2
, aEndPt1
;
1088 aRect
.Left() -= nLogPixelWidth
; aRect
.Top() -= nLogPixelWidth
; aRect
.Right() += nLogPixelWidth
; aRect
.Bottom() += nLogPixelWidth
;
1089 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle(), aPt1
, aPt2
, aInc
, aEndPt1
);
1092 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1093 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1094 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1096 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1098 if( ( rHatch
.GetStyle() == HATCH_DOUBLE
) || ( rHatch
.GetStyle() == HATCH_TRIPLE
) )
1101 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle() + 900, aPt1
, aPt2
, aInc
, aEndPt1
);
1104 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1105 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1106 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1108 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1110 if( rHatch
.GetStyle() == HATCH_TRIPLE
)
1113 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle() + 450, aPt1
, aPt2
, aInc
, aEndPt1
);
1116 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1117 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1118 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1120 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1127 void OutputDevice::ImplCalcHatchValues( const Rectangle
& rRect
, long nDist
, sal_uInt16 nAngle10
,
1128 Point
& rPt1
, Point
& rPt2
, Size
& rInc
, Point
& rEndPt1
)
1131 long nAngle
= nAngle10
% 1800;
1137 aRef
= ( !IsRefPoint() ? rRect
.TopLeft() : GetRefPoint() );
1141 rInc
= Size( 0, nDist
);
1142 rPt1
= rRect
.TopLeft();
1143 rPt2
= rRect
.TopRight();
1144 rEndPt1
= rRect
.BottomLeft();
1146 if( aRef
.Y() <= rRect
.Top() )
1147 nOffset
= ( ( rRect
.Top() - aRef
.Y() ) % nDist
);
1149 nOffset
= ( nDist
- ( ( aRef
.Y() - rRect
.Top() ) % nDist
) );
1151 rPt1
.Y() -= nOffset
;
1152 rPt2
.Y() -= nOffset
;
1154 else if( 900 == nAngle
)
1156 rInc
= Size( nDist
, 0 );
1157 rPt1
= rRect
.TopLeft();
1158 rPt2
= rRect
.BottomLeft();
1159 rEndPt1
= rRect
.TopRight();
1161 if( aRef
.X() <= rRect
.Left() )
1162 nOffset
= ( rRect
.Left() - aRef
.X() ) % nDist
;
1164 nOffset
= nDist
- ( ( aRef
.X() - rRect
.Left() ) % nDist
);
1166 rPt1
.X() -= nOffset
;
1167 rPt2
.X() -= nOffset
;
1169 else if( nAngle
>= -450 && nAngle
<= 450 )
1171 const double fAngle
= F_PI1800
* labs( nAngle
);
1172 const double fTan
= tan( fAngle
);
1173 const long nYOff
= FRound( ( rRect
.Right() - rRect
.Left() ) * fTan
);
1176 rInc
= Size( 0, nDist
= FRound( nDist
/ cos( fAngle
) ) );
1180 rPt1
= rRect
.TopLeft();
1181 rPt2
= Point( rRect
.Right(), rRect
.Top() - nYOff
);
1182 rEndPt1
= Point( rRect
.Left(), rRect
.Bottom() + nYOff
);
1183 nPY
= FRound( aRef
.Y() - ( ( rPt1
.X() - aRef
.X() ) * fTan
) );
1187 rPt1
= rRect
.TopRight();
1188 rPt2
= Point( rRect
.Left(), rRect
.Top() - nYOff
);
1189 rEndPt1
= Point( rRect
.Right(), rRect
.Bottom() + nYOff
);
1190 nPY
= FRound( aRef
.Y() + ( ( rPt1
.X() - aRef
.X() ) * fTan
) );
1193 if( nPY
<= rPt1
.Y() )
1194 nOffset
= ( rPt1
.Y() - nPY
) % nDist
;
1196 nOffset
= nDist
- ( ( nPY
- rPt1
.Y() ) % nDist
);
1198 rPt1
.Y() -= nOffset
;
1199 rPt2
.Y() -= nOffset
;
1203 const double fAngle
= F_PI1800
* labs( nAngle
);
1204 const double fTan
= tan( fAngle
);
1205 const long nXOff
= FRound( ( rRect
.Bottom() - rRect
.Top() ) / fTan
);
1208 rInc
= Size( nDist
= FRound( nDist
/ sin( fAngle
) ), 0 );
1212 rPt1
= rRect
.TopLeft();
1213 rPt2
= Point( rRect
.Left() - nXOff
, rRect
.Bottom() );
1214 rEndPt1
= Point( rRect
.Right() + nXOff
, rRect
.Top() );
1215 nPX
= FRound( aRef
.X() - ( ( rPt1
.Y() - aRef
.Y() ) / fTan
) );
1219 rPt1
= rRect
.BottomLeft();
1220 rPt2
= Point( rRect
.Left() - nXOff
, rRect
.Top() );
1221 rEndPt1
= Point( rRect
.Right() + nXOff
, rRect
.Bottom() );
1222 nPX
= FRound( aRef
.X() + ( ( rPt1
.Y() - aRef
.Y() ) / fTan
) );
1225 if( nPX
<= rPt1
.X() )
1226 nOffset
= ( rPt1
.X() - nPX
) % nDist
;
1228 nOffset
= nDist
- ( ( nPX
- rPt1
.X() ) % nDist
);
1230 rPt1
.X() -= nOffset
;
1231 rPt2
.X() -= nOffset
;
1235 void OutputDevice::ImplDrawHatchLine( const Line
& rLine
, const PolyPolygon
& rPolyPoly
,
1236 Point
* pPtBuffer
, sal_Bool bMtf
)
1239 long nAdd
, nPCounter
= 0;
1241 for( long nPoly
= 0, nPolyCount
= rPolyPoly
.Count(); nPoly
< nPolyCount
; nPoly
++ )
1243 const Polygon
& rPoly
= rPolyPoly
[ (sal_uInt16
) nPoly
];
1245 if( rPoly
.GetSize() > 1 )
1247 Line
aCurSegment( rPoly
[ 0 ], Point() );
1249 for( long i
= 1, nCount
= rPoly
.GetSize(); i
<= nCount
; i
++ )
1251 aCurSegment
.SetEnd( rPoly
[ (sal_uInt16
)( i
% nCount
) ] );
1254 if( rLine
.Intersection( aCurSegment
, fX
, fY
) )
1256 if( ( fabs( fX
- aCurSegment
.GetStart().X() ) <= 0.0000001 ) &&
1257 ( fabs( fY
- aCurSegment
.GetStart().Y() ) <= 0.0000001 ) )
1259 const Line
aPrevSegment( rPoly
[ (sal_uInt16
)( ( i
> 1 ) ? ( i
- 2 ) : ( nCount
- 1 ) ) ], aCurSegment
.GetStart() );
1260 const double fPrevDistance
= rLine
.GetDistance( aPrevSegment
.GetStart() );
1261 const double fCurDistance
= rLine
.GetDistance( aCurSegment
.GetEnd() );
1263 if( ( fPrevDistance
<= 0.0 && fCurDistance
> 0.0 ) ||
1264 ( fPrevDistance
> 0.0 && fCurDistance
< 0.0 ) )
1269 else if( ( fabs( fX
- aCurSegment
.GetEnd().X() ) <= 0.0000001 ) &&
1270 ( fabs( fY
- aCurSegment
.GetEnd().Y() ) <= 0.0000001 ) )
1272 const Line
aNextSegment( aCurSegment
.GetEnd(), rPoly
[ (sal_uInt16
)( ( i
+ 1 ) % nCount
) ] );
1274 if( ( fabs( rLine
.GetDistance( aNextSegment
.GetEnd() ) ) <= 0.0000001 ) &&
1275 ( rLine
.GetDistance( aCurSegment
.GetStart() ) > 0.0 ) )
1284 pPtBuffer
[ nPCounter
++ ] = Point( FRound( fX
), FRound( fY
) );
1287 aCurSegment
.SetStart( aCurSegment
.GetEnd() );
1294 qsort( pPtBuffer
, nPCounter
, sizeof( Point
), ImplHatchCmpFnc
);
1301 for( long i
= 0; i
< nPCounter
; i
+= 2 )
1302 mpMetaFile
->AddAction( new MetaLineAction( pPtBuffer
[ i
], pPtBuffer
[ i
+ 1 ] ) );
1306 for( long i
= 0; i
< nPCounter
; i
+= 2 )
1310 mpPDFWriter
->drawLine( pPtBuffer
[ i
], pPtBuffer
[ i
+1 ] );
1314 const Point
aPt1( ImplLogicToDevicePixel( pPtBuffer
[ i
] ) );
1315 const Point
aPt2( ImplLogicToDevicePixel( pPtBuffer
[ i
+ 1 ] ) );
1316 mpGraphics
->DrawLine( aPt1
.X(), aPt1
.Y(), aPt2
.X(), aPt2
.Y(), this );
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */