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: gradwrap.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_svtools.hxx"
36 #include <svbmpacc.hxx>
37 #include <gradwrap.hxx>
39 // -------------------
40 // - GradientWrapper -
41 // -------------------
43 GradientWrapper::GradientWrapper(const Link
& rDrawPolyRecordHdl
,
44 const Link
& rDrawPolyPolyRecordHdl
,
45 const Link
& rSetFillInBrushRecordHdl
) :
46 aDrawPolyRecordHdl (rDrawPolyRecordHdl
),
47 aDrawPolyPolyRecordHdl (rDrawPolyPolyRecordHdl
),
48 aSetFillInBrushRecordHdl(rSetFillInBrushRecordHdl
)
52 // ------------------------------------------------------------------------
54 GradientWrapper::~GradientWrapper()
58 // ------------------------------------------------------------------------
60 void GradientWrapper::WriteLinearGradient(const Rectangle
& rRect
,
61 const Gradient
& rGradient
)
63 USHORT nStepCount
= 100;
65 Rectangle aRect
= rRect
;
71 // rotiertes BoundRect ausrechnen
72 double fAngle
= (rGradient
.GetAngle() % 3600) * F_PI1800
;
73 double fWidth
= aRect
.GetWidth();
74 double fHeight
= aRect
.GetHeight();
75 double fDX
= fWidth
* fabs( cos( fAngle
) ) +
76 fHeight
* fabs( sin( fAngle
) );
77 double fDY
= fHeight
* fabs( cos( fAngle
) ) +
78 fWidth
* fabs( sin( fAngle
) );
79 fDX
= (fDX
- fWidth
) * 0.5 + 0.5;
80 fDY
= (fDY
- fHeight
) * 0.5 + 0.5;
81 aRect
.Left() -= (long)fDX
;
82 aRect
.Right() += (long)fDX
;
83 aRect
.Top() -= (long)fDY
;
84 aRect
.Bottom() += (long)fDY
;
86 // Rand berechnen und Rechteck neu setzen
87 Point aCenter
= rRect
.Center();
88 Rectangle aFullRect
= aRect
;
89 long nBorder
= (long)rGradient
.GetBorder() * aRect
.GetHeight() / 100;
92 // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
93 if ( rGradient
.GetStyle() == GRADIENT_LINEAR
)
96 aRect
.Top() += nBorder
;
98 // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
104 aRect
.Top() += nBorder
;
105 aRect
.Bottom() -= nBorder
;
108 // Top darf nicht groesser als Bottom sein
109 aRect
.Top() = Min( aRect
.Top(), (long)(aRect
.Bottom() - 1) );
111 long nMinRect
= aRect
.GetHeight();
113 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
116 long nInc
= ((nMinRect
>> 9) + 1) << 3;
121 nStepCount
= (USHORT
)(nMinRect
/ nInc
);
123 // minimal drei Schritte
124 long nSteps
= Max( nStepCount
, (USHORT
)3 );
126 // Falls axialer Farbverlauf, muss die Schrittanzahl ungerade sein
127 if ( !bLinear
&& !(nSteps
& 1) )
130 // Berechnung ueber Double-Addition wegen Genauigkeit
131 double fScanLine
= aRect
.Top();
132 double fScanInc
= (double)aRect
.GetHeight() / (double)nSteps
;
134 // Intensitaeten von Start- und Endfarbe ggf. aendern und
135 // Farbschrittweiten berechnen
137 const Color
& rStartCol
= rGradient
.GetStartColor();
138 const Color
& rEndCol
= rGradient
.GetEndColor();
139 long nRed
= rStartCol
.GetRed();
140 long nGreen
= rStartCol
.GetGreen();
141 long nBlue
= rStartCol
.GetBlue();
142 long nEndRed
= rEndCol
.GetRed();
143 long nEndGreen
= rEndCol
.GetGreen();
144 long nEndBlue
= rEndCol
.GetBlue();
145 nFactor
= rGradient
.GetStartIntensity();
146 nRed
= (nRed
* nFactor
) / 100;
147 nGreen
= (nGreen
* nFactor
) / 100;
148 nBlue
= (nBlue
* nFactor
) / 100;
149 nFactor
= rGradient
.GetEndIntensity();
150 nEndRed
= (nEndRed
* nFactor
) / 100;
151 nEndGreen
= (nEndGreen
* nFactor
) / 100;
152 nEndBlue
= (nEndBlue
* nFactor
) / 100;
153 long nStepRed
= (nEndRed
- nRed
) / nSteps
;
154 long nStepGreen
= (nEndGreen
- nGreen
) / nSteps
;
155 long nStepBlue
= (nEndBlue
- nBlue
) / nSteps
;
160 // Um 1 erhoeht, um die Border innerhalb der Schleife
161 // zeichnen zu koennen
162 nSteps2
= nSteps
+ 1;
173 // Um 2 erhoeht, um die Border innerhalb der Schleife
174 // zeichnen zu koennen
175 nSteps2
= nSteps
+ 2;
177 Color
aCol( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
179 // GDI-Objekte sichern und setzen
180 aSetFillInBrushRecordHdl
.Call(&aCol
);
182 // Startpolygon erzeugen (== Borderpolygon)
184 Polygon
aTempPoly( 2 );
185 aPoly
[0] = aFullRect
.TopLeft();
186 aPoly
[1] = aFullRect
.TopRight();
187 aPoly
[2] = aRect
.TopRight();
188 aPoly
[3] = aRect
.TopLeft();
189 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
191 // Schleife, um rotierten Verlauf zu fuellen
192 for ( long i
= 0; i
< nSteps2
; i
++ )
194 Polygon aTempPoly
= aPoly
;
195 aTempPoly
.Clip( rRect
);
196 aDrawPolyRecordHdl
.Call(&aTempPoly
);
197 aTempPoly
.SetSize( 2 );
199 // neues Polygon berechnen
200 aRect
.Top() = (long)(fScanLine
+= fScanInc
);
202 // unteren Rand komplett fuellen
205 aTempPoly
[0] = aFullRect
.BottomLeft();
206 aTempPoly
[1] = aFullRect
.BottomRight();
210 aTempPoly
[0] = aRect
.TopLeft();
211 aTempPoly
[1] = aRect
.TopRight();
213 aTempPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
217 aPoly
[2] = aTempPoly
[1];
218 aPoly
[3] = aTempPoly
[0];
220 // Farbintensitaeten aendern...
225 nGreen
+= nStepGreen
;
231 if ( i
<= (nSteps
>> 1) )
234 nGreen
-= nStepGreen
;
237 // genau die Mitte und hoeher
241 nGreen
+= nStepGreen
;
246 nRed
= MinMax( nRed
, 0, 255 );
247 nGreen
= MinMax( nGreen
, 0, 255 );
248 nBlue
= MinMax( nBlue
, 0, 255 );
250 // fuer lineare FV ganz normale Bestimmung der Farbe
251 if ( bLinear
|| (i
<= nSteps
) )
253 aCol
= Color( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
255 // fuer axiale FV muss die letzte Farbe der ersten
259 aCol
= Color( (BYTE
) nEndRed
, (BYTE
) nEndGreen
, (BYTE
) nEndBlue
);
262 aSetFillInBrushRecordHdl
.Call(&aCol
);
266 // ------------------------------------------------------------------------
268 void GradientWrapper::WriteRadialGradient(const Rectangle
& rRect
,
269 const Gradient
& rGradient
)
271 USHORT nStepCount
= 100;
272 Rectangle aClipRect
= rRect
;
273 Rectangle aRect
= rRect
;
274 long nZWidth
= aRect
.GetWidth() * (long)rGradient
.GetOfsX() / 100;
275 long nZHeight
= aRect
.GetHeight() * (long)rGradient
.GetOfsY() / 100;
276 Size aSize
= aRect
.GetSize();
277 Point
aCenter( aRect
.Left() + nZWidth
, aRect
.Top() + nZHeight
);
279 // Radien-Berechnung fuer Kreisausgabe (Kreis schliesst Rechteck ein)
280 if ( rGradient
.GetStyle() == GRADIENT_RADIAL
)
282 aSize
.Width() = (long)(0.5 + sqrt((double)aSize
.Width()*(double)aSize
.Width() +
283 (double)aSize
.Height()*(double)aSize
.Height()));
284 aSize
.Height() = aSize
.Width();
286 // Radien-Berechnung fuer Ellipse
289 aSize
.Width() = (long)(0.5 + (double)aSize
.Width() * 1.4142);
290 aSize
.Height() = (long)(0.5 + (double)aSize
.Height() * 1.4142);
293 long nBorderX
= (long)rGradient
.GetBorder() * aSize
.Width() / 100;
294 long nBorderY
= (long)rGradient
.GetBorder() * aSize
.Height() / 100;
295 aSize
.Width() -= nBorderX
;
296 aSize
.Height() -= nBorderY
;
297 aRect
.Left() = aCenter
.X() - (aSize
.Width() >> 1);
298 aRect
.Top() = aCenter
.Y() - (aSize
.Height() >> 1);
299 aRect
.SetSize( aSize
);
301 long nMinRect
= Min( aRect
.GetWidth(), aRect
.GetHeight() );
303 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
306 long nInc
= ((nMinRect
>> 9) + 1) << 3;
311 nStepCount
= (USHORT
)(nMinRect
/ nInc
);
313 // minimal drei Schritte
314 long nSteps
= Max( nStepCount
, (USHORT
)3 );
316 // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
317 double fScanLeft
= aRect
.Left();
318 double fScanTop
= aRect
.Top();
319 double fScanRight
= aRect
.Right();
320 double fScanBottom
= aRect
.Bottom();
321 double fScanInc
= (double)nMinRect
/ (double)nSteps
* 0.5;
323 // Intensitaeten von Start- und Endfarbe ggf. aendern und
324 // Farbschrittweiten berechnen
326 const Color
& rStartCol
= rGradient
.GetStartColor();
327 const Color
& rEndCol
= rGradient
.GetEndColor();
328 long nRed
= rStartCol
.GetRed();
329 long nGreen
= rStartCol
.GetGreen();
330 long nBlue
= rStartCol
.GetBlue();
331 long nEndRed
= rEndCol
.GetRed();
332 long nEndGreen
= rEndCol
.GetGreen();
333 long nEndBlue
= rEndCol
.GetBlue();
334 nFactor
= rGradient
.GetStartIntensity();
335 nRed
= (nRed
* nFactor
) / 100;
336 nGreen
= (nGreen
* nFactor
) / 100;
337 nBlue
= (nBlue
* nFactor
) / 100;
338 nFactor
= rGradient
.GetEndIntensity();
339 nEndRed
= (nEndRed
* nFactor
) / 100;
340 nEndGreen
= (nEndGreen
* nFactor
) / 100;
341 nEndBlue
= (nEndBlue
* nFactor
) / 100;
342 long nStepRed
= (nEndRed
- nRed
) / nSteps
;
343 long nStepGreen
= (nEndGreen
- nGreen
) / nSteps
;
344 long nStepBlue
= (nEndBlue
- nBlue
) / nSteps
;
345 Color
aCol( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
347 // GDI-Objekte sichern und setzen
348 aSetFillInBrushRecordHdl
.Call(&aCol
);
350 // Recteck erstmal ausgeben
351 PolyPolygon
aPolyPoly( 2 );
352 Polygon
aPoly( rRect
);
354 aPolyPoly
.Insert( aPoly
);
355 aPoly
= Polygon( aRect
);
356 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
357 aPolyPoly
.Insert( aPoly
);
359 // erstes Polygon zeichnen (entspricht Rechteck)
360 PolyPolygon aTempPolyPoly
= aPolyPoly
;
361 aTempPolyPoly
.Clip( aClipRect
);
362 aDrawPolyPolyRecordHdl
.Call(&aTempPolyPoly
);
364 for ( long i
= 0; i
< nSteps
; i
++ )
366 Color
aCol( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
367 aSetFillInBrushRecordHdl
.Call(&aCol
);
369 // neues Polygon berechnen
370 aRect
.Left() = (long)(fScanLeft
+= fScanInc
);
371 aRect
.Top() = (long)(fScanTop
+= fScanInc
);
372 aRect
.Right() = (long)(fScanRight
-= fScanInc
);
373 aRect
.Bottom() = (long)(fScanBottom
-= fScanInc
);
375 if ( (aRect
.GetWidth() < 2) || (aRect
.GetHeight() < 2) )
378 aPoly
= Polygon( aRect
.Center(),
379 aRect
.GetWidth() >> 1, aRect
.GetHeight() >> 1 );
380 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
382 aPolyPoly
.Replace( aPolyPoly
.GetObject( 1 ), 0 );
383 aPolyPoly
.Replace( aPoly
, 1 );
385 PolyPolygon aTempPolyPoly
= aPolyPoly
;
386 aTempPolyPoly
.Clip( aClipRect
);
387 aDrawPolyPolyRecordHdl
.Call(&aTempPolyPoly
);
389 // Farbe entsprechend anpassen
391 nGreen
+= nStepGreen
;
394 nRed
= MinMax( nRed
, 0, 0xFF );
395 nGreen
= MinMax( nGreen
, 0, 0xFF );
396 nBlue
= MinMax( nBlue
, 0, 0xFF );
399 // Falls PolyPolygon-Ausgabe, muessen wir noch ein letztes
400 // inneres Polygon zeichnen
401 aCol
= Color( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
402 aSetFillInBrushRecordHdl
.Call(&aCol
);
404 aPoly
= aPolyPoly
.GetObject( 1 );
405 if ( !aPoly
.GetBoundRect().IsEmpty() )
407 aPoly
.Clip( aClipRect
);
408 aDrawPolyRecordHdl
.Call(&aPoly
);
412 // ------------------------------------------------------------------------
414 void GradientWrapper::WriteRectGradient(const Rectangle
& rRect
,
415 const Gradient
& rGradient
)
417 USHORT nStepCount
= 100;
418 Rectangle aClipRect
= rRect
;
419 Rectangle aRect
= rRect
;
426 // rotiertes BoundRect ausrechnen
427 double fAngle
= (rGradient
.GetAngle() % 3600) * F_PI1800
;
428 double fWidth
= aRect
.GetWidth();
429 double fHeight
= aRect
.GetHeight();
430 double fDX
= fWidth
* fabs( cos( fAngle
) ) +
431 fHeight
* fabs( sin( fAngle
) );
432 double fDY
= fHeight
* fabs( cos( fAngle
) ) +
433 fWidth
* fabs( sin( fAngle
) );
434 fDX
= (fDX
- fWidth
) * 0.5 + 0.5;
435 fDY
= (fDY
- fHeight
) * 0.5 + 0.5;
436 aRect
.Left() -= (long)fDX
;
437 aRect
.Right() += (long)fDX
;
438 aRect
.Top() -= (long)fDY
;
439 aRect
.Bottom() += (long)fDY
;
441 // Quadratisch machen, wenn angefordert;
442 Size aSize
= aRect
.GetSize();
443 if ( rGradient
.GetStyle() == GRADIENT_SQUARE
)
445 if ( aSize
.Width() > aSize
.Height() )
446 aSize
.Height() = aSize
.Width();
448 aSize
.Width() = aSize
.Height();
451 // neue Mittelpunkte berechnen
452 long nZWidth
= aRect
.GetWidth() * (long)rGradient
.GetOfsX() / 100;
453 long nZHeight
= aRect
.GetHeight() * (long)rGradient
.GetOfsY() / 100;
454 long nBorderX
= (long)rGradient
.GetBorder() * aSize
.Width() / 100;
455 long nBorderY
= (long)rGradient
.GetBorder() * aSize
.Height() / 100;
456 Point
aCenter( aRect
.Left() + nZWidth
, aRect
.Top() + nZHeight
);
458 // Rand beruecksichtigen
459 aSize
.Width() -= nBorderX
;
460 aSize
.Height() -= nBorderY
;
462 // Ausgaberechteck neu setzen
463 aRect
.Left() = aCenter
.X() - (aSize
.Width() >> 1);
464 aRect
.Top() = aCenter
.Y() - (aSize
.Height() >> 1);
465 aRect
.SetSize( aSize
);
467 long nMinRect
= Min( aRect
.GetWidth(), aRect
.GetHeight() );
469 // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
472 long nInc
= ((nMinRect
>> 9) + 1) << 3;
477 nStepCount
= (USHORT
)(nMinRect
/ nInc
);
479 // minimal drei Schritte
480 long nSteps
= Max( nStepCount
, (USHORT
)3 );
482 // Ausgabebegrenzungen und Schrittweite fuer jede Richtung festlegen
483 double fScanLeft
= aRect
.Left();
484 double fScanTop
= aRect
.Top();
485 double fScanRight
= aRect
.Right();
486 double fScanBottom
= aRect
.Bottom();
487 double fScanInc
= (double)nMinRect
/ (double)nSteps
* 0.5;
489 // Intensitaeten von Start- und Endfarbe ggf. aendern und
490 // Farbschrittweiten berechnen
492 const Color
& rStartCol
= rGradient
.GetStartColor();
493 const Color
& rEndCol
= rGradient
.GetEndColor();
494 long nRed
= rStartCol
.GetRed();
495 long nGreen
= rStartCol
.GetGreen();
496 long nBlue
= rStartCol
.GetBlue();
497 long nEndRed
= rEndCol
.GetRed();
498 long nEndGreen
= rEndCol
.GetGreen();
499 long nEndBlue
= rEndCol
.GetBlue();
500 nFactor
= rGradient
.GetStartIntensity();
501 nRed
= (nRed
* nFactor
) / 100;
502 nGreen
= (nGreen
* nFactor
) / 100;
503 nBlue
= (nBlue
* nFactor
) / 100;
504 nFactor
= rGradient
.GetEndIntensity();
505 nEndRed
= (nEndRed
* nFactor
) / 100;
506 nEndGreen
= (nEndGreen
* nFactor
) / 100;
507 nEndBlue
= (nEndBlue
* nFactor
) / 100;
508 long nStepRed
= (nEndRed
- nRed
) / nSteps
;
509 long nStepGreen
= (nEndGreen
- nGreen
) / nSteps
;
510 long nStepBlue
= (nEndBlue
- nBlue
) / nSteps
;
511 Color
aCol( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
513 // GDI-Objekte sichern und setzen
514 aSetFillInBrushRecordHdl
.Call(&aCol
);
516 // Recteck erstmal ausgeben
517 PolyPolygon
aPolyPoly( 2 );
518 Polygon
aPoly( rRect
);
520 aPolyPoly
.Insert( aPoly
);
521 aPoly
= Polygon( aRect
);
522 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
523 aPolyPoly
.Insert( aPoly
);
525 PolyPolygon aTempPolyPoly
= aPolyPoly
;
526 aTempPolyPoly
.Clip( aClipRect
);
527 aDrawPolyPolyRecordHdl
.Call(&aTempPolyPoly
);
529 // Schleife, um nacheinander die Polygone/PolyPolygone auszugeben
530 for ( long i
= 0; i
< nSteps
; i
++ )
532 Color
aCol( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
533 aSetFillInBrushRecordHdl
.Call(&aCol
);
535 // neues Polygon berechnen
536 aRect
.Left() = (long)(fScanLeft
+= fScanInc
);
537 aRect
.Top() = (long)(fScanTop
+= fScanInc
);
538 aRect
.Right() = (long)(fScanRight
-= fScanInc
);
539 aRect
.Bottom() = (long)(fScanBottom
-= fScanInc
);
541 if ( (aRect
.GetWidth() < 2) || (aRect
.GetHeight() < 2) )
544 aPoly
= Polygon( aRect
);
545 aPoly
.Rotate( aCenter
, rGradient
.GetAngle() );
547 aPolyPoly
.Replace( aPolyPoly
.GetObject( 1 ), 0 );
548 aPolyPoly
.Replace( aPoly
, 1 );
550 PolyPolygon aTempPolyPoly
= aPolyPoly
;
551 aTempPolyPoly
.Clip( aClipRect
);
552 aDrawPolyPolyRecordHdl
.Call(&aTempPolyPoly
);
556 nGreen
+= nStepGreen
;
559 nRed
= MinMax( nRed
, 0, 0xFF );
560 nGreen
= MinMax( nGreen
, 0, 0xFF );
561 nBlue
= MinMax( nBlue
, 0, 0xFF );
564 aCol
= Color( (BYTE
) nRed
, (BYTE
) nGreen
, (BYTE
) nBlue
);
565 aSetFillInBrushRecordHdl
.Call(&aCol
);
567 aPoly
= aPolyPoly
.GetObject( 1 );
568 if ( !aPoly
.GetBoundRect().IsEmpty() )
570 aPoly
.Clip( aClipRect
);
571 aDrawPolyRecordHdl
.Call(&aPoly
);