Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / drawinglayer / source / primitive2d / fillgradientprimitive2d.cxx
blob96b3de031accd61bd97dd6b5c686d7c7795f9df3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/utils/canvastools.hxx>
26 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
29 using namespace com::sun::star;
32 namespace drawinglayer
34 namespace primitive2d
36 void FillGradientPrimitive2D::generateMatricesAndColors(
37 std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
38 basegfx::BColor& rOuterColor) const
40 rEntries.clear();
42 // make sure steps is not too high/low
43 const basegfx::BColor aStart(getFillGradient().getStartColor());
44 const basegfx::BColor aEnd(getFillGradient().getEndColor());
45 const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
46 sal_uInt32 nSteps(getFillGradient().getSteps());
48 if(nSteps == 0)
50 nSteps = nMaxSteps;
53 if(nSteps < 2)
55 nSteps = 2;
58 if(nSteps > nMaxSteps)
60 nSteps = nMaxSteps;
63 nSteps = std::max(sal_uInt32(1), nSteps);
65 switch(getFillGradient().getStyle())
67 case attribute::GradientStyle::Linear:
69 texture::GeoTexSvxGradientLinear aGradient(
70 getDefinitionRange(),
71 getOutputRange(),
72 aStart,
73 aEnd,
74 nSteps,
75 getFillGradient().getBorder(),
76 getFillGradient().getAngle());
77 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
78 break;
80 case attribute::GradientStyle::Axial:
82 texture::GeoTexSvxGradientAxial aGradient(
83 getDefinitionRange(),
84 getOutputRange(),
85 aStart,
86 aEnd,
87 nSteps,
88 getFillGradient().getBorder(),
89 getFillGradient().getAngle());
90 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
91 break;
93 case attribute::GradientStyle::Radial:
95 texture::GeoTexSvxGradientRadial aGradient(
96 getDefinitionRange(),
97 aStart,
98 aEnd,
99 nSteps,
100 getFillGradient().getBorder(),
101 getFillGradient().getOffsetX(),
102 getFillGradient().getOffsetY());
103 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
104 break;
106 case attribute::GradientStyle::Elliptical:
108 texture::GeoTexSvxGradientElliptical aGradient(
109 getDefinitionRange(),
110 aStart,
111 aEnd,
112 nSteps,
113 getFillGradient().getBorder(),
114 getFillGradient().getOffsetX(),
115 getFillGradient().getOffsetY(),
116 getFillGradient().getAngle());
117 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
118 break;
120 case attribute::GradientStyle::Square:
122 texture::GeoTexSvxGradientSquare aGradient(
123 getDefinitionRange(),
124 aStart,
125 aEnd,
126 nSteps,
127 getFillGradient().getBorder(),
128 getFillGradient().getOffsetX(),
129 getFillGradient().getOffsetY(),
130 getFillGradient().getAngle());
131 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
132 break;
134 case attribute::GradientStyle::Rect:
136 texture::GeoTexSvxGradientRect aGradient(
137 getDefinitionRange(),
138 aStart,
139 aEnd,
140 nSteps,
141 getFillGradient().getBorder(),
142 getFillGradient().getOffsetX(),
143 getFillGradient().getOffsetY(),
144 getFillGradient().getAngle());
145 aGradient.appendTransformationsAndColors(rEntries, rOuterColor);
146 break;
151 void FillGradientPrimitive2D::createOverlappingFill(
152 Primitive2DContainer& rContainer,
153 const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
154 const basegfx::BColor& rOuterColor,
155 const basegfx::B2DPolygon& rUnitPolygon) const
157 // create solid fill with outmost color
158 rContainer.push_back(
159 new PolyPolygonColorPrimitive2D(
160 basegfx::B2DPolyPolygon(
161 basegfx::utils::createPolygonFromRect(getOutputRange())),
162 rOuterColor));
164 // create solid fill steps
165 for(size_t a(0); a < rEntries.size(); a++)
167 // create part polygon
168 basegfx::B2DPolygon aNewPoly(rUnitPolygon);
170 aNewPoly.transform(rEntries[a].maB2DHomMatrix);
172 // create solid fill
173 rContainer.push_back(
174 new PolyPolygonColorPrimitive2D(
175 basegfx::B2DPolyPolygon(aNewPoly),
176 rEntries[a].maBColor));
180 void FillGradientPrimitive2D::createNonOverlappingFill(
181 Primitive2DContainer& rContainer,
182 const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
183 const basegfx::BColor& rOuterColor,
184 const basegfx::B2DPolygon& rUnitPolygon) const
186 // get outmost visible range from object
187 basegfx::B2DRange aOutmostRange(getOutputRange());
188 basegfx::B2DPolyPolygon aCombinedPolyPoly;
190 if(!rEntries.empty())
192 // extend aOutmostRange with first polygon
193 basegfx::B2DPolygon aFirstPoly(rUnitPolygon);
195 aFirstPoly.transform(rEntries[0].maB2DHomMatrix);
196 aCombinedPolyPoly.append(aFirstPoly);
197 aOutmostRange.expand(aFirstPoly.getB2DRange());
200 // add outmost range to combined polypolygon (in 1st place), create first primitive
201 aCombinedPolyPoly.insert(0, basegfx::utils::createPolygonFromRect(aOutmostRange));
202 rContainer.push_back(
203 new PolyPolygonColorPrimitive2D(
204 aCombinedPolyPoly,
205 rOuterColor));
207 if(!rEntries.empty())
209 // reuse first polygon, it's the second one
210 aCombinedPolyPoly.remove(0);
212 for(size_t a(0); a < rEntries.size() - 1; a++)
214 // create next inner polygon, combined with last one
215 basegfx::B2DPolygon aNextPoly(rUnitPolygon);
217 aNextPoly.transform(rEntries[a + 1].maB2DHomMatrix);
218 aCombinedPolyPoly.append(aNextPoly);
220 // create primitive with correct color
221 rContainer.push_back(
222 new PolyPolygonColorPrimitive2D(
223 aCombinedPolyPoly,
224 rEntries[a].maBColor));
226 // reuse inner polygon, it's the 2nd one
227 aCombinedPolyPoly.remove(0);
230 // add last inner polygon with last color
231 rContainer.push_back(
232 new PolyPolygonColorPrimitive2D(
233 aCombinedPolyPoly,
234 rEntries[rEntries.size() - 1].maBColor));
238 void FillGradientPrimitive2D::createFill(Primitive2DContainer& rContainer, bool bOverlapping) const
240 // prepare shape of the Unit Polygon
241 basegfx::B2DPolygon aUnitPolygon;
243 switch(getFillGradient().getStyle())
245 case attribute::GradientStyle::Radial:
246 case attribute::GradientStyle::Elliptical:
248 aUnitPolygon = basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0);
249 break;
251 default: // GradientStyle::Linear, attribute::GradientStyle::Axial, attribute::GradientStyle::Square, attribute::GradientStyle::Rect
253 aUnitPolygon = basegfx::utils::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0));
254 break;
258 // get the transform matrices and colors (where colors
259 // will have one more entry that matrices)
260 std::vector< drawinglayer::texture::B2DHomMatrixAndBColor > aEntries;
261 basegfx::BColor aOuterColor;
263 generateMatricesAndColors(aEntries, aOuterColor);
265 if(bOverlapping)
267 createOverlappingFill(rContainer, aEntries, aOuterColor, aUnitPolygon);
269 else
271 createNonOverlappingFill(rContainer, aEntries, aOuterColor, aUnitPolygon);
275 void FillGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
277 // default creates overlapping fill which works with AntiAliasing and without.
278 // The non-overlapping version does not create single filled polygons, but
279 // PolyPolygons where each one describes a 'ring' for the gradient such
280 // that the rings will not overlap. This is useful for the old XOR-paint
281 // 'trick' of VCL which is recorded in Metafiles; so this version may be
282 // used from the MetafilePrimitive2D in its decomposition.
284 if(!getFillGradient().isDefault())
286 createFill(rContainer, /*bOverlapping*/true);
290 FillGradientPrimitive2D::FillGradientPrimitive2D(
291 const basegfx::B2DRange& rOutputRange,
292 const attribute::FillGradientAttribute& rFillGradient)
293 : BufferedDecompositionPrimitive2D(),
294 maOutputRange(rOutputRange),
295 maDefinitionRange(rOutputRange),
296 maFillGradient(rFillGradient)
300 FillGradientPrimitive2D::FillGradientPrimitive2D(
301 const basegfx::B2DRange& rOutputRange,
302 const basegfx::B2DRange& rDefinitionRange,
303 const attribute::FillGradientAttribute& rFillGradient)
304 : BufferedDecompositionPrimitive2D(),
305 maOutputRange(rOutputRange),
306 maDefinitionRange(rDefinitionRange),
307 maFillGradient(rFillGradient)
311 bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
313 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
315 const FillGradientPrimitive2D& rCompare = static_cast<const FillGradientPrimitive2D&>(rPrimitive);
317 return (getOutputRange() == rCompare.getOutputRange()
318 && getDefinitionRange() == rCompare.getDefinitionRange()
319 && getFillGradient() == rCompare.getFillGradient());
322 return false;
325 basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
327 // return the geometrically visible area
328 return getOutputRange();
331 // provide unique ID
332 ImplPrimitive2DIDBlock(FillGradientPrimitive2D, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D)
334 } // end of namespace primitive2d
335 } // end of namespace drawinglayer
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */