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: canvastools.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_basegfx.hxx"
34 #include <basegfx/tools/gradienttools.hxx>
36 #include <basegfx/point/b2dpoint.hxx>
37 #include <basegfx/range/b2drange.hxx>
41 /** Most of the setup for linear & axial gradient is the same, except
42 for the border treatment. Factored out here.
44 static void init1DGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
45 const B2DRange
& rTargetRange
,
51 o_rGradientInfo
.maTextureTransform
.identity();
52 o_rGradientInfo
.maBackTextureTransform
.identity();
53 o_rGradientInfo
.mnSteps
= nSteps
;
55 double fTargetSizeX(rTargetRange
.getWidth());
56 double fTargetSizeY(rTargetRange
.getHeight());
57 double fTargetOffsetX(rTargetRange
.getMinX());
58 double fTargetOffsetY(rTargetRange
.getMinY());
60 // add object expansion
63 const double fAbsCos(fabs(cos(fAngle
)));
64 const double fAbsSin(fabs(sin(fAngle
)));
65 const double fNewX(fTargetSizeX
* fAbsCos
+ fTargetSizeY
* fAbsSin
);
66 const double fNewY(fTargetSizeY
* fAbsCos
+ fTargetSizeX
* fAbsSin
);
67 fTargetOffsetX
-= (fNewX
- fTargetSizeX
) / 2.0;
68 fTargetOffsetY
-= (fNewY
- fTargetSizeY
) / 2.0;
73 // add object scale before rotate
74 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
76 // add texture rotate after scale to keep perpendicular angles
79 B2DPoint
aCenter(0.5, 0.5);
80 aCenter
*= o_rGradientInfo
.maTextureTransform
;
82 o_rGradientInfo
.maTextureTransform
.translate(-aCenter
.getX(), -aCenter
.getY());
83 o_rGradientInfo
.maTextureTransform
.rotate(fAngle
);
84 o_rGradientInfo
.maTextureTransform
.translate(aCenter
.getX(), aCenter
.getY());
87 // add object translate
88 o_rGradientInfo
.maTextureTransform
.translate(fTargetOffsetX
, fTargetOffsetY
);
90 // prepare aspect for texture
91 o_rGradientInfo
.mfAspectRatio
= (0.0 != fTargetSizeY
) ? fTargetSizeX
/ fTargetSizeY
: 1.0;
93 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
94 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
95 o_rGradientInfo
.maBackTextureTransform
.invert();
97 double fSizeWithoutBorder
=0;
100 fSizeWithoutBorder
= (1.0 - fBorder
) * 0.5;
101 o_rGradientInfo
.maBackTextureTransform
.translate(0.0, -0.5);
105 fSizeWithoutBorder
= 1.0 - fBorder
;
106 o_rGradientInfo
.maBackTextureTransform
.translate(0.0, -fBorder
);
109 if(!fTools::equal(fSizeWithoutBorder
, 0.0))
110 o_rGradientInfo
.maBackTextureTransform
.scale(1.0, 1.0 / fSizeWithoutBorder
);
113 /** Most of the setup for radial & ellipsoidal gradient is the same,
114 except for the border treatment. Factored out here.
116 static void initEllipticalGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
117 const B2DRange
& rTargetRange
,
118 const B2DVector
& rOffset
,
124 o_rGradientInfo
.maTextureTransform
.identity();
125 o_rGradientInfo
.maBackTextureTransform
.identity();
126 o_rGradientInfo
.mnSteps
= nSteps
;
128 double fTargetSizeX(rTargetRange
.getWidth());
129 double fTargetSizeY(rTargetRange
.getHeight());
130 double fTargetOffsetX(rTargetRange
.getMinX());
131 double fTargetOffsetY(rTargetRange
.getMinY());
133 // add object expansion
136 const double fOriginalDiag(sqrt((fTargetSizeX
* fTargetSizeX
) + (fTargetSizeY
* fTargetSizeY
)));
137 fTargetOffsetX
-= (fOriginalDiag
- fTargetSizeX
) / 2.0;
138 fTargetOffsetY
-= (fOriginalDiag
- fTargetSizeY
) / 2.0;
139 fTargetSizeX
= fOriginalDiag
;
140 fTargetSizeY
= fOriginalDiag
;
144 fTargetOffsetX
-= (0.4142 / 2.0 ) * fTargetSizeX
;
145 fTargetOffsetY
-= (0.4142 / 2.0 ) * fTargetSizeY
;
146 fTargetSizeX
= 1.4142 * fTargetSizeX
;
147 fTargetSizeY
= 1.4142 * fTargetSizeY
;
150 // add object scale before rotate
151 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
155 // add texture rotate after scale to keep perpendicular angles
158 B2DPoint
aCenter(0.5, 0.5);
159 aCenter
*= o_rGradientInfo
.maTextureTransform
;
161 o_rGradientInfo
.maTextureTransform
.translate(-aCenter
.getX(), -aCenter
.getY());
162 o_rGradientInfo
.maTextureTransform
.rotate(fAngle
);
163 o_rGradientInfo
.maTextureTransform
.translate(aCenter
.getX(), aCenter
.getY());
167 // add defined offsets after rotation
168 if(0.5 != rOffset
.getX() || 0.5 != rOffset
.getY())
170 // use original target size
171 fTargetOffsetX
+= (rOffset
.getX() - 0.5) * rTargetRange
.getWidth();
172 fTargetOffsetY
+= (rOffset
.getY() - 0.5) * rTargetRange
.getHeight();
175 // add object translate
176 o_rGradientInfo
.maTextureTransform
.translate(fTargetOffsetX
, fTargetOffsetY
);
178 // prepare aspect for texture
179 o_rGradientInfo
.mfAspectRatio
= (0.0 != fTargetSizeY
) ? fTargetSizeX
/ fTargetSizeY
: 1.0;
181 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
182 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
183 o_rGradientInfo
.maBackTextureTransform
.invert();
184 o_rGradientInfo
.maBackTextureTransform
.translate(-0.5, -0.5);
185 const double fHalfBorder((1.0 - fBorder
) * 0.5);
187 if(!fTools::equal(fHalfBorder
, 0.0))
189 const double fFactor(1.0 / fHalfBorder
);
190 o_rGradientInfo
.maBackTextureTransform
.scale(fFactor
, fFactor
);
194 /** Setup for rect & square gradient is exactly the same. Factored out
197 static void initRectGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
198 const B2DRange
& rTargetRange
,
199 const B2DVector
& rOffset
,
204 o_rGradientInfo
.maTextureTransform
.identity();
205 o_rGradientInfo
.maBackTextureTransform
.identity();
206 o_rGradientInfo
.mnSteps
= nSteps
;
208 double fTargetSizeX(rTargetRange
.getWidth());
209 double fTargetSizeY(rTargetRange
.getHeight());
210 double fTargetOffsetX(rTargetRange
.getMinX());
211 double fTargetOffsetY(rTargetRange
.getMinY());
213 // add object expansion
216 const double fAbsCos(fabs(cos(fAngle
)));
217 const double fAbsSin(fabs(sin(fAngle
)));
218 const double fNewX(fTargetSizeX
* fAbsCos
+ fTargetSizeY
* fAbsSin
);
219 const double fNewY(fTargetSizeY
* fAbsCos
+ fTargetSizeX
* fAbsSin
);
220 fTargetOffsetX
-= (fNewX
- fTargetSizeX
) / 2.0;
221 fTargetOffsetY
-= (fNewY
- fTargetSizeY
) / 2.0;
222 fTargetSizeX
= fNewX
;
223 fTargetSizeY
= fNewY
;
226 // add object scale before rotate
227 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
229 // add texture rotate after scale to keep perpendicular angles
232 B2DPoint
aCenter(0.5, 0.5);
233 aCenter
*= o_rGradientInfo
.maTextureTransform
;
235 o_rGradientInfo
.maTextureTransform
.translate(-aCenter
.getX(), -aCenter
.getY());
236 o_rGradientInfo
.maTextureTransform
.rotate(fAngle
);
237 o_rGradientInfo
.maTextureTransform
.translate(aCenter
.getX(), aCenter
.getY());
240 // add defined offsets after rotation
241 if(0.5 != rOffset
.getX() || 0.5 != rOffset
.getY())
243 // use scaled target size
244 fTargetOffsetX
+= (rOffset
.getX() - 0.5) * fTargetSizeX
;
245 fTargetOffsetY
+= (rOffset
.getY() - 0.5) * fTargetSizeY
;
248 // add object translate
249 o_rGradientInfo
.maTextureTransform
.translate(fTargetOffsetX
, fTargetOffsetY
);
251 // prepare aspect for texture
252 o_rGradientInfo
.mfAspectRatio
= (0.0 != fTargetSizeY
) ? fTargetSizeX
/ fTargetSizeY
: 1.0;
254 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
255 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
256 o_rGradientInfo
.maBackTextureTransform
.invert();
257 o_rGradientInfo
.maBackTextureTransform
.translate(-0.5, -0.5);
258 const double fHalfBorder((1.0 - fBorder
) * 0.5);
260 if(!fTools::equal(fHalfBorder
, 0.0))
262 const double fFactor(1.0 / fHalfBorder
);
263 o_rGradientInfo
.maBackTextureTransform
.scale(fFactor
, fFactor
);
269 ODFGradientInfo
& createLinearODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
270 const B2DRange
& rTargetArea
,
275 init1DGradientInfo(o_rGradientInfo
,
281 return o_rGradientInfo
;
284 ODFGradientInfo
& createAxialODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
285 const B2DRange
& rTargetArea
,
290 init1DGradientInfo(o_rGradientInfo
,
296 return o_rGradientInfo
;
299 ODFGradientInfo
& createRadialODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
300 const B2DRange
& rTargetArea
,
301 const B2DVector
& rOffset
,
305 initEllipticalGradientInfo(o_rGradientInfo
,
312 return o_rGradientInfo
;
315 ODFGradientInfo
& createEllipticalODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
316 const B2DRange
& rTargetArea
,
317 const B2DVector
& rOffset
,
322 initEllipticalGradientInfo(o_rGradientInfo
,
329 return o_rGradientInfo
;
332 ODFGradientInfo
& createSquareODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
333 const B2DRange
& rTargetArea
,
334 const B2DVector
& rOffset
,
339 initRectGradientInfo(o_rGradientInfo
,
345 return o_rGradientInfo
;
348 ODFGradientInfo
& createRectangularODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
349 const B2DRange
& rTargetArea
,
350 const B2DVector
& rOffset
,
355 initRectGradientInfo(o_rGradientInfo
,
361 return o_rGradientInfo
;
366 } // namespace basegfx