1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: outdev4.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
35 #include <vcl/salgdi.hxx>
36 #include <tools/debug.hxx>
37 #include <vcl/svdata.hxx>
38 #include <vcl/gradient.hxx>
39 #include <vcl/metaact.hxx>
40 #include <vcl/gdimtf.hxx>
41 #include <vcl/outdata.hxx>
42 #include <tools/poly.hxx>
43 #include <vcl/salbtype.hxx>
44 #include <tools/line.hxx>
45 #include <vcl/hatch.hxx>
46 #include <vcl/window.hxx>
47 #include <vcl/virdev.hxx>
48 #include <vcl/outdev.hxx>
50 #include "pdfwriter_impl.hxx"
51 #include "vcl/window.h"
52 #include "vcl/salframe.hxx"
54 #include <basegfx/polygon/b2dpolygon.hxx>
55 #include <basegfx/polygon/b2dpolypolygon.hxx>
56 #include <basegfx/matrix/b2dhommatrix.hxx>
62 #define HATCH_MAXPOINTS 1024
63 #define GRADIENT_DEFAULT_STEPCOUNT 0
69 extern "C" int __LOADONCALLAPI
ImplHatchCmpFnc( const void* p1
, const void* p2
)
71 const long nX1
= ( (Point
*) p1
)->X();
72 const long nX2
= ( (Point
*) p2
)->X();
73 const long nY1
= ( (Point
*) p1
)->Y();
74 const long nY2
= ( (Point
*) p2
)->Y();
76 return ( nX1
> nX2
? 1 : nX1
== nX2
? nY1
> nY2
? 1: nY1
== nY2
? 0 : -1 : -1 );
79 // =======================================================================
81 DBG_NAMEEX( OutputDevice
)
82 DBG_NAMEEX( Gradient
)
84 // =======================================================================
86 void OutputDevice::ImplDrawPolygon( const Polygon
& rPoly
, const PolyPolygon
* pClipPolyPoly
)
89 ImplDrawPolyPolygon( rPoly
, pClipPolyPoly
);
92 USHORT nPoints
= rPoly
.GetSize();
97 const SalPoint
* pPtAry
= (const SalPoint
*)rPoly
.GetConstPointAry();
98 mpGraphics
->DrawPolygon( nPoints
, pPtAry
, this );
102 // -----------------------------------------------------------------------
104 void OutputDevice::ImplDrawPolyPolygon( const PolyPolygon
& rPolyPoly
, const PolyPolygon
* pClipPolyPoly
)
106 PolyPolygon
* pPolyPoly
;
110 pPolyPoly
= new PolyPolygon
;
111 rPolyPoly
.GetIntersection( *pClipPolyPoly
, *pPolyPoly
);
114 pPolyPoly
= (PolyPolygon
*) &rPolyPoly
;
116 if( pPolyPoly
->Count() == 1 )
118 const Polygon rPoly
= pPolyPoly
->GetObject( 0 );
119 USHORT nSize
= rPoly
.GetSize();
123 const SalPoint
* pPtAry
= (const SalPoint
*)rPoly
.GetConstPointAry();
124 mpGraphics
->DrawPolygon( nSize
, pPtAry
, this );
127 else if( pPolyPoly
->Count() )
129 USHORT nCount
= pPolyPoly
->Count();
130 sal_uInt32
* pPointAry
= new sal_uInt32
[nCount
];
131 PCONSTSALPOINT
* pPointAryAry
= new PCONSTSALPOINT
[nCount
];
135 const Polygon
& rPoly
= pPolyPoly
->GetObject( i
);
136 USHORT nSize
= rPoly
.GetSize();
139 pPointAry
[i
] = nSize
;
140 pPointAryAry
[i
] = (PCONSTSALPOINT
)rPoly
.GetConstPointAry();
149 mpGraphics
->DrawPolygon( *pPointAry
, *pPointAryAry
, this );
151 mpGraphics
->DrawPolyPolygon( nCount
, pPointAry
, pPointAryAry
, this );
154 delete[] pPointAryAry
;
161 // -----------------------------------------------------------------------
163 inline UINT8
ImplGetGradientColorValue( long nValue
)
167 else if ( nValue
> 0xFF )
170 return (UINT8
)nValue
;
173 // -----------------------------------------------------------------------
175 void OutputDevice::ImplDrawLinearGradient( const Rectangle
& rRect
,
176 const Gradient
& rGradient
,
177 BOOL bMtf
, const PolyPolygon
* pClipPolyPoly
)
179 // rotiertes BoundRect ausrechnen
180 Rectangle aRect
= rRect
;
185 USHORT nAngle
= rGradient
.GetAngle() % 3600;
186 double fAngle
= nAngle
* F_PI1800
;
187 double fWidth
= aRect
.GetWidth();
188 double fHeight
= aRect
.GetHeight();
189 double fDX
= fWidth
* fabs( cos( fAngle
) ) +
190 fHeight
* fabs( sin( fAngle
) );
191 double fDY
= fHeight
* fabs( cos( fAngle
) ) +
192 fWidth
* fabs( sin( fAngle
) );
193 fDX
= (fDX
- fWidth
) * 0.5 + 0.5;
194 fDY
= (fDY
- fHeight
) * 0.5 + 0.5;
195 aRect
.Left() -= (long)fDX
;
196 aRect
.Right() += (long)fDX
;
197 aRect
.Top() -= (long)fDY
;
198 aRect
.Bottom() += (long)fDY
;
200 // Rand berechnen und Rechteck neu setzen
201 Point aCenter
= rRect
.Center();
202 Rectangle aFullRect
= aRect
;
203 long nBorder
= (long)rGradient
.GetBorder() * aRect
.GetHeight() / 100;
206 // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
207 if ( rGradient
.GetStyle() == GRADIENT_LINEAR
)
210 aRect
.Top() += nBorder
;
212 // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
218 aRect
.Top() += nBorder
;
219 aRect
.Bottom() -= nBorder
;
222 // Top darf nicht groesser als Bottom sein
223 aRect
.Top() = Min( aRect
.Top(), (long)(aRect
.Bottom() - 1) );
225 long nMinRect
= aRect
.GetHeight();
227 // Intensitaeten von Start- und Endfarbe ggf. aendern und
228 // Farbschrittweiten berechnen
230 Color aStartCol
= rGradient
.GetStartColor();
231 Color aEndCol
= rGradient
.GetEndColor();
232 long nStartRed
= aStartCol
.GetRed();
233 long nStartGreen
= aStartCol
.GetGreen();
234 long nStartBlue
= aStartCol
.GetBlue();
235 long nEndRed
= aEndCol
.GetRed();
236 long nEndGreen
= aEndCol
.GetGreen();
237 long nEndBlue
= aEndCol
.GetBlue();
238 nFactor
= rGradient
.GetStartIntensity();
239 nStartRed
= (nStartRed
* nFactor
) / 100;
240 nStartGreen
= (nStartGreen
* nFactor
) / 100;
241 nStartBlue
= (nStartBlue
* nFactor
) / 100;
242 nFactor
= rGradient
.GetEndIntensity();
243 nEndRed
= (nEndRed
* nFactor
) / 100;
244 nEndGreen
= (nEndGreen
* nFactor
) / 100;
245 nEndBlue
= (nEndBlue
* nFactor
) / 100;
246 long nRedSteps
= nEndRed
- nStartRed
;
247 long nGreenSteps
= nEndGreen
- nStartGreen
;
248 long nBlueSteps
= nEndBlue
- nStartBlue
;
249 long nStepCount
= rGradient
.GetSteps();
251 // Bei nicht linearen Farbverlaeufen haben wir nur die halben Steps
260 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
265 if ( meOutDevType
!= OUTDEV_PRINTER
&& !bMtf
)
267 nInc
= (nMinRect
< 50) ? 2 : 4;
271 // #105998# Use display-equivalent step size calculation
272 nInc
= (nMinRect
< 800) ? 10 : 20;
278 nStepCount
= nMinRect
/ nInc
;
280 // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
281 long nSteps
= Max( nStepCount
, 2L );
282 long nCalcSteps
= Abs( nRedSteps
);
283 long nTempSteps
= Abs( nGreenSteps
);
284 if ( nTempSteps
> nCalcSteps
)
285 nCalcSteps
= nTempSteps
;
286 nTempSteps
= Abs( nBlueSteps
);
287 if ( nTempSteps
> nCalcSteps
)
288 nCalcSteps
= nTempSteps
;
289 if ( nCalcSteps
< nSteps
)
294 // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
295 if ( !bLinear
&& !(nSteps
& 1) )
298 // Berechnung ueber Double-Addition wegen Genauigkeit
299 double fScanLine
= aRect
.Top();
300 double fScanInc
= (double)aRect
.GetHeight() / (double)nSteps
;
302 // Startfarbe berechnen und setzen
310 // Um 1 erhoeht, um die Border innerhalb der Schleife
311 // zeichnen zu koennen
312 nSteps2
= nSteps
+ 1;
313 nRed
= (UINT8
)nStartRed
;
314 nGreen
= (UINT8
)nStartGreen
;
315 nBlue
= (UINT8
)nStartBlue
;
319 // Um 2 erhoeht, um die Border innerhalb der Schleife
320 // zeichnen zu koennen
321 nSteps2
= nSteps
+ 2;
322 nRed
= (UINT8
)nEndRed
;
323 nGreen
= (UINT8
)nEndGreen
;
324 nBlue
= (UINT8
)nEndBlue
;
325 nStepsHalf
= nSteps
>> 1;
329 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
331 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
333 // Startpolygon erzeugen (== Borderpolygon)
335 Polygon
aTempPoly( 2 );
336 aPoly
[0] = aFullRect
.TopLeft();
337 aPoly
[1] = aFullRect
.TopRight();
338 aPoly
[2] = aRect
.TopRight();
339 aPoly
[3] = aRect
.TopLeft();
340 aPoly
.Rotate( aCenter
, nAngle
);
342 // Schleife, um rotierten Verlauf zu fuellen
343 for ( long i
= 0; i
< nSteps2
; i
++ )
345 // berechnetesPolygon ausgeben
347 mpMetaFile
->AddAction( new MetaPolygonAction( aPoly
) );
349 ImplDrawPolygon( aPoly
, pClipPolyPoly
);
351 // neues Polygon berechnen
352 aRect
.Top() = (long)(fScanLine
+= fScanInc
);
354 // unteren Rand komplett fuellen
357 aTempPoly
[0] = aFullRect
.BottomLeft();
358 aTempPoly
[1] = aFullRect
.BottomRight();
362 aTempPoly
[0] = aRect
.TopLeft();
363 aTempPoly
[1] = aRect
.TopRight();
365 aTempPoly
.Rotate( aCenter
, nAngle
);
369 aPoly
[2] = aTempPoly
[1];
370 aPoly
[3] = aTempPoly
[0];
372 // Farbintensitaeten aendern...
376 nRed
= ImplGetGradientColorValue( nStartRed
+((nRedSteps
*i
)/nSteps2
) );
377 nGreen
= ImplGetGradientColorValue( nStartGreen
+((nGreenSteps
*i
)/nSteps2
) );
378 nBlue
= ImplGetGradientColorValue( nStartBlue
+((nBlueSteps
*i
)/nSteps2
) );
383 // fuer axiale FV muss die letzte Farbe der ersten
385 // #107350# Setting end color one step earlier, as the
386 // last time we get here, we drop out of the loop later
390 nRed
= (UINT8
)nEndRed
;
391 nGreen
= (UINT8
)nEndGreen
;
392 nBlue
= (UINT8
)nEndBlue
;
396 if ( i
<= nStepsHalf
)
398 nRed
= ImplGetGradientColorValue( nEndRed
-((nRedSteps
*i
)/nSteps2
) );
399 nGreen
= ImplGetGradientColorValue( nEndGreen
-((nGreenSteps
*i
)/nSteps2
) );
400 nBlue
= ImplGetGradientColorValue( nEndBlue
-((nBlueSteps
*i
)/nSteps2
) );
402 // genau die Mitte und hoeher
405 long i2
= i
- nStepsHalf
;
406 nRed
= ImplGetGradientColorValue( nStartRed
+((nRedSteps
*i2
)/nSteps2
) );
407 nGreen
= ImplGetGradientColorValue( nStartGreen
+((nGreenSteps
*i2
)/nSteps2
) );
408 nBlue
= ImplGetGradientColorValue( nStartBlue
+((nBlueSteps
*i2
)/nSteps2
) );
414 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
416 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
420 // -----------------------------------------------------------------------
422 void OutputDevice::ImplDrawComplexGradient( const Rectangle
& rRect
,
423 const Gradient
& rGradient
,
424 BOOL bMtf
, const PolyPolygon
* pClipPolyPoly
)
426 // Feststellen ob Ausgabe ueber Polygon oder PolyPolygon
427 // Bei Rasteroperationen ungleich Overpaint immer PolyPolygone,
428 // da es zu falschen Ergebnissen kommt, wenn man mehrfach uebereinander
430 // Bei Druckern auch immer PolyPolygone, da nicht alle Drucker
431 // das Uebereinanderdrucken von Polygonen koennen
432 // Virtuelle Device werden auch ausgeklammert, da einige Treiber
433 // ansonsten zu langsam sind
434 PolyPolygon
* pPolyPoly
;
435 Rectangle
aRect( rRect
);
436 Color
aStartCol( rGradient
.GetStartColor() );
437 Color
aEndCol( rGradient
.GetEndColor() );
438 long nStartRed
= ( (long) aStartCol
.GetRed() * rGradient
.GetStartIntensity() ) / 100;
439 long nStartGreen
= ( (long) aStartCol
.GetGreen() * rGradient
.GetStartIntensity() ) / 100;
440 long nStartBlue
= ( (long) aStartCol
.GetBlue() * rGradient
.GetStartIntensity() ) / 100;
441 long nEndRed
= ( (long) aEndCol
.GetRed() * rGradient
.GetEndIntensity() ) / 100;
442 long nEndGreen
= ( (long) aEndCol
.GetGreen() * rGradient
.GetEndIntensity() ) / 100;
443 long nEndBlue
= ( (long) aEndCol
.GetBlue() * rGradient
.GetEndIntensity() ) / 100;
444 long nRedSteps
= nEndRed
- nStartRed
;
445 long nGreenSteps
= nEndGreen
- nStartGreen
;
446 long nBlueSteps
= nEndBlue
- nStartBlue
;
447 long nStepCount
= rGradient
.GetSteps();
448 USHORT nAngle
= rGradient
.GetAngle() % 3600;
450 if( (meRasterOp
!= ROP_OVERPAINT
) || (meOutDevType
!= OUTDEV_WINDOW
) || bMtf
)
451 pPolyPoly
= new PolyPolygon( 2 );
455 if( rGradient
.GetStyle() == GRADIENT_SQUARE
|| rGradient
.GetStyle() == GRADIENT_RECT
)
457 const double fAngle
= nAngle
* F_PI1800
;
458 const double fWidth
= aRect
.GetWidth();
459 const double fHeight
= aRect
.GetHeight();
460 double fDX
= fWidth
* fabs( cos( fAngle
) ) + fHeight
* fabs( sin( fAngle
) );
461 double fDY
= fHeight
* fabs( cos( fAngle
) ) + fWidth
* fabs( sin( fAngle
) );
463 fDX
= ( fDX
- fWidth
) * 0.5 + 0.5;
464 fDY
= ( fDY
- fHeight
) * 0.5 + 0.5;
466 aRect
.Left() -= (long) fDX
;
467 aRect
.Right() += (long) fDX
;
468 aRect
.Top() -= (long) fDY
;
469 aRect
.Bottom() += (long) fDY
;
472 Size
aSize( aRect
.GetSize() );
474 if( rGradient
.GetStyle() == GRADIENT_RADIAL
)
476 // Radien-Berechnung fuer Kreis
477 aSize
.Width() = (long)(0.5 + sqrt((double)aSize
.Width()*(double)aSize
.Width() + (double)aSize
.Height()*(double)aSize
.Height()));
478 aSize
.Height() = aSize
.Width();
480 else if( rGradient
.GetStyle() == GRADIENT_ELLIPTICAL
)
482 // Radien-Berechnung fuer Ellipse
483 aSize
.Width() = (long)( 0.5 + (double) aSize
.Width() * 1.4142 );
484 aSize
.Height() = (long)( 0.5 + (double) aSize
.Height() * 1.4142 );
486 else if( rGradient
.GetStyle() == GRADIENT_SQUARE
)
488 if ( aSize
.Width() > aSize
.Height() )
489 aSize
.Height() = aSize
.Width();
491 aSize
.Width() = aSize
.Height();
494 // neue Mittelpunkte berechnen
495 long nZWidth
= aRect
.GetWidth() * (long) rGradient
.GetOfsX() / 100;
496 long nZHeight
= aRect
.GetHeight() * (long) rGradient
.GetOfsY() / 100;
497 long nBorderX
= (long) rGradient
.GetBorder() * aSize
.Width() / 100;
498 long nBorderY
= (long) rGradient
.GetBorder() * aSize
.Height() / 100;
499 Point
aCenter( aRect
.Left() + nZWidth
, aRect
.Top() + nZHeight
);
501 // Rand beruecksichtigen
502 aSize
.Width() -= nBorderX
;
503 aSize
.Height() -= nBorderY
;
505 // Ausgaberechteck neu setzen
506 aRect
.Left() = aCenter
.X() - ( aSize
.Width() >> 1 );
507 aRect
.Top() = aCenter
.Y() - ( aSize
.Height() >> 1 );
509 aRect
.SetSize( aSize
);
510 long nMinRect
= Min( aRect
.GetWidth(), aRect
.GetHeight() );
512 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
517 if ( meOutDevType
!= OUTDEV_PRINTER
&& !bMtf
)
519 nInc
= ( nMinRect
< 50 ) ? 2 : 4;
523 // #105998# Use display-equivalent step size calculation
524 nInc
= (nMinRect
< 800) ? 10 : 20;
530 nStepCount
= nMinRect
/ nInc
;
533 // minimal drei Schritte und maximal die Anzahl der Farbunterschiede
534 long nSteps
= Max( nStepCount
, 2L );
535 long nCalcSteps
= Abs( nRedSteps
);
536 long nTempSteps
= Abs( nGreenSteps
);
537 if ( nTempSteps
> nCalcSteps
)
538 nCalcSteps
= nTempSteps
;
539 nTempSteps
= Abs( nBlueSteps
);
540 if ( nTempSteps
> nCalcSteps
)
541 nCalcSteps
= nTempSteps
;
542 if ( nCalcSteps
< nSteps
)
547 // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
549 double fScanLeft
= aRect
.Left();
550 double fScanTop
= aRect
.Top();
551 double fScanRight
= aRect
.Right();
552 double fScanBottom
= aRect
.Bottom();
553 double fScanInc
= (double) nMinRect
/ (double) nSteps
* 0.5;
554 UINT8 nRed
= (UINT8
) nStartRed
, nGreen
= (UINT8
) nStartGreen
, nBlue
= (UINT8
) nStartBlue
;
555 bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
558 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
560 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
564 pPolyPoly
->Insert( aPoly
= rRect
);
565 pPolyPoly
->Insert( aPoly
);
569 // extend rect, to avoid missing bounding line
570 Rectangle
aExtRect( rRect
);
572 aExtRect
.Left() -= 1;
574 aExtRect
.Right() += 1;
575 aExtRect
.Bottom() += 1;
577 ImplDrawPolygon( aPoly
= aExtRect
, pClipPolyPoly
);
580 // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben
581 for( long i
= 1; i
< nSteps
; i
++ )
583 // neues Polygon berechnen
584 aRect
.Left() = (long)( fScanLeft
+= fScanInc
);
585 aRect
.Top() = (long)( fScanTop
+= fScanInc
);
586 aRect
.Right() = (long)( fScanRight
-= fScanInc
);
587 aRect
.Bottom() = (long)( fScanBottom
-= fScanInc
);
589 if( ( aRect
.GetWidth() < 2 ) || ( aRect
.GetHeight() < 2 ) )
592 if( rGradient
.GetStyle() == GRADIENT_RADIAL
|| rGradient
.GetStyle() == GRADIENT_ELLIPTICAL
)
593 aPoly
= Polygon( aRect
.Center(), aRect
.GetWidth() >> 1, aRect
.GetHeight() >> 1 );
595 aPoly
= Polygon( aRect
);
597 aPoly
.Rotate( aCenter
, nAngle
);
599 // Farbe entsprechend anpassen
600 const long nStepIndex
= ( ( pPolyPoly
!= NULL
) ? i
: ( i
+ 1 ) );
601 nRed
= ImplGetGradientColorValue( nStartRed
+ ( ( nRedSteps
* nStepIndex
) / nSteps
) );
602 nGreen
= ImplGetGradientColorValue( nStartGreen
+ ( ( nGreenSteps
* nStepIndex
) / nSteps
) );
603 nBlue
= ImplGetGradientColorValue( nStartBlue
+ ( ( nBlueSteps
* nStepIndex
) / nSteps
) );
605 // entweder langsame PolyPolygon-Ausgaben oder schnelles Polygon-Painting
608 bPaintLastPolygon
= true; // #107349# Paint last polygon only if loop has generated any output
610 pPolyPoly
->Replace( pPolyPoly
->GetObject( 1 ), 0 );
611 pPolyPoly
->Replace( aPoly
, 1 );
614 mpMetaFile
->AddAction( new MetaPolyPolygonAction( *pPolyPoly
) );
616 ImplDrawPolyPolygon( *pPolyPoly
, pClipPolyPoly
);
618 // #107349# Set fill color _after_ geometry painting:
619 // pPolyPoly's geometry is the band from last iteration's
620 // aPoly to current iteration's aPoly. The window outdev
621 // path (see else below), on the other hand, paints the
622 // full aPoly. Thus, here, we're painting the band before
623 // the one painted in the window outdev path below. To get
624 // matching colors, have to delay color setting here.
626 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
628 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
632 // #107349# Set fill color _before_ geometry painting
634 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
636 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
638 ImplDrawPolygon( aPoly
, pClipPolyPoly
);
642 // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes inneres Polygon zeichnen
645 const Polygon
& rPoly
= pPolyPoly
->GetObject( 1 );
647 if( !rPoly
.GetBoundRect().IsEmpty() )
649 // #107349# Paint last polygon with end color only if loop
650 // has generated output. Otherwise, the current
651 // (i.e. start) color is taken, to generate _any_ output.
652 if( bPaintLastPolygon
)
654 nRed
= ImplGetGradientColorValue( nEndRed
);
655 nGreen
= ImplGetGradientColorValue( nEndGreen
);
656 nBlue
= ImplGetGradientColorValue( nEndBlue
);
661 mpMetaFile
->AddAction( new MetaFillColorAction( Color( nRed
, nGreen
, nBlue
), TRUE
) );
662 mpMetaFile
->AddAction( new MetaPolygonAction( rPoly
) );
666 mpGraphics
->SetFillColor( MAKE_SALCOLOR( nRed
, nGreen
, nBlue
) );
667 ImplDrawPolygon( rPoly
, pClipPolyPoly
);
675 // -----------------------------------------------------------------------
677 void OutputDevice::DrawGradient( const Rectangle
& rRect
,
678 const Gradient
& rGradient
)
680 DBG_TRACE( "OutputDevice::DrawGradient()" );
681 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
682 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
684 if ( mnDrawMode
& DRAWMODE_NOGRADIENT
)
686 else if ( mnDrawMode
& ( DRAWMODE_BLACKGRADIENT
| DRAWMODE_WHITEGRADIENT
| DRAWMODE_SETTINGSGRADIENT
) )
690 if ( mnDrawMode
& DRAWMODE_BLACKGRADIENT
)
691 aColor
= Color( COL_BLACK
);
692 else if ( mnDrawMode
& DRAWMODE_WHITEGRADIENT
)
693 aColor
= Color( COL_WHITE
);
694 else if ( mnDrawMode
& DRAWMODE_SETTINGSGRADIENT
)
695 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
697 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
699 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
700 ( aColor
.GetGreen() >> 1 ) | 0x80,
701 ( aColor
.GetBlue() >> 1 ) | 0x80 );
704 Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
705 SetLineColor( aColor
);
706 SetFillColor( aColor
);
712 Gradient
aGradient( rGradient
);
714 if ( mnDrawMode
& ( DRAWMODE_GRAYGRADIENT
| DRAWMODE_GHOSTEDGRADIENT
) )
716 Color
aStartCol( aGradient
.GetStartColor() );
717 Color
aEndCol( aGradient
.GetEndColor() );
719 if ( mnDrawMode
& DRAWMODE_GRAYGRADIENT
)
721 BYTE cStartLum
= aStartCol
.GetLuminance(), cEndLum
= aEndCol
.GetLuminance();
722 aStartCol
= Color( cStartLum
, cStartLum
, cStartLum
);
723 aEndCol
= Color( cEndLum
, cEndLum
, cEndLum
);
726 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
728 aStartCol
= Color( ( aStartCol
.GetRed() >> 1 ) | 0x80,
729 ( aStartCol
.GetGreen() >> 1 ) | 0x80,
730 ( aStartCol
.GetBlue() >> 1 ) | 0x80 );
732 aEndCol
= Color( ( aEndCol
.GetRed() >> 1 ) | 0x80,
733 ( aEndCol
.GetGreen() >> 1 ) | 0x80,
734 ( aEndCol
.GetBlue() >> 1 ) | 0x80 );
737 aGradient
.SetStartColor( aStartCol
);
738 aGradient
.SetEndColor( aEndCol
);
742 mpMetaFile
->AddAction( new MetaGradientAction( rRect
, aGradient
) );
744 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
747 // Rechteck in Pixel umrechnen
748 Rectangle
aRect( ImplLogicToDevicePixel( rRect
) );
751 // Wenn Rechteck leer ist, brauchen wir nichts machen
752 if ( !aRect
.IsEmpty() )
754 // Clip Region sichern
755 Push( PUSH_CLIPREGION
);
756 IntersectClipRegion( rRect
);
758 // because we draw with no border line, we have to expand gradient
759 // rect to avoid missing lines on the right and bottom edge
765 // we need a graphics
768 if ( !ImplGetGraphics() )
772 if ( mbInitClipRegion
)
773 ImplInitClipRegion();
775 if ( !mbOutputClipped
)
777 // Gradienten werden ohne Umrandung gezeichnet
778 if ( mbLineColor
|| mbInitLineColor
)
780 mpGraphics
->SetLineColor();
781 mbInitLineColor
= TRUE
;
784 mbInitFillColor
= TRUE
;
786 // calculate step count if neccessary
787 if ( !aGradient
.GetSteps() )
788 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
790 if( aGradient
.GetStyle() == GRADIENT_LINEAR
|| aGradient
.GetStyle() == GRADIENT_AXIAL
)
791 ImplDrawLinearGradient( aRect
, aGradient
, FALSE
, NULL
);
793 ImplDrawComplexGradient( aRect
, aGradient
, FALSE
, NULL
);
801 // #i32109#: Make gradient area opaque
802 mpAlphaVDev
->ImplFillOpaqueRectangle( rRect
);
806 // -----------------------------------------------------------------------
808 void OutputDevice::DrawGradient( const PolyPolygon
& rPolyPoly
,
809 const Gradient
& rGradient
)
811 DBG_TRACE( "OutputDevice::DrawGradient()" );
812 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
813 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
815 if( mbInitClipRegion
)
816 ImplInitClipRegion();
818 if( mbOutputClipped
)
822 if( !ImplGetGraphics() )
825 if( rPolyPoly
.Count() && rPolyPoly
[ 0 ].GetSize() && !( mnDrawMode
& DRAWMODE_NOGRADIENT
) )
827 if ( mnDrawMode
& ( DRAWMODE_BLACKGRADIENT
| DRAWMODE_WHITEGRADIENT
| DRAWMODE_SETTINGSGRADIENT
) )
831 if ( mnDrawMode
& DRAWMODE_BLACKGRADIENT
)
832 aColor
= Color( COL_BLACK
);
833 else if ( mnDrawMode
& DRAWMODE_WHITEGRADIENT
)
834 aColor
= Color( COL_WHITE
);
835 else if ( mnDrawMode
& DRAWMODE_SETTINGSGRADIENT
)
836 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
838 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
840 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
841 ( aColor
.GetGreen() >> 1 ) | 0x80,
842 ( aColor
.GetBlue() >> 1 ) | 0x80 );
845 Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
846 SetLineColor( aColor
);
847 SetFillColor( aColor
);
848 DrawPolyPolygon( rPolyPoly
);
855 const Rectangle
aRect( rPolyPoly
.GetBoundRect() );
857 mpMetaFile
->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
858 mpMetaFile
->AddAction( new MetaGradientExAction( rPolyPoly
, rGradient
) );
860 if( OUTDEV_PRINTER
== meOutDevType
)
862 Push( PUSH_CLIPREGION
);
863 IntersectClipRegion( rPolyPoly
);
864 DrawGradient( aRect
, rGradient
);
869 const BOOL bOldOutput
= IsOutputEnabled();
871 EnableOutput( FALSE
);
872 Push( PUSH_RASTEROP
);
873 SetRasterOp( ROP_XOR
);
874 DrawGradient( aRect
, rGradient
);
875 SetFillColor( COL_BLACK
);
876 SetRasterOp( ROP_0
);
877 DrawPolyPolygon( rPolyPoly
);
878 SetRasterOp( ROP_XOR
);
879 DrawGradient( aRect
, rGradient
);
881 EnableOutput( bOldOutput
);
884 mpMetaFile
->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
887 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
890 Gradient
aGradient( rGradient
);
892 if ( mnDrawMode
& ( DRAWMODE_GRAYGRADIENT
| DRAWMODE_GHOSTEDGRADIENT
) )
894 Color
aStartCol( aGradient
.GetStartColor() );
895 Color
aEndCol( aGradient
.GetEndColor() );
897 if ( mnDrawMode
& DRAWMODE_GRAYGRADIENT
)
899 BYTE cStartLum
= aStartCol
.GetLuminance(), cEndLum
= aEndCol
.GetLuminance();
900 aStartCol
= Color( cStartLum
, cStartLum
, cStartLum
);
901 aEndCol
= Color( cEndLum
, cEndLum
, cEndLum
);
904 if ( mnDrawMode
& DRAWMODE_GHOSTEDGRADIENT
)
906 aStartCol
= Color( ( aStartCol
.GetRed() >> 1 ) | 0x80,
907 ( aStartCol
.GetGreen() >> 1 ) | 0x80,
908 ( aStartCol
.GetBlue() >> 1 ) | 0x80 );
910 aEndCol
= Color( ( aEndCol
.GetRed() >> 1 ) | 0x80,
911 ( aEndCol
.GetGreen() >> 1 ) | 0x80,
912 ( aEndCol
.GetBlue() >> 1 ) | 0x80 );
915 aGradient
.SetStartColor( aStartCol
);
916 aGradient
.SetEndColor( aEndCol
);
919 if( OUTDEV_PRINTER
== meOutDevType
|| ImplGetSVData()->maGDIData
.mbNoXORClipping
)
921 const Rectangle
aBoundRect( rPolyPoly
.GetBoundRect() );
923 if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() )
925 // Rechteck in Pixel umrechnen
926 Rectangle
aRect( ImplLogicToDevicePixel( aBoundRect
) );
929 // Wenn Rechteck leer ist, brauchen wir nichts machen
930 if ( !aRect
.IsEmpty() )
932 if( !mpGraphics
&& !ImplGetGraphics() )
935 if( mbInitClipRegion
)
936 ImplInitClipRegion();
938 if( !mbOutputClipped
)
940 PolyPolygon
aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly
) );
942 // Gradienten werden ohne Umrandung gezeichnet
943 if( mbLineColor
|| mbInitLineColor
)
945 mpGraphics
->SetLineColor();
946 mbInitLineColor
= TRUE
;
949 mbInitFillColor
= TRUE
;
951 // calculate step count if neccessary
952 if ( !aGradient
.GetSteps() )
953 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
955 if( aGradient
.GetStyle() == GRADIENT_LINEAR
|| aGradient
.GetStyle() == GRADIENT_AXIAL
)
956 ImplDrawLinearGradient( aRect
, aGradient
, FALSE
, &aClipPolyPoly
);
958 ImplDrawComplexGradient( aRect
, aGradient
, FALSE
, &aClipPolyPoly
);
965 const PolyPolygon
aPolyPoly( LogicToPixel( rPolyPoly
) );
966 const Rectangle
aBoundRect( aPolyPoly
.GetBoundRect() );
968 Rectangle
aDstRect( aPoint
, GetOutputSizePixel() );
970 aDstRect
.Intersection( aBoundRect
);
972 if( OUTDEV_WINDOW
== meOutDevType
)
974 const Region
aPaintRgn( ( (Window
*) this )->GetPaintRegion() );
976 if( !aPaintRgn
.IsNull() )
977 aDstRect
.Intersection( LogicToPixel( aPaintRgn
).GetBoundRect() );
980 if( !aDstRect
.IsEmpty() )
982 VirtualDevice
* pVDev
;
983 const Size
aDstSize( aDstRect
.GetSize() );
987 // #110958# Pay attention to alpha VDevs here, otherwise,
988 // background will be wrong: Temp VDev has to have alpha, too.
989 pVDev
= new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 );
993 // nothing special here. Plain VDev
994 pVDev
= new VirtualDevice();
997 if( pVDev
->SetOutputSizePixel( aDstSize
) )
1000 const BOOL bOldMap
= mbMap
;
1002 EnableMapMode( FALSE
);
1004 pVDev
->DrawOutDev( Point(), aDstSize
, aDstRect
.TopLeft(), aDstSize
, *this );
1005 pVDev
->SetRasterOp( ROP_XOR
);
1006 aVDevMap
.SetOrigin( Point( -aDstRect
.Left(), -aDstRect
.Top() ) );
1007 pVDev
->SetMapMode( aVDevMap
);
1008 pVDev
->DrawGradient( aBoundRect
, aGradient
);
1009 pVDev
->SetFillColor( COL_BLACK
);
1010 pVDev
->SetRasterOp( ROP_0
);
1011 pVDev
->DrawPolyPolygon( aPolyPoly
);
1012 pVDev
->SetRasterOp( ROP_XOR
);
1013 pVDev
->DrawGradient( aBoundRect
, aGradient
);
1014 aVDevMap
.SetOrigin( Point() );
1015 pVDev
->SetMapMode( aVDevMap
);
1016 DrawOutDev( aDstRect
.TopLeft(), aDstSize
, Point(), aDstSize
, *pVDev
);
1018 EnableMapMode( bOldMap
);
1027 mpAlphaVDev
->DrawPolyPolygon( rPolyPoly
);
1030 // -----------------------------------------------------------------------
1032 void OutputDevice::AddGradientActions( const Rectangle
& rRect
, const Gradient
& rGradient
,
1035 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1036 DBG_CHKOBJ( &rGradient
, Gradient
, NULL
);
1038 Rectangle
aRect( rRect
);
1042 // Wenn Rechteck leer ist, brauchen wir nichts machen
1043 if ( !aRect
.IsEmpty() )
1045 Gradient
aGradient( rGradient
);
1046 GDIMetaFile
* pOldMtf
= mpMetaFile
;
1049 mpMetaFile
->AddAction( new MetaPushAction( PUSH_ALL
) );
1050 mpMetaFile
->AddAction( new MetaISectRectClipRegionAction( aRect
) );
1051 mpMetaFile
->AddAction( new MetaLineColorAction( Color(), FALSE
) );
1053 // because we draw with no border line, we have to expand gradient
1054 // rect to avoid missing lines on the right and bottom edge
1060 // calculate step count if neccessary
1061 if ( !aGradient
.GetSteps() )
1062 aGradient
.SetSteps( GRADIENT_DEFAULT_STEPCOUNT
);
1064 if( aGradient
.GetStyle() == GRADIENT_LINEAR
|| aGradient
.GetStyle() == GRADIENT_AXIAL
)
1065 ImplDrawLinearGradient( aRect
, aGradient
, TRUE
, NULL
);
1067 ImplDrawComplexGradient( aRect
, aGradient
, TRUE
, NULL
);
1069 mpMetaFile
->AddAction( new MetaPopAction() );
1070 mpMetaFile
= pOldMtf
;
1074 // -----------------------------------------------------------------------
1076 void OutputDevice::DrawHatch( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
)
1078 DBG_TRACE( "OutputDevice::DrawHatch()" );
1079 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1081 Hatch
aHatch( rHatch
);
1083 if ( mnDrawMode
& ( DRAWMODE_BLACKLINE
| DRAWMODE_WHITELINE
|
1084 DRAWMODE_GRAYLINE
| DRAWMODE_GHOSTEDLINE
|
1085 DRAWMODE_SETTINGSLINE
) )
1087 Color
aColor( rHatch
.GetColor() );
1089 if ( mnDrawMode
& DRAWMODE_BLACKLINE
)
1090 aColor
= Color( COL_BLACK
);
1091 else if ( mnDrawMode
& DRAWMODE_WHITELINE
)
1092 aColor
= Color( COL_WHITE
);
1093 else if ( mnDrawMode
& DRAWMODE_GRAYLINE
)
1095 const UINT8 cLum
= aColor
.GetLuminance();
1096 aColor
= Color( cLum
, cLum
, cLum
);
1098 else if( mnDrawMode
& DRAWMODE_SETTINGSLINE
)
1100 aColor
= GetSettings().GetStyleSettings().GetFontColor();
1103 if ( mnDrawMode
& DRAWMODE_GHOSTEDLINE
)
1105 aColor
= Color( ( aColor
.GetRed() >> 1 ) | 0x80,
1106 ( aColor
.GetGreen() >> 1 ) | 0x80,
1107 ( aColor
.GetBlue() >> 1 ) | 0x80);
1110 aHatch
.SetColor( aColor
);
1114 mpMetaFile
->AddAction( new MetaHatchAction( rPolyPoly
, aHatch
) );
1116 if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1119 if( !mpGraphics
&& !ImplGetGraphics() )
1122 if( mbInitClipRegion
)
1123 ImplInitClipRegion();
1125 if( mbOutputClipped
)
1128 if( rPolyPoly
.Count() )
1130 PolyPolygon
aPolyPoly( LogicToPixel( rPolyPoly
) );
1131 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
1132 BOOL bOldMap
= mbMap
;
1134 aPolyPoly
.Optimize( POLY_OPTIMIZE_NO_SAME
);
1135 aHatch
.SetDistance( ImplLogicWidthToDevicePixel( aHatch
.GetDistance() ) );
1138 EnableMapMode( FALSE
);
1139 Push( PUSH_LINECOLOR
);
1140 SetLineColor( aHatch
.GetColor() );
1141 ImplInitLineColor();
1142 ImplDrawHatch( aPolyPoly
, aHatch
, FALSE
);
1144 EnableMapMode( bOldMap
);
1145 mpMetaFile
= pOldMetaFile
;
1149 mpAlphaVDev
->DrawHatch( rPolyPoly
, rHatch
);
1152 // -----------------------------------------------------------------------
1154 void OutputDevice::AddHatchActions( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
,
1157 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
1159 PolyPolygon
aPolyPoly( rPolyPoly
);
1160 aPolyPoly
.Optimize( POLY_OPTIMIZE_NO_SAME
| POLY_OPTIMIZE_CLOSE
);
1162 if( aPolyPoly
.Count() )
1164 GDIMetaFile
* pOldMtf
= mpMetaFile
;
1167 mpMetaFile
->AddAction( new MetaPushAction( PUSH_ALL
) );
1168 mpMetaFile
->AddAction( new MetaLineColorAction( rHatch
.GetColor(), TRUE
) );
1169 ImplDrawHatch( aPolyPoly
, rHatch
, TRUE
);
1170 mpMetaFile
->AddAction( new MetaPopAction() );
1171 mpMetaFile
= pOldMtf
;
1175 // -----------------------------------------------------------------------
1177 void OutputDevice::ImplDrawHatch( const PolyPolygon
& rPolyPoly
, const Hatch
& rHatch
, BOOL bMtf
)
1179 Rectangle
aRect( rPolyPoly
.GetBoundRect() );
1180 const long nLogPixelWidth
= ImplDevicePixelToLogicWidth( 1 );
1181 const long nWidth
= ImplDevicePixelToLogicWidth( Max( ImplLogicWidthToDevicePixel( rHatch
.GetDistance() ), 3L ) );
1182 Point
* pPtBuffer
= new Point
[ HATCH_MAXPOINTS
];
1183 Point aPt1
, aPt2
, aEndPt1
;
1187 aRect
.Left() -= nLogPixelWidth
; aRect
.Top() -= nLogPixelWidth
; aRect
.Right() += nLogPixelWidth
; aRect
.Bottom() += nLogPixelWidth
;
1188 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle(), aPt1
, aPt2
, aInc
, aEndPt1
);
1191 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1192 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1193 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1195 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1197 if( ( rHatch
.GetStyle() == HATCH_DOUBLE
) || ( rHatch
.GetStyle() == HATCH_TRIPLE
) )
1200 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle() + 900, aPt1
, aPt2
, aInc
, aEndPt1
);
1203 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1204 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1205 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1207 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1209 if( rHatch
.GetStyle() == HATCH_TRIPLE
)
1212 ImplCalcHatchValues( aRect
, nWidth
, rHatch
.GetAngle() + 450, aPt1
, aPt2
, aInc
, aEndPt1
);
1215 ImplDrawHatchLine( Line( aPt1
, aPt2
), rPolyPoly
, pPtBuffer
, bMtf
);
1216 aPt1
.X() += aInc
.Width(); aPt1
.Y() += aInc
.Height();
1217 aPt2
.X() += aInc
.Width(); aPt2
.Y() += aInc
.Height();
1219 while( ( aPt1
.X() <= aEndPt1
.X() ) && ( aPt1
.Y() <= aEndPt1
.Y() ) );
1226 // -----------------------------------------------------------------------
1228 void OutputDevice::ImplCalcHatchValues( const Rectangle
& rRect
, long nDist
, USHORT nAngle10
,
1229 Point
& rPt1
, Point
& rPt2
, Size
& rInc
, Point
& rEndPt1
)
1232 long nAngle
= nAngle10
% 1800;
1238 aRef
= ( !IsRefPoint() ? rRect
.TopLeft() : GetRefPoint() );
1242 rInc
= Size( 0, nDist
);
1243 rPt1
= rRect
.TopLeft();
1244 rPt2
= rRect
.TopRight();
1245 rEndPt1
= rRect
.BottomLeft();
1247 if( aRef
.Y() <= rRect
.Top() )
1248 nOffset
= ( ( rRect
.Top() - aRef
.Y() ) % nDist
);
1250 nOffset
= ( nDist
- ( ( aRef
.Y() - rRect
.Top() ) % nDist
) );
1252 rPt1
.Y() -= nOffset
;
1253 rPt2
.Y() -= nOffset
;
1255 else if( 900 == nAngle
)
1257 rInc
= Size( nDist
, 0 );
1258 rPt1
= rRect
.TopLeft();
1259 rPt2
= rRect
.BottomLeft();
1260 rEndPt1
= rRect
.TopRight();
1262 if( aRef
.X() <= rRect
.Left() )
1263 nOffset
= ( rRect
.Left() - aRef
.X() ) % nDist
;
1265 nOffset
= nDist
- ( ( aRef
.X() - rRect
.Left() ) % nDist
);
1267 rPt1
.X() -= nOffset
;
1268 rPt2
.X() -= nOffset
;
1270 else if( nAngle
>= -450 && nAngle
<= 450 )
1272 const double fAngle
= F_PI1800
* labs( nAngle
);
1273 const double fTan
= tan( fAngle
);
1274 const long nYOff
= FRound( ( rRect
.Right() - rRect
.Left() ) * fTan
);
1277 rInc
= Size( 0, nDist
= FRound( nDist
/ cos( fAngle
) ) );
1281 rPt1
= rRect
.TopLeft();
1282 rPt2
= Point( rRect
.Right(), rRect
.Top() - nYOff
);
1283 rEndPt1
= Point( rRect
.Left(), rRect
.Bottom() + nYOff
);
1284 nPY
= FRound( aRef
.Y() - ( ( rPt1
.X() - aRef
.X() ) * fTan
) );
1288 rPt1
= rRect
.TopRight();
1289 rPt2
= Point( rRect
.Left(), rRect
.Top() - nYOff
);
1290 rEndPt1
= Point( rRect
.Right(), rRect
.Bottom() + nYOff
);
1291 nPY
= FRound( aRef
.Y() + ( ( rPt1
.X() - aRef
.X() ) * fTan
) );
1294 if( nPY
<= rPt1
.Y() )
1295 nOffset
= ( rPt1
.Y() - nPY
) % nDist
;
1297 nOffset
= nDist
- ( ( nPY
- rPt1
.Y() ) % nDist
);
1299 rPt1
.Y() -= nOffset
;
1300 rPt2
.Y() -= nOffset
;
1304 const double fAngle
= F_PI1800
* labs( nAngle
);
1305 const double fTan
= tan( fAngle
);
1306 const long nXOff
= FRound( ( rRect
.Bottom() - rRect
.Top() ) / fTan
);
1309 rInc
= Size( nDist
= FRound( nDist
/ sin( fAngle
) ), 0 );
1313 rPt1
= rRect
.TopLeft();
1314 rPt2
= Point( rRect
.Left() - nXOff
, rRect
.Bottom() );
1315 rEndPt1
= Point( rRect
.Right() + nXOff
, rRect
.Top() );
1316 nPX
= FRound( aRef
.X() - ( ( rPt1
.Y() - aRef
.Y() ) / fTan
) );
1320 rPt1
= rRect
.BottomLeft();
1321 rPt2
= Point( rRect
.Left() - nXOff
, rRect
.Top() );
1322 rEndPt1
= Point( rRect
.Right() + nXOff
, rRect
.Bottom() );
1323 nPX
= FRound( aRef
.X() + ( ( rPt1
.Y() - aRef
.Y() ) / fTan
) );
1326 if( nPX
<= rPt1
.X() )
1327 nOffset
= ( rPt1
.X() - nPX
) % nDist
;
1329 nOffset
= nDist
- ( ( nPX
- rPt1
.X() ) % nDist
);
1331 rPt1
.X() -= nOffset
;
1332 rPt2
.X() -= nOffset
;
1336 // ------------------------------------------------------------------------
1338 void OutputDevice::ImplDrawHatchLine( const Line
& rLine
, const PolyPolygon
& rPolyPoly
,
1339 Point
* pPtBuffer
, BOOL bMtf
)
1342 long nAdd
, nPCounter
= 0;
1344 for( long nPoly
= 0, nPolyCount
= rPolyPoly
.Count(); nPoly
< nPolyCount
; nPoly
++ )
1346 const Polygon
& rPoly
= rPolyPoly
[ (USHORT
) nPoly
];
1348 if( rPoly
.GetSize() > 1 )
1350 Line
aCurSegment( rPoly
[ 0 ], Point() );
1352 for( long i
= 1, nCount
= rPoly
.GetSize(); i
<= nCount
; i
++ )
1354 aCurSegment
.SetEnd( rPoly
[ (USHORT
)( i
% nCount
) ] );
1357 if( rLine
.Intersection( aCurSegment
, fX
, fY
) )
1359 if( ( fabs( fX
- aCurSegment
.GetStart().X() ) <= 0.0000001 ) &&
1360 ( fabs( fY
- aCurSegment
.GetStart().Y() ) <= 0.0000001 ) )
1362 const Line
aPrevSegment( rPoly
[ (USHORT
)( ( i
> 1 ) ? ( i
- 2 ) : ( nCount
- 1 ) ) ], aCurSegment
.GetStart() );
1363 const double fPrevDistance
= rLine
.GetDistance( aPrevSegment
.GetStart() );
1364 const double fCurDistance
= rLine
.GetDistance( aCurSegment
.GetEnd() );
1366 if( ( fPrevDistance
<= 0.0 && fCurDistance
> 0.0 ) ||
1367 ( fPrevDistance
> 0.0 && fCurDistance
< 0.0 ) )
1372 else if( ( fabs( fX
- aCurSegment
.GetEnd().X() ) <= 0.0000001 ) &&
1373 ( fabs( fY
- aCurSegment
.GetEnd().Y() ) <= 0.0000001 ) )
1375 const Line
aNextSegment( aCurSegment
.GetEnd(), rPoly
[ (USHORT
)( ( i
+ 1 ) % nCount
) ] );
1377 if( ( fabs( rLine
.GetDistance( aNextSegment
.GetEnd() ) ) <= 0.0000001 ) &&
1378 ( rLine
.GetDistance( aCurSegment
.GetStart() ) > 0.0 ) )
1387 pPtBuffer
[ nPCounter
++ ] = Point( FRound( fX
), FRound( fY
) );
1390 aCurSegment
.SetStart( aCurSegment
.GetEnd() );
1397 qsort( pPtBuffer
, nPCounter
, sizeof( Point
), ImplHatchCmpFnc
);
1404 for( long i
= 0; i
< nPCounter
; i
+= 2 )
1405 mpMetaFile
->AddAction( new MetaLineAction( pPtBuffer
[ i
], pPtBuffer
[ i
+ 1 ] ) );
1409 for( long i
= 0; i
< nPCounter
; i
+= 2 )
1413 mpPDFWriter
->drawLine( pPtBuffer
[ i
], pPtBuffer
[ i
+1 ] );
1417 const Point
aPt1( ImplLogicToDevicePixel( pPtBuffer
[ i
] ) );
1418 const Point
aPt2( ImplLogicToDevicePixel( pPtBuffer
[ i
+ 1 ] ) );
1419 mpGraphics
->DrawLine( aPt1
.X(), aPt1
.Y(), aPt2
.X(), aPt2
.Y(), this );