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_drawinglayer.hxx" 30 31 #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> 32 #include <basegfx/polygon/b2dpolygon.hxx> 33 #include <basegfx/polygon/b2dpolygontools.hxx> 34 #include <drawinglayer/texture/texture.hxx> 35 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 36 #include <basegfx/tools/canvastools.hxx> 37 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 38 39 ////////////////////////////////////////////////////////////////////////////// 40 41 using namespace com::sun::star; 42 43 ////////////////////////////////////////////////////////////////////////////// 44 45 namespace drawinglayer 46 { 47 namespace primitive2d 48 { 49 void FillGradientPrimitive2D::generateMatricesAndColors( 50 std::vector< basegfx::B2DHomMatrix >& rMatrices, 51 std::vector< basegfx::BColor >& rColors) const 52 { 53 rMatrices.clear(); 54 rColors.clear(); 55 56 // make sure steps is not too high/low 57 const basegfx::BColor aStart(getFillGradient().getStartColor()); 58 const basegfx::BColor aEnd(getFillGradient().getEndColor()); 59 const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5)); 60 sal_uInt32 nSteps(getFillGradient().getSteps()); 61 62 if(nSteps == 0) 63 { 64 nSteps = nMaxSteps; 65 } 66 67 if(nSteps < 2) 68 { 69 nSteps = 2; 70 } 71 72 if(nSteps > nMaxSteps) 73 { 74 nSteps = nMaxSteps; 75 } 76 77 switch(getFillGradient().getStyle()) 78 { 79 case attribute::GRADIENTSTYLE_LINEAR: 80 { 81 texture::GeoTexSvxGradientLinear aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle()); 82 aGradient.appendTransformations(rMatrices); 83 aGradient.appendColors(rColors); 84 break; 85 } 86 case attribute::GRADIENTSTYLE_AXIAL: 87 { 88 texture::GeoTexSvxGradientAxial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle()); 89 aGradient.appendTransformations(rMatrices); 90 aGradient.appendColors(rColors); 91 break; 92 } 93 case attribute::GRADIENTSTYLE_RADIAL: 94 { 95 texture::GeoTexSvxGradientRadial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY()); 96 aGradient.appendTransformations(rMatrices); 97 aGradient.appendColors(rColors); 98 break; 99 } 100 case attribute::GRADIENTSTYLE_ELLIPTICAL: 101 { 102 texture::GeoTexSvxGradientElliptical aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); 103 aGradient.appendTransformations(rMatrices); 104 aGradient.appendColors(rColors); 105 break; 106 } 107 case attribute::GRADIENTSTYLE_SQUARE: 108 { 109 texture::GeoTexSvxGradientSquare aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); 110 aGradient.appendTransformations(rMatrices); 111 aGradient.appendColors(rColors); 112 break; 113 } 114 case attribute::GRADIENTSTYLE_RECT: 115 { 116 texture::GeoTexSvxGradientRect aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); 117 aGradient.appendTransformations(rMatrices); 118 aGradient.appendColors(rColors); 119 break; 120 } 121 } 122 } 123 124 Primitive2DSequence FillGradientPrimitive2D::createOverlappingFill( 125 const std::vector< basegfx::B2DHomMatrix >& rMatrices, 126 const std::vector< basegfx::BColor >& rColors, 127 const basegfx::B2DPolygon& rUnitPolygon) const 128 { 129 // prepare return value 130 Primitive2DSequence aRetval(rColors.size() ? rMatrices.size() + 1 : rMatrices.size()); 131 132 // create solid fill with start color 133 if(rColors.size()) 134 { 135 // create primitive 136 const Primitive2DReference xRef( 137 new PolyPolygonColorPrimitive2D( 138 basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(getObjectRange())), 139 rColors[0])); 140 aRetval[0] = xRef; 141 } 142 143 // create solid fill steps 144 for(sal_uInt32 a(0); a < rMatrices.size(); a++) 145 { 146 // create part polygon 147 basegfx::B2DPolygon aNewPoly(rUnitPolygon); 148 aNewPoly.transform(rMatrices[a]); 149 150 // create solid fill 151 const Primitive2DReference xRef( 152 new PolyPolygonColorPrimitive2D( 153 basegfx::B2DPolyPolygon(aNewPoly), 154 rColors[a + 1])); 155 aRetval[a + 1] = xRef; 156 } 157 158 return aRetval; 159 } 160 161 Primitive2DSequence FillGradientPrimitive2D::createNonOverlappingFill( 162 const std::vector< basegfx::B2DHomMatrix >& rMatrices, 163 const std::vector< basegfx::BColor >& rColors, 164 const basegfx::B2DPolygon& rUnitPolygon) const 165 { 166 // prepare return value 167 Primitive2DSequence aRetval; 168 const sal_uInt32 nMatricesSize(rMatrices.size()); 169 170 if(nMatricesSize) 171 { 172 basegfx::B2DPolygon aOuterPoly(rUnitPolygon); 173 aOuterPoly.transform(rMatrices[0]); 174 basegfx::B2DPolyPolygon aCombinedPolyPoly(aOuterPoly); 175 const sal_uInt32 nEntryCount(rColors.size() ? rMatrices.size() + 1 : rMatrices.size()); 176 sal_uInt32 nIndex(0); 177 178 aRetval.realloc(nEntryCount); 179 180 if(rColors.size()) 181 { 182 basegfx::B2DRange aOuterPolyRange(aOuterPoly.getB2DRange()); 183 aOuterPolyRange.expand(getObjectRange()); 184 aCombinedPolyPoly.append(basegfx::tools::createPolygonFromRect(aOuterPolyRange)); 185 aRetval[nIndex++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(aCombinedPolyPoly, rColors[0])); 186 aCombinedPolyPoly = basegfx::B2DPolyPolygon(aOuterPoly); 187 } 188 189 for(sal_uInt32 a(1); a < nMatricesSize - 1; a++) 190 { 191 basegfx::B2DPolygon aInnerPoly(rUnitPolygon); 192 aInnerPoly.transform(rMatrices[a]); 193 aCombinedPolyPoly.append(aInnerPoly); 194 aRetval[nIndex++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(aCombinedPolyPoly, rColors[a])); 195 aCombinedPolyPoly = basegfx::B2DPolyPolygon(aInnerPoly); 196 } 197 198 if(rColors.size()) 199 { 200 aRetval[nIndex] = Primitive2DReference(new PolyPolygonColorPrimitive2D( 201 aCombinedPolyPoly, rColors[rColors.size() - 1])); 202 } 203 } 204 205 return aRetval; 206 } 207 208 Primitive2DSequence FillGradientPrimitive2D::createFill(bool bOverlapping) const 209 { 210 // prepare shape of the Unit Polygon 211 basegfx::B2DPolygon aUnitPolygon; 212 213 if(attribute::GRADIENTSTYLE_RADIAL == getFillGradient().getStyle() 214 || attribute::GRADIENTSTYLE_ELLIPTICAL == getFillGradient().getStyle()) 215 { 216 aUnitPolygon = basegfx::tools::createPolygonFromCircle( 217 basegfx::B2DPoint(0,0), 1); 218 } 219 else if(attribute::GRADIENTSTYLE_LINEAR == maFillGradient.getStyle()) 220 { 221 aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0, 0, 1, 1)); 222 } 223 else 224 { 225 aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1, -1, 1, 1)); 226 } 227 228 // get the transform matrices and colors (where colors 229 // will have one more entry that matrices) 230 std::vector< basegfx::B2DHomMatrix > aMatrices; 231 std::vector< basegfx::BColor > aColors; 232 generateMatricesAndColors(aMatrices, aColors); 233 234 if(bOverlapping) 235 { 236 return createOverlappingFill(aMatrices, aColors, aUnitPolygon); 237 } 238 else 239 { 240 return createNonOverlappingFill(aMatrices, aColors, aUnitPolygon); 241 } 242 } 243 244 Primitive2DSequence FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const 245 { 246 // default creates overlapping fill which works with AntiAliasing and without. 247 // The non-overlapping version does not create single filled polygons, but 248 // PolyPolygons where each one describes a 'ring' for the gradient such 249 // that the rings will not overlap. This is useful fir the old XOR-paint 250 // 'trick' of VCL which is recorded in Metafiles; so this version may be 251 // used from the MetafilePrimitive2D in it's decomposition. 252 253 if(!getFillGradient().isDefault()) 254 { 255 return createFill(true); 256 } 257 else 258 { 259 return Primitive2DSequence(); 260 } 261 } 262 263 FillGradientPrimitive2D::FillGradientPrimitive2D( 264 const basegfx::B2DRange& rObjectRange, 265 const attribute::FillGradientAttribute& rFillGradient) 266 : BufferedDecompositionPrimitive2D(), 267 maObjectRange(rObjectRange), 268 maFillGradient(rFillGradient) 269 { 270 } 271 272 bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 273 { 274 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) 275 { 276 const FillGradientPrimitive2D& rCompare = (FillGradientPrimitive2D&)rPrimitive; 277 278 return (getObjectRange() == rCompare.getObjectRange() 279 && getFillGradient() == rCompare.getFillGradient()); 280 } 281 282 return false; 283 } 284 285 basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const 286 { 287 // return ObjectRange 288 return getObjectRange(); 289 } 290 291 // provide unique ID 292 ImplPrimitrive2DIDBlock(FillGradientPrimitive2D, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D) 293 294 } // end of namespace primitive2d 295 } // end of namespace drawinglayer 296 297 ////////////////////////////////////////////////////////////////////////////// 298 // eof 299