tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / drawinglayer / source / primitive2d / fillgradientprimitive2d.cxx
blob8c2e339f8fbb719178c54644b6d93edf15868ab5
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 <texture/texture.hxx>
24 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
25 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
26 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
29 #include <utility>
30 #include <algorithm>
33 using namespace com::sun::star;
36 namespace drawinglayer::primitive2d
38 // Get the OuterColor. Take into account that for css::awt::GradientStyle_AXIAL
39 // this is the last one due to inverted gradient usage (see constructor there)
40 basegfx::BColor FillGradientPrimitive2D::getOuterColor() const
42 if (getFillGradient().getColorStops().empty())
43 return basegfx::BColor();
45 if (css::awt::GradientStyle_AXIAL == getFillGradient().getStyle())
46 return getFillGradient().getColorStops().back().getStopColor();
48 return getFillGradient().getColorStops().front().getStopColor();
51 // Get the needed UnitPolygon dependent on the GradientStyle
52 basegfx::B2DPolygon FillGradientPrimitive2D::getUnitPolygon() const
54 if (css::awt::GradientStyle_RADIAL == getFillGradient().getStyle()
55 || css::awt::GradientStyle_ELLIPTICAL == getFillGradient().getStyle())
57 return basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0);
60 return basegfx::utils::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0));
63 void FillGradientPrimitive2D::generateMatricesAndColors(
64 std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) const
66 switch(getFillGradient().getStyle())
68 default: // GradientStyle_MAKE_FIXED_SIZE
69 case css::awt::GradientStyle_LINEAR:
71 texture::GeoTexSvxGradientLinear aGradient(
72 getDefinitionRange(),
73 getOutputRange(),
74 getFillGradient().getSteps(),
75 getFillGradient().getColorStops(),
76 getFillGradient().getBorder(),
77 getFillGradient().getAngle());
78 aGradient.appendTransformationsAndColors(aCallback);
79 break;
81 case css::awt::GradientStyle_AXIAL:
83 texture::GeoTexSvxGradientAxial aGradient(
84 getDefinitionRange(),
85 getOutputRange(),
86 getFillGradient().getSteps(),
87 getFillGradient().getColorStops(),
88 getFillGradient().getBorder(),
89 getFillGradient().getAngle());
90 aGradient.appendTransformationsAndColors(aCallback);
91 break;
93 case css::awt::GradientStyle_RADIAL:
95 texture::GeoTexSvxGradientRadial aGradient(
96 getDefinitionRange(),
97 getFillGradient().getSteps(),
98 getFillGradient().getColorStops(),
99 getFillGradient().getBorder(),
100 getFillGradient().getOffsetX(),
101 getFillGradient().getOffsetY());
102 aGradient.appendTransformationsAndColors(aCallback);
103 break;
105 case css::awt::GradientStyle_ELLIPTICAL:
107 texture::GeoTexSvxGradientElliptical aGradient(
108 getDefinitionRange(),
109 getFillGradient().getSteps(),
110 getFillGradient().getColorStops(),
111 getFillGradient().getBorder(),
112 getFillGradient().getOffsetX(),
113 getFillGradient().getOffsetY(),
114 getFillGradient().getAngle());
115 aGradient.appendTransformationsAndColors(aCallback);
116 break;
118 case css::awt::GradientStyle_SQUARE:
120 texture::GeoTexSvxGradientSquare aGradient(
121 getDefinitionRange(),
122 getFillGradient().getSteps(),
123 getFillGradient().getColorStops(),
124 getFillGradient().getBorder(),
125 getFillGradient().getOffsetX(),
126 getFillGradient().getOffsetY(),
127 getFillGradient().getAngle());
128 aGradient.appendTransformationsAndColors(aCallback);
129 break;
131 case css::awt::GradientStyle_RECT:
133 texture::GeoTexSvxGradientRect aGradient(
134 getDefinitionRange(),
135 getFillGradient().getSteps(),
136 getFillGradient().getColorStops(),
137 getFillGradient().getBorder(),
138 getFillGradient().getOffsetX(),
139 getFillGradient().getOffsetY(),
140 getFillGradient().getAngle());
141 aGradient.appendTransformationsAndColors(aCallback);
142 break;
147 Primitive2DReference FillGradientPrimitive2D::createFill(bool bOverlapping) const
149 Primitive2DContainer aContainer;
150 if (bOverlapping)
152 // OverlappingFill: create solid fill with outmost color
153 aContainer.push_back(
154 new PolyPolygonColorPrimitive2D(
155 basegfx::B2DPolyPolygon(
156 basegfx::utils::createPolygonFromRect(getOutputRange())),
157 getOuterColor()));
159 // create solid fill steps by providing callback as lambda
160 auto aCallback([&aContainer,this](
161 const basegfx::B2DHomMatrix& rMatrix,
162 const basegfx::BColor& rColor)
164 // create part polygon
165 basegfx::B2DPolygon aNewPoly(getUnitPolygon());
166 aNewPoly.transform(rMatrix);
168 // create solid fill
169 aContainer.push_back(
170 new PolyPolygonColorPrimitive2D(
171 basegfx::B2DPolyPolygon(aNewPoly),
172 rColor));
175 // call value generator to trigger callbacks
176 generateMatricesAndColors(aCallback);
178 else
180 // NonOverlappingFill
181 if (getFillGradient().getColorStops().size() < 2)
183 // not really a gradient, we need to create a start primitive
184 // entry using the single color and the covered area
185 const basegfx::B2DRange aOutmostRange(getOutputRange());
186 aContainer.push_back(
187 new PolyPolygonColorPrimitive2D(
188 basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aOutmostRange)),
189 getOuterColor()));
191 else
193 // gradient with stops, prepare CombinedPolyPoly, use callback
194 basegfx::B2DPolyPolygon aCombinedPolyPoly;
195 basegfx::BColor aLastColor;
197 auto aCallback([&aContainer,&aCombinedPolyPoly,&aLastColor,this](
198 const basegfx::B2DHomMatrix& rMatrix,
199 const basegfx::BColor& rColor)
201 if (aContainer.empty())
203 // 1st callback, init CombinedPolyPoly & create 1st entry
204 basegfx::B2DRange aOutmostRange(getOutputRange());
206 // expand aOutmostRange with transformed first polygon
207 // to ensure confinement
208 basegfx::B2DPolygon aFirstPoly(getUnitPolygon());
209 aFirstPoly.transform(rMatrix);
210 aOutmostRange.expand(aFirstPoly.getB2DRange());
212 // build 1st combined polygon; outmost range 1st, then
213 // the shaped, transformed polygon
214 aCombinedPolyPoly.append(basegfx::utils::createPolygonFromRect(aOutmostRange));
215 aCombinedPolyPoly.append(aFirstPoly);
217 // create first primitive
218 aContainer.push_back(
219 new PolyPolygonColorPrimitive2D(
220 aCombinedPolyPoly,
221 getOuterColor()));
223 // save first polygon for re-use in next call, it's the second
224 // one, so remove 1st
225 aCombinedPolyPoly.remove(0);
227 // remember color for next primitive creation
228 aLastColor = rColor;
230 else
232 // regular n-th callback, create combined entry by re-using
233 // CombinedPolyPoly and aLastColor
234 basegfx::B2DPolygon aNextPoly(getUnitPolygon());
235 aNextPoly.transform(rMatrix);
236 aCombinedPolyPoly.append(aNextPoly);
238 // create primitive with correct color
239 aContainer.push_back(
240 new PolyPolygonColorPrimitive2D(
241 aCombinedPolyPoly,
242 aLastColor));
244 // prepare re-use of inner polygon, save color
245 aCombinedPolyPoly.remove(0);
246 aLastColor = rColor;
250 // call value generator to trigger callbacks
251 generateMatricesAndColors(aCallback);
253 // add last inner polygon with last color
254 aContainer.push_back(
255 new PolyPolygonColorPrimitive2D(
256 std::move(aCombinedPolyPoly),
257 aLastColor));
260 return new GroupPrimitive2D(std::move(aContainer));
263 Primitive2DReference FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
265 // SDPR: support alpha directly now. If a primitive processor
266 // cannot deal with it, use it's decomposition. For that purpose
267 // this decomposition has two stages now: This 1st one will
268 // (if needed) separate content and alpha into a TransparencePrimitive2D
269 // and (if needed) embed that to a UnifiedTransparencePrimitive2D,
270 // so all processors can work as before
271 if (hasAlphaGradient() || hasTransparency())
273 Primitive2DReference aRetval(
274 new FillGradientPrimitive2D(
275 getOutputRange(),
276 getDefinitionRange(),
277 getFillGradient()));
279 if (hasAlphaGradient())
281 Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
282 getOutputRange(),
283 getDefinitionRange(),
284 getAlphaGradient()) };
286 aRetval = new TransparencePrimitive2D(Primitive2DContainer{ aRetval }, std::move(aAlpha));
289 if (hasTransparency())
291 aRetval = new UnifiedTransparencePrimitive2D(Primitive2DContainer{ aRetval }, getTransparency());
294 return aRetval;
297 // default creates overlapping fill which works with AntiAliasing and without.
298 // The non-overlapping version does not create single filled polygons, but
299 // PolyPolygons where each one describes a 'ring' for the gradient such
300 // that the rings will not overlap. This is useful for the old XOR-paint
301 // 'trick' of VCL which is recorded in Metafiles; so this version may be
302 // used from the MetafilePrimitive2D in its decomposition.
303 if(!getFillGradient().isDefault())
305 return createFill(/*bOverlapping*/true);
308 return nullptr;
311 FillGradientPrimitive2D::FillGradientPrimitive2D(
312 const basegfx::B2DRange& rOutputRange,
313 const attribute::FillGradientAttribute& rFillGradient)
314 : maOutputRange(rOutputRange)
315 , maDefinitionRange(rOutputRange)
316 , maFillGradient(rFillGradient)
317 , maAlphaGradient()
318 , mfTransparency(0.0)
322 FillGradientPrimitive2D::FillGradientPrimitive2D(
323 const basegfx::B2DRange& rOutputRange,
324 const basegfx::B2DRange& rDefinitionRange,
325 const attribute::FillGradientAttribute& rFillGradient,
326 const attribute::FillGradientAttribute* pAlphaGradient,
327 double fTransparency)
328 : maOutputRange(rOutputRange)
329 , maDefinitionRange(rDefinitionRange)
330 , maFillGradient(rFillGradient)
331 , maAlphaGradient()
332 , mfTransparency(fTransparency)
334 // copy alpha gradient if we got one
335 if (nullptr != pAlphaGradient)
336 maAlphaGradient = *pAlphaGradient;
339 bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
341 if(!BufferedDecompositionPrimitive2D::operator==(rPrimitive))
342 return false;
344 const FillGradientPrimitive2D& rCompare(static_cast<const FillGradientPrimitive2D&>(rPrimitive));
346 if (getOutputRange() != rCompare.getOutputRange())
347 return false;
349 if (getDefinitionRange() != rCompare.getDefinitionRange())
350 return false;
352 if (getFillGradient() != rCompare.getFillGradient())
353 return false;
355 if (maAlphaGradient != rCompare.maAlphaGradient)
356 return false;
358 if (!basegfx::fTools::equal(getTransparency(), rCompare.getTransparency()))
359 return false;
361 return true;
364 basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
366 // return the geometrically visible area
367 return getOutputRange();
370 // provide unique ID
371 sal_uInt32 FillGradientPrimitive2D::getPrimitive2DID() const
373 return PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D;
376 } // end of namespace
378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */