update dev300-m58
[ooovba.git] / svtools / source / filter.vcl / filter / gradwrap.cxx
bloba7ccc69cd269eab2b1298e2d8a5b0a2ab0cab507
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gradwrap.cxx,v $
10 * $Revision: 1.8 $
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"
34 #include <math.h>
35 #include <svgrad.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;
66 aRect.Left()--;
67 aRect.Top()--;
68 aRect.Right()++;
69 aRect.Bottom()++;
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;
90 BOOL bLinear;
92 // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
93 if ( rGradient.GetStyle() == GRADIENT_LINEAR )
95 bLinear = TRUE;
96 aRect.Top() += nBorder;
98 // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
99 else
101 bLinear = FALSE;
102 nBorder >>= 1;
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
114 if ( !nStepCount )
116 long nInc = ((nMinRect >> 9) + 1) << 3;
118 if ( !nInc )
119 nInc = 1;
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) )
128 nSteps++;
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
136 long nFactor;
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;
156 long nSteps2;
158 if ( bLinear )
160 // Um 1 erhoeht, um die Border innerhalb der Schleife
161 // zeichnen zu koennen
162 nSteps2 = nSteps + 1;
164 else
166 nStepRed <<= 1;
167 nStepGreen <<= 1;
168 nStepBlue <<= 1;
169 nRed = nEndRed;
170 nGreen = nEndGreen;
171 nBlue = nEndBlue;
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)
183 Polygon aPoly( 4 );
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
203 if ( i == nSteps )
205 aTempPoly[0] = aFullRect.BottomLeft();
206 aTempPoly[1] = aFullRect.BottomRight();
208 else
210 aTempPoly[0] = aRect.TopLeft();
211 aTempPoly[1] = aRect.TopRight();
213 aTempPoly.Rotate( aCenter, rGradient.GetAngle() );
215 aPoly[0] = aPoly[3];
216 aPoly[1] = aPoly[2];
217 aPoly[2] = aTempPoly[1];
218 aPoly[3] = aTempPoly[0];
220 // Farbintensitaeten aendern...
221 // fuer lineare FV
222 if ( bLinear )
224 nRed += nStepRed;
225 nGreen += nStepGreen;
226 nBlue += nStepBlue;
228 // fuer radiale FV
229 else
231 if ( i <= (nSteps >> 1) )
233 nRed -= nStepRed;
234 nGreen -= nStepGreen;
235 nBlue -= nStepBlue;
237 // genau die Mitte und hoeher
238 else
240 nRed += nStepRed;
241 nGreen += nStepGreen;
242 nBlue += nStepBlue;
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
256 // Farbe entsprechen
257 else
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
287 else
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
304 if ( !nStepCount )
306 long nInc = ((nMinRect >> 9) + 1) << 3;
308 if ( !nInc )
309 nInc = 1;
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
325 long nFactor;
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) )
376 break;
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
390 nRed += nStepRed;
391 nGreen += nStepGreen;
392 nBlue += nStepBlue;
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;
421 aRect.Left()--;
422 aRect.Top()--;
423 aRect.Right()++;
424 aRect.Bottom()++;
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();
447 else
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
470 if ( !nStepCount )
472 long nInc = ((nMinRect >> 9) + 1) << 3;
474 if ( !nInc )
475 nInc = 1;
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
491 long nFactor;
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) )
542 break;
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);
554 // Farben aendern
555 nRed += nStepRed;
556 nGreen += nStepGreen;
557 nBlue += nStepBlue;
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);