1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_basegfx.hxx" 30 31 #include <basegfx/tools/gradienttools.hxx> 32 #include <basegfx/point/b2dpoint.hxx> 33 #include <basegfx/range/b2drange.hxx> 34 #include <basegfx/matrix/b2dhommatrixtools.hxx> 35 36 namespace basegfx 37 { 38 /** Most of the setup for linear & axial gradient is the same, except 39 for the border treatment. Factored out here. 40 */ 41 static void init1DGradientInfo(ODFGradientInfo& o_rGradientInfo, 42 const B2DRange& rTargetRange, 43 sal_uInt32 nSteps, 44 double fBorder, 45 double fAngle, 46 bool bAxial) 47 { 48 o_rGradientInfo.maTextureTransform.identity(); 49 o_rGradientInfo.maBackTextureTransform.identity(); 50 o_rGradientInfo.mnSteps = nSteps; 51 52 fAngle = -fAngle; 53 54 double fTargetSizeX(rTargetRange.getWidth()); 55 double fTargetSizeY(rTargetRange.getHeight()); 56 double fTargetOffsetX(rTargetRange.getMinX()); 57 double fTargetOffsetY(rTargetRange.getMinY()); 58 59 // add object expansion 60 if(0.0 != fAngle) 61 { 62 const double fAbsCos(fabs(cos(fAngle))); 63 const double fAbsSin(fabs(sin(fAngle))); 64 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); 65 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); 66 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; 67 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; 68 fTargetSizeX = fNewX; 69 fTargetSizeY = fNewY; 70 } 71 72 const double fSizeWithoutBorder=1.0 - fBorder; 73 if( bAxial ) 74 { 75 o_rGradientInfo.maTextureTransform.scale(1.0, fSizeWithoutBorder * .5); 76 o_rGradientInfo.maTextureTransform.translate(0.0, 0.5); 77 } 78 else 79 { 80 if(!fTools::equal(fSizeWithoutBorder, 1.0)) 81 { 82 o_rGradientInfo.maTextureTransform.scale(1.0, fSizeWithoutBorder); 83 o_rGradientInfo.maTextureTransform.translate(0.0, fBorder); 84 } 85 } 86 87 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); 88 89 // add texture rotate after scale to keep perpendicular angles 90 if(0.0 != fAngle) 91 { 92 const B2DPoint aCenter(0.5*fTargetSizeX, 93 0.5*fTargetSizeY); 94 o_rGradientInfo.maTextureTransform *= 95 basegfx::tools::createRotateAroundPoint(aCenter, fAngle); 96 } 97 98 // add object translate 99 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); 100 101 // prepare aspect for texture 102 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; 103 104 // build transform from u,v to [0.0 .. 1.0]. 105 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; 106 o_rGradientInfo.maBackTextureTransform.invert(); 107 } 108 109 /** Most of the setup for radial & ellipsoidal gradient is the same, 110 except for the border treatment. Factored out here. 111 */ 112 static void initEllipticalGradientInfo(ODFGradientInfo& o_rGradientInfo, 113 const B2DRange& rTargetRange, 114 const B2DVector& rOffset, 115 sal_uInt32 nSteps, 116 double fBorder, 117 double fAngle, 118 bool bCircular) 119 { 120 o_rGradientInfo.maTextureTransform.identity(); 121 o_rGradientInfo.maBackTextureTransform.identity(); 122 o_rGradientInfo.mnSteps = nSteps; 123 124 fAngle = -fAngle; 125 126 double fTargetSizeX(rTargetRange.getWidth()); 127 double fTargetSizeY(rTargetRange.getHeight()); 128 double fTargetOffsetX(rTargetRange.getMinX()); 129 double fTargetOffsetY(rTargetRange.getMinY()); 130 131 // add object expansion 132 if( bCircular ) 133 { 134 const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY))); 135 fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0; 136 fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0; 137 fTargetSizeX = fOriginalDiag; 138 fTargetSizeY = fOriginalDiag; 139 } 140 else 141 { 142 fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX; 143 fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY; 144 fTargetSizeX = 1.4142 * fTargetSizeX; 145 fTargetSizeY = 1.4142 * fTargetSizeY; 146 } 147 148 const double fHalfBorder((1.0 - fBorder) * 0.5); 149 o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder); 150 151 o_rGradientInfo.maTextureTransform.translate(0.5, 0.5); 152 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); 153 154 // add texture rotate after scale to keep perpendicular angles 155 if( !bCircular && 0.0 != fAngle) 156 { 157 const B2DPoint aCenter(0.5*fTargetSizeX, 158 0.5*fTargetSizeY); 159 o_rGradientInfo.maTextureTransform *= 160 basegfx::tools::createRotateAroundPoint(aCenter, fAngle); 161 } 162 163 // add defined offsets after rotation 164 if(0.5 != rOffset.getX() || 0.5 != rOffset.getY()) 165 { 166 // use original target size 167 fTargetOffsetX += (rOffset.getX() - 0.5) * rTargetRange.getWidth(); 168 fTargetOffsetY += (rOffset.getY() - 0.5) * rTargetRange.getHeight(); 169 } 170 171 // add object translate 172 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); 173 174 // prepare aspect for texture 175 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; 176 177 // build transform from u,v to [0.0 .. 1.0]. 178 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; 179 o_rGradientInfo.maBackTextureTransform.invert(); 180 } 181 182 /** Setup for rect & square gradient is exactly the same. Factored out 183 here. 184 */ 185 static void initRectGradientInfo(ODFGradientInfo& o_rGradientInfo, 186 const B2DRange& rTargetRange, 187 const B2DVector& rOffset, 188 sal_uInt32 nSteps, 189 double fBorder, 190 double fAngle) 191 { 192 o_rGradientInfo.maTextureTransform.identity(); 193 o_rGradientInfo.maBackTextureTransform.identity(); 194 o_rGradientInfo.mnSteps = nSteps; 195 196 fAngle = -fAngle; 197 198 double fTargetSizeX(rTargetRange.getWidth()); 199 double fTargetSizeY(rTargetRange.getHeight()); 200 double fTargetOffsetX(rTargetRange.getMinX()); 201 double fTargetOffsetY(rTargetRange.getMinY()); 202 203 // add object expansion 204 if(0.0 != fAngle) 205 { 206 const double fAbsCos(fabs(cos(fAngle))); 207 const double fAbsSin(fabs(sin(fAngle))); 208 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); 209 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); 210 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; 211 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; 212 fTargetSizeX = fNewX; 213 fTargetSizeY = fNewY; 214 } 215 216 const double fHalfBorder((1.0 - fBorder) * 0.5); 217 o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder); 218 219 o_rGradientInfo.maTextureTransform.translate(0.5, 0.5); 220 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); 221 222 // add texture rotate after scale to keep perpendicular angles 223 if(0.0 != fAngle) 224 { 225 const B2DPoint aCenter(0.5*fTargetSizeX, 226 0.5*fTargetSizeY); 227 o_rGradientInfo.maTextureTransform *= 228 basegfx::tools::createRotateAroundPoint(aCenter, fAngle); 229 } 230 231 // add defined offsets after rotation 232 if(0.5 != rOffset.getX() || 0.5 != rOffset.getY()) 233 { 234 // use scaled target size 235 fTargetOffsetX += (rOffset.getX() - 0.5) * fTargetSizeX; 236 fTargetOffsetY += (rOffset.getY() - 0.5) * fTargetSizeY; 237 } 238 239 // add object translate 240 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); 241 242 // prepare aspect for texture 243 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; 244 245 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform 246 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; 247 o_rGradientInfo.maBackTextureTransform.invert(); 248 } 249 250 namespace tools 251 { 252 ODFGradientInfo& createLinearODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 253 const B2DRange& rTargetArea, 254 sal_uInt32 nSteps, 255 double fBorder, 256 double fAngle) 257 { 258 init1DGradientInfo(o_rGradientInfo, 259 rTargetArea, 260 nSteps, 261 fBorder, 262 fAngle, 263 false); 264 return o_rGradientInfo; 265 } 266 267 ODFGradientInfo& createAxialODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 268 const B2DRange& rTargetArea, 269 sal_uInt32 nSteps, 270 double fBorder, 271 double fAngle) 272 { 273 init1DGradientInfo(o_rGradientInfo, 274 rTargetArea, 275 nSteps, 276 fBorder, 277 fAngle, 278 true); 279 return o_rGradientInfo; 280 } 281 282 ODFGradientInfo& createRadialODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 283 const B2DRange& rTargetArea, 284 const B2DVector& rOffset, 285 sal_uInt32 nSteps, 286 double fBorder) 287 { 288 initEllipticalGradientInfo(o_rGradientInfo, 289 rTargetArea, 290 rOffset, 291 nSteps, 292 fBorder, 293 0.0, 294 true); 295 return o_rGradientInfo; 296 } 297 298 ODFGradientInfo& createEllipticalODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 299 const B2DRange& rTargetArea, 300 const B2DVector& rOffset, 301 sal_uInt32 nSteps, 302 double fBorder, 303 double fAngle) 304 { 305 initEllipticalGradientInfo(o_rGradientInfo, 306 rTargetArea, 307 rOffset, 308 nSteps, 309 fBorder, 310 fAngle, 311 false); 312 return o_rGradientInfo; 313 } 314 315 ODFGradientInfo& createSquareODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 316 const B2DRange& rTargetArea, 317 const B2DVector& rOffset, 318 sal_uInt32 nSteps, 319 double fBorder, 320 double fAngle) 321 { 322 initRectGradientInfo(o_rGradientInfo, 323 rTargetArea, 324 rOffset, 325 nSteps, 326 fBorder, 327 fAngle); 328 return o_rGradientInfo; 329 } 330 331 ODFGradientInfo& createRectangularODFGradientInfo(ODFGradientInfo& o_rGradientInfo, 332 const B2DRange& rTargetArea, 333 const B2DVector& rOffset, 334 sal_uInt32 nSteps, 335 double fBorder, 336 double fAngle) 337 { 338 initRectGradientInfo(o_rGradientInfo, 339 rTargetArea, 340 rOffset, 341 nSteps, 342 fBorder, 343 fAngle); 344 return o_rGradientInfo; 345 } 346 347 } // namespace tools 348 349 } // namespace basegfx 350