xref: /trunk/main/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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