Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
21 : #include <basegfx/polygon/b2dpolygon.hxx>
22 : #include <basegfx/polygon/b2dpolygontools.hxx>
23 : #include <drawinglayer/texture/texture.hxx>
24 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
25 : #include <basegfx/tools/canvastools.hxx>
26 : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
27 :
28 : //////////////////////////////////////////////////////////////////////////////
29 :
30 : using namespace com::sun::star;
31 :
32 : //////////////////////////////////////////////////////////////////////////////
33 :
34 : namespace drawinglayer
35 : {
36 : namespace primitive2d
37 : {
38 686 : void FillGradientPrimitive2D::generateMatricesAndColors(
39 : std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
40 : basegfx::BColor& rOutmostColor) const
41 : {
42 686 : rEntries.clear();
43 :
44 : // make sure steps is not too high/low
45 686 : const basegfx::BColor aStart(getFillGradient().getStartColor());
46 1372 : const basegfx::BColor aEnd(getFillGradient().getEndColor());
47 686 : const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
48 686 : sal_uInt32 nSteps(getFillGradient().getSteps());
49 :
50 686 : if(nSteps == 0)
51 : {
52 686 : nSteps = nMaxSteps;
53 : }
54 :
55 686 : if(nSteps < 2)
56 : {
57 0 : nSteps = 2;
58 : }
59 :
60 686 : if(nSteps > nMaxSteps)
61 : {
62 0 : nSteps = nMaxSteps;
63 : }
64 :
65 686 : nSteps = std::max(sal_uInt32(1), nSteps);
66 :
67 686 : switch(getFillGradient().getStyle())
68 : {
69 : case attribute::GRADIENTSTYLE_LINEAR:
70 : {
71 536 : texture::GeoTexSvxGradientLinear aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
72 536 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
73 536 : break;
74 : }
75 : case attribute::GRADIENTSTYLE_AXIAL:
76 : {
77 150 : texture::GeoTexSvxGradientAxial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
78 150 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
79 150 : break;
80 : }
81 : case attribute::GRADIENTSTYLE_RADIAL:
82 : {
83 0 : texture::GeoTexSvxGradientRadial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY());
84 0 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
85 0 : break;
86 : }
87 : case attribute::GRADIENTSTYLE_ELLIPTICAL:
88 : {
89 0 : texture::GeoTexSvxGradientElliptical aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
90 0 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
91 0 : break;
92 : }
93 : case attribute::GRADIENTSTYLE_SQUARE:
94 : {
95 0 : texture::GeoTexSvxGradientSquare aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
96 0 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
97 0 : break;
98 : }
99 : case attribute::GRADIENTSTYLE_RECT:
100 : {
101 0 : texture::GeoTexSvxGradientRect aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
102 0 : aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
103 0 : break;
104 : }
105 686 : }
106 686 : }
107 :
108 686 : Primitive2DSequence FillGradientPrimitive2D::createOverlappingFill(
109 : const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
110 : const basegfx::BColor& rOutmostColor,
111 : const basegfx::B2DPolygon& rUnitPolygon) const
112 : {
113 : // prepare return value
114 686 : Primitive2DSequence aRetval(rEntries.size() + 1);
115 :
116 : // create solid fill with outmost color
117 1372 : aRetval[0] = Primitive2DReference(
118 : new PolyPolygonColorPrimitive2D(
119 686 : basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(getObjectRange())),
120 2058 : rOutmostColor));
121 :
122 : // create solid fill steps
123 87680 : for(sal_uInt32 a(0); a < rEntries.size(); a++)
124 : {
125 : // create part polygon
126 86994 : basegfx::B2DPolygon aNewPoly(rUnitPolygon);
127 :
128 86994 : aNewPoly.transform(rEntries[a].maB2DHomMatrix);
129 :
130 : // create solid fill
131 173988 : aRetval[a + 1] = Primitive2DReference(
132 : new PolyPolygonColorPrimitive2D(
133 : basegfx::B2DPolyPolygon(aNewPoly),
134 260982 : rEntries[a].maBColor));
135 86994 : }
136 :
137 686 : return aRetval;
138 : }
139 :
140 0 : Primitive2DSequence FillGradientPrimitive2D::createNonOverlappingFill(
141 : const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
142 : const basegfx::BColor& rOutmostColor,
143 : const basegfx::B2DPolygon& rUnitPolygon) const
144 : {
145 : // prepare return value
146 0 : Primitive2DSequence aRetval(rEntries.size() + 1);
147 :
148 : // get outmost range from object
149 0 : basegfx::B2DRange aOutmostRange(getObjectRange());
150 0 : basegfx::B2DPolyPolygon aCombinedPolyPoly;
151 :
152 0 : if(rEntries.size())
153 : {
154 : // extend aOutmostRange with first polygon
155 0 : basegfx::B2DPolygon aFirstPoly(rUnitPolygon);
156 :
157 0 : aFirstPoly.transform(rEntries[0].maB2DHomMatrix);
158 0 : aCombinedPolyPoly.append(aFirstPoly);
159 0 : aOutmostRange.expand(aFirstPoly.getB2DRange());
160 : }
161 :
162 : // add outmost range to combined polypolygon (in 1st place), create first primitive
163 0 : aCombinedPolyPoly.insert(0, basegfx::tools::createPolygonFromRect(aOutmostRange));
164 0 : aRetval[0] = Primitive2DReference(
165 : new PolyPolygonColorPrimitive2D(
166 : aCombinedPolyPoly,
167 0 : rOutmostColor));
168 :
169 0 : if(rEntries.size())
170 : {
171 : // reuse first polygon, it's the second one
172 0 : aCombinedPolyPoly.remove(0);
173 :
174 0 : for(sal_uInt32 a(0); a < rEntries.size() - 1; a++)
175 : {
176 : // create next inner polygon, combinbe with last one
177 0 : basegfx::B2DPolygon aNextPoly(rUnitPolygon);
178 :
179 0 : aNextPoly.transform(rEntries[a + 1].maB2DHomMatrix);
180 0 : aCombinedPolyPoly.append(aNextPoly);
181 :
182 : // create primitive with correct color
183 0 : aRetval[a + 1] = Primitive2DReference(
184 : new PolyPolygonColorPrimitive2D(
185 : aCombinedPolyPoly,
186 0 : rEntries[a].maBColor));
187 :
188 : // reuse inner polygon, it's the 2nd one
189 0 : aCombinedPolyPoly.remove(0);
190 0 : }
191 :
192 : // add last inner polygon with last color
193 0 : aRetval[rEntries.size()] = Primitive2DReference(
194 : new PolyPolygonColorPrimitive2D(
195 : aCombinedPolyPoly,
196 0 : rEntries[rEntries.size() - 1].maBColor));
197 : }
198 :
199 0 : return aRetval;
200 : }
201 :
202 686 : Primitive2DSequence FillGradientPrimitive2D::createFill(bool bOverlapping) const
203 : {
204 : // prepare shape of the Unit Polygon
205 686 : basegfx::B2DPolygon aUnitPolygon;
206 :
207 686 : switch(getFillGradient().getStyle())
208 : {
209 : case attribute::GRADIENTSTYLE_RADIAL:
210 : case attribute::GRADIENTSTYLE_ELLIPTICAL:
211 : {
212 0 : aUnitPolygon = basegfx::tools::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0);
213 0 : break;
214 : }
215 : default: // GRADIENTSTYLE_LINEAR, attribute::GRADIENTSTYLE_AXIAL, attribute::GRADIENTSTYLE_SQUARE, attribute::GRADIENTSTYLE_RECT
216 : {
217 686 : aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0));
218 686 : break;
219 : }
220 : }
221 :
222 : // get the transform matrices and colors (where colors
223 : // will have one more entry that matrices)
224 686 : std::vector< drawinglayer::texture::B2DHomMatrixAndBColor > aEntries;
225 1372 : basegfx::BColor aOutmostColor;
226 :
227 686 : generateMatricesAndColors(aEntries, aOutmostColor);
228 :
229 686 : if(bOverlapping)
230 : {
231 686 : return createOverlappingFill(aEntries, aOutmostColor, aUnitPolygon);
232 : }
233 : else
234 : {
235 0 : return createNonOverlappingFill(aEntries, aOutmostColor, aUnitPolygon);
236 686 : }
237 : }
238 :
239 686 : Primitive2DSequence FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
240 : {
241 : // default creates overlapping fill which works with AntiAliasing and without.
242 : // The non-overlapping version does not create single filled polygons, but
243 : // PolyPolygons where each one describes a 'ring' for the gradient such
244 : // that the rings will not overlap. This is useful fir the old XOR-paint
245 : // 'trick' of VCL which is recorded in Metafiles; so this version may be
246 : // used from the MetafilePrimitive2D in it's decomposition.
247 :
248 686 : if(!getFillGradient().isDefault())
249 : {
250 : static bool bOverlapping(true); // allow to test non-overlapping in the debugger
251 :
252 686 : return createFill(bOverlapping);
253 : }
254 : else
255 : {
256 0 : return Primitive2DSequence();
257 : }
258 : }
259 :
260 1207 : FillGradientPrimitive2D::FillGradientPrimitive2D(
261 : const basegfx::B2DRange& rObjectRange,
262 : const attribute::FillGradientAttribute& rFillGradient)
263 : : BufferedDecompositionPrimitive2D(),
264 : maObjectRange(rObjectRange),
265 1207 : maFillGradient(rFillGradient)
266 : {
267 1207 : }
268 :
269 0 : bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
270 : {
271 0 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
272 : {
273 0 : const FillGradientPrimitive2D& rCompare = (FillGradientPrimitive2D&)rPrimitive;
274 :
275 0 : return (getObjectRange() == rCompare.getObjectRange()
276 0 : && getFillGradient() == rCompare.getFillGradient());
277 : }
278 :
279 0 : return false;
280 : }
281 :
282 47 : basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
283 : {
284 : // return ObjectRange
285 47 : return getObjectRange();
286 : }
287 :
288 : // provide unique ID
289 722 : ImplPrimitive2DIDBlock(FillGradientPrimitive2D, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D)
290 :
291 : } // end of namespace primitive2d
292 : } // end of namespace drawinglayer
293 :
294 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|