1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
36 void FillGradientPrimitive2D::generateMatricesAndColors(
37 std::vector
< drawinglayer::texture::B2DHomMatrixAndBColor
>& rEntries
,
38 basegfx::BColor
& rOuterColor
) const
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());
58 if(nSteps
> nMaxSteps
)
63 nSteps
= std::max(sal_uInt32(1), nSteps
);
65 switch(getFillGradient().getStyle())
67 case attribute::GradientStyle::Linear
:
69 texture::GeoTexSvxGradientLinear
aGradient(
75 getFillGradient().getBorder(),
76 getFillGradient().getAngle());
77 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
80 case attribute::GradientStyle::Axial
:
82 texture::GeoTexSvxGradientAxial
aGradient(
88 getFillGradient().getBorder(),
89 getFillGradient().getAngle());
90 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
93 case attribute::GradientStyle::Radial
:
95 texture::GeoTexSvxGradientRadial
aGradient(
100 getFillGradient().getBorder(),
101 getFillGradient().getOffsetX(),
102 getFillGradient().getOffsetY());
103 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
106 case attribute::GradientStyle::Elliptical
:
108 texture::GeoTexSvxGradientElliptical
aGradient(
109 getDefinitionRange(),
113 getFillGradient().getBorder(),
114 getFillGradient().getOffsetX(),
115 getFillGradient().getOffsetY(),
116 getFillGradient().getAngle());
117 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
120 case attribute::GradientStyle::Square
:
122 texture::GeoTexSvxGradientSquare
aGradient(
123 getDefinitionRange(),
127 getFillGradient().getBorder(),
128 getFillGradient().getOffsetX(),
129 getFillGradient().getOffsetY(),
130 getFillGradient().getAngle());
131 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
134 case attribute::GradientStyle::Rect
:
136 texture::GeoTexSvxGradientRect
aGradient(
137 getDefinitionRange(),
141 getFillGradient().getBorder(),
142 getFillGradient().getOffsetX(),
143 getFillGradient().getOffsetY(),
144 getFillGradient().getAngle());
145 aGradient
.appendTransformationsAndColors(rEntries
, rOuterColor
);
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())),
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
);
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(
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(
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(
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);
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));
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
);
267 createOverlappingFill(rContainer
, aEntries
, aOuterColor
, aUnitPolygon
);
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());
325 basegfx::B2DRange
FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D
& /*rViewInformation*/) const
327 // return the geometrically visible area
328 return getOutputRange();
332 ImplPrimitive2DIDBlock(FillGradientPrimitive2D
, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D
)
334 } // end of namespace primitive2d
335 } // end of namespace drawinglayer
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */