LibreOffice Module drawinglayer (master) 1
fillgradientprimitive2d.cxx
Go to the documentation of this file.
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
23#include <texture/texture.hxx>
26#include <utility>
27#include <algorithm>
28
29
30using namespace com::sun::star;
31
32
34{
35 // Get the OuterColor. Take into account that for css::awt::GradientStyle_AXIAL
36 // this is the last one due to inverted gradient usage (see constructor there)
38 {
39 if (getFillGradient().getColorStops().empty())
40 return basegfx::BColor();
41
42 if (css::awt::GradientStyle_AXIAL == getFillGradient().getStyle())
43 return getFillGradient().getColorStops().back().getStopColor();
44
45 return getFillGradient().getColorStops().front().getStopColor();
46 }
47
48 // Get the needed UnitPolygon dependent on the GradientStyle
50 {
51 if (css::awt::GradientStyle_RADIAL == getFillGradient().getStyle()
52 || css::awt::GradientStyle_ELLIPTICAL == getFillGradient().getStyle())
53 {
55 }
56
57 return basegfx::utils::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0));
58 }
59
61 std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) const
62 {
63 switch(getFillGradient().getStyle())
64 {
65 default: // GradientStyle_MAKE_FIXED_SIZE
66 case css::awt::GradientStyle_LINEAR:
67 {
71 getFillGradient().getSteps(),
72 getFillGradient().getColorStops(),
73 getFillGradient().getBorder(),
74 getFillGradient().getAngle());
75 aGradient.appendTransformationsAndColors(aCallback);
76 break;
77 }
78 case css::awt::GradientStyle_AXIAL:
79 {
83 getFillGradient().getSteps(),
84 getFillGradient().getColorStops(),
85 getFillGradient().getBorder(),
86 getFillGradient().getAngle());
87 aGradient.appendTransformationsAndColors(aCallback);
88 break;
89 }
90 case css::awt::GradientStyle_RADIAL:
91 {
94 getFillGradient().getSteps(),
95 getFillGradient().getColorStops(),
96 getFillGradient().getBorder(),
97 getFillGradient().getOffsetX(),
98 getFillGradient().getOffsetY());
99 aGradient.appendTransformationsAndColors(aCallback);
100 break;
101 }
102 case css::awt::GradientStyle_ELLIPTICAL:
103 {
106 getFillGradient().getSteps(),
107 getFillGradient().getColorStops(),
108 getFillGradient().getBorder(),
109 getFillGradient().getOffsetX(),
110 getFillGradient().getOffsetY(),
111 getFillGradient().getAngle());
112 aGradient.appendTransformationsAndColors(aCallback);
113 break;
114 }
115 case css::awt::GradientStyle_SQUARE:
116 {
119 getFillGradient().getSteps(),
120 getFillGradient().getColorStops(),
121 getFillGradient().getBorder(),
122 getFillGradient().getOffsetX(),
123 getFillGradient().getOffsetY(),
124 getFillGradient().getAngle());
125 aGradient.appendTransformationsAndColors(aCallback);
126 break;
127 }
128 case css::awt::GradientStyle_RECT:
129 {
132 getFillGradient().getSteps(),
133 getFillGradient().getColorStops(),
134 getFillGradient().getBorder(),
135 getFillGradient().getOffsetX(),
136 getFillGradient().getOffsetY(),
137 getFillGradient().getAngle());
138 aGradient.appendTransformationsAndColors(aCallback);
139 break;
140 }
141 }
142 }
143
144 void FillGradientPrimitive2D::createFill(Primitive2DContainer& rContainer, bool bOverlapping) const
145 {
146 if (bOverlapping)
147 {
148 // OverlappingFill: create solid fill with outmost color
149 rContainer.push_back(
153 getOuterColor()));
154
155 // create solid fill steps by providing callback as lambda
156 auto aCallback([&rContainer,this](
157 const basegfx::B2DHomMatrix& rMatrix,
158 const basegfx::BColor& rColor)
159 {
160 // create part polygon
162 aNewPoly.transform(rMatrix);
163
164 // create solid fill
165 rContainer.push_back(
167 basegfx::B2DPolyPolygon(aNewPoly),
168 rColor));
169 });
170
171 // call value generator to trigger callbacks
172 generateMatricesAndColors(aCallback);
173 }
174 else
175 {
176 // NonOverlappingFill
177 if (getFillGradient().getColorStops().size() < 2)
178 {
179 // not really a gradient, we need to create a start primitive
180 // entry using the single color and the covered area
181 const basegfx::B2DRange aOutmostRange(getOutputRange());
182 rContainer.push_back(
185 getOuterColor()));
186 }
187 else
188 {
189 // gradient with stops, prepare CombinedPolyPoly, use callback
190 basegfx::B2DPolyPolygon aCombinedPolyPoly;
191 basegfx::BColor aLastColor;
192
193 auto aCallback([&rContainer,&aCombinedPolyPoly,&aLastColor,this](
194 const basegfx::B2DHomMatrix& rMatrix,
195 const basegfx::BColor& rColor)
196 {
197 if (rContainer.empty())
198 {
199 // 1st callback, init CombinedPolyPoly & create 1st entry
200 basegfx::B2DRange aOutmostRange(getOutputRange());
201
202 // expand aOutmostRange with transformed first polygon
203 // to ensure confinement
204 basegfx::B2DPolygon aFirstPoly(getUnitPolygon());
205 aFirstPoly.transform(rMatrix);
206 aOutmostRange.expand(aFirstPoly.getB2DRange());
207
208 // build 1st combined polygon; outmost range 1st, then
209 // the shaped, transformed polygon
210 aCombinedPolyPoly.append(basegfx::utils::createPolygonFromRect(aOutmostRange));
211 aCombinedPolyPoly.append(aFirstPoly);
212
213 // create first primitive
214 rContainer.push_back(
215 new PolyPolygonColorPrimitive2D(
216 aCombinedPolyPoly,
217 getOuterColor()));
218
219 // save first polygon for re-use in next call, it's the second
220 // one, so remove 1st
221 aCombinedPolyPoly.remove(0);
222
223 // remember color for next primitive creation
224 aLastColor = rColor;
225 }
226 else
227 {
228 // regular n-th callback, create combined entry by re-using
229 // CombinedPolyPoly and aLastColor
230 basegfx::B2DPolygon aNextPoly(getUnitPolygon());
231 aNextPoly.transform(rMatrix);
232 aCombinedPolyPoly.append(aNextPoly);
233
234 // create primitive with correct color
235 rContainer.push_back(
236 new PolyPolygonColorPrimitive2D(
237 aCombinedPolyPoly,
238 aLastColor));
239
240 // prepare re-use of inner polygon, save color
241 aCombinedPolyPoly.remove(0);
242 aLastColor = rColor;
243 }
244 });
245
246 // call value generator to trigger callbacks
247 generateMatricesAndColors(aCallback);
248
249 // add last inner polygon with last color
250 rContainer.push_back(
252 aCombinedPolyPoly,
253 aLastColor));
254 }
255 }
256 }
257
259 {
260 // default creates overlapping fill which works with AntiAliasing and without.
261 // The non-overlapping version does not create single filled polygons, but
262 // PolyPolygons where each one describes a 'ring' for the gradient such
263 // that the rings will not overlap. This is useful for the old XOR-paint
264 // 'trick' of VCL which is recorded in Metafiles; so this version may be
265 // used from the MetafilePrimitive2D in its decomposition.
266
267 if(!getFillGradient().isDefault())
268 {
269 createFill(rContainer, /*bOverlapping*/true);
270 }
271 }
272
274 const basegfx::B2DRange& rOutputRange,
276 : maOutputRange(rOutputRange),
277 maDefinitionRange(rOutputRange),
278 maFillGradient(std::move(aFillGradient))
279 {
280 }
281
283 const basegfx::B2DRange& rOutputRange,
284 const basegfx::B2DRange& rDefinitionRange,
286 : maOutputRange(rOutputRange),
287 maDefinitionRange(rDefinitionRange),
288 maFillGradient(std::move(aFillGradient))
289 {
290 }
291
293 {
294 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
295 {
296 const FillGradientPrimitive2D& rCompare = static_cast<const FillGradientPrimitive2D&>(rPrimitive);
297
298 return (getOutputRange() == rCompare.getOutputRange()
299 && getDefinitionRange() == rCompare.getDefinitionRange()
300 && getFillGradient() == rCompare.getFillGradient());
301 }
302
303 return false;
304 }
305
307 {
308 // return the geometrically visible area
309 return getOutputRange();
310 }
311
312 // provide unique ID
314 {
316 }
317
318} // end of namespace
319
320/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void transform(const basegfx::B2DHomMatrix &rMatrix)
const basegfx::BColorStops & getColorStops() const
basegfx::B2DPolygon getUnitPolygon() const
helpers that support e.g. direct paint/geometry creation
void createFill(Primitive2DContainer &rContainer, bool bOverlapping) const
local helper
virtual void create2DDecomposition(Primitive2DContainer &rContainer, const geometry::ViewInformation2D &rViewInformation) const override
local decomposition.
const basegfx::B2DRange & getOutputRange() const
data read access
const attribute::FillGradientAttribute & getFillGradient() const
virtual bool operator==(const BasePrimitive2D &rPrimitive) const override
compare operator
virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D &rViewInformation) const override
get range
FillGradientPrimitive2D(const basegfx::B2DRange &rOutputRange, attribute::FillGradientAttribute aFillGradient)
constructors. The one without definition range will use output range as definition range
void generateMatricesAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) const
virtual sal_uInt32 getPrimitive2DID() const override
provide unique ID
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:287
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:510
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:135
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:407
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:723
virtual void appendTransformationsAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) override
Definition: texture.cxx:620
#define PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolygon createPolygonFromCircle(const B2DPoint &rCenter, double fRadius)
size