xref: /AOO41X/main/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx (revision 96fc4b33382e706b7361f08aba6c96207eedf10a)
1464702f4SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3464702f4SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4464702f4SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5464702f4SAndrew Rist  * distributed with this work for additional information
6464702f4SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7464702f4SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8464702f4SAndrew Rist  * "License"); you may not use this file except in compliance
9464702f4SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11464702f4SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13464702f4SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14464702f4SAndrew Rist  * software distributed under the License is distributed on an
15464702f4SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16464702f4SAndrew Rist  * KIND, either express or implied.  See the License for the
17464702f4SAndrew Rist  * specific language governing permissions and limitations
18464702f4SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20464702f4SAndrew Rist  *************************************************************/
21464702f4SAndrew Rist 
22464702f4SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
28cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
29cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
30cdf0e10cSrcweir #include <drawinglayer/texture/texture.hxx>
31cdf0e10cSrcweir #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
32cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
33cdf0e10cSrcweir #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
34cdf0e10cSrcweir 
35cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
36cdf0e10cSrcweir 
37cdf0e10cSrcweir using namespace com::sun::star;
38cdf0e10cSrcweir 
39cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
40cdf0e10cSrcweir 
41cdf0e10cSrcweir namespace drawinglayer
42cdf0e10cSrcweir {
43cdf0e10cSrcweir 	namespace primitive2d
44cdf0e10cSrcweir 	{
generateMatricesAndColors(std::vector<drawinglayer::texture::B2DHomMatrixAndBColor> & rEntries,basegfx::BColor & rOutmostColor) const45cdf0e10cSrcweir         void FillGradientPrimitive2D::generateMatricesAndColors(
46*96fc4b33SArmin Le Grand             std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
47*96fc4b33SArmin Le Grand             basegfx::BColor& rOutmostColor) const
48cdf0e10cSrcweir         {
49*96fc4b33SArmin Le Grand             rEntries.clear();
50cdf0e10cSrcweir 
51cdf0e10cSrcweir 			// make sure steps is not too high/low
52cdf0e10cSrcweir 			const basegfx::BColor aStart(getFillGradient().getStartColor());
53cdf0e10cSrcweir 			const basegfx::BColor aEnd(getFillGradient().getEndColor());
54cdf0e10cSrcweir 			const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
55cdf0e10cSrcweir 			sal_uInt32 nSteps(getFillGradient().getSteps());
56cdf0e10cSrcweir 
57cdf0e10cSrcweir 			if(nSteps == 0)
58cdf0e10cSrcweir 			{
59cdf0e10cSrcweir 				nSteps = nMaxSteps;
60cdf0e10cSrcweir 			}
61cdf0e10cSrcweir 
62cdf0e10cSrcweir 			if(nSteps < 2)
63cdf0e10cSrcweir 			{
64cdf0e10cSrcweir 				nSteps = 2;
65cdf0e10cSrcweir 			}
66cdf0e10cSrcweir 
67cdf0e10cSrcweir 			if(nSteps > nMaxSteps)
68cdf0e10cSrcweir 			{
69cdf0e10cSrcweir 				nSteps = nMaxSteps;
70cdf0e10cSrcweir 			}
71cdf0e10cSrcweir 
72cdf0e10cSrcweir 			switch(getFillGradient().getStyle())
73cdf0e10cSrcweir 			{
74cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_LINEAR:
75cdf0e10cSrcweir 				{
76cdf0e10cSrcweir 					texture::GeoTexSvxGradientLinear aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
77*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
78cdf0e10cSrcweir 					break;
79cdf0e10cSrcweir 				}
80cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_AXIAL:
81cdf0e10cSrcweir 				{
82cdf0e10cSrcweir 					texture::GeoTexSvxGradientAxial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
83*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
84cdf0e10cSrcweir 					break;
85cdf0e10cSrcweir 				}
86cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_RADIAL:
87cdf0e10cSrcweir 				{
88cdf0e10cSrcweir 					texture::GeoTexSvxGradientRadial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY());
89*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
90cdf0e10cSrcweir 					break;
91cdf0e10cSrcweir 				}
92cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_ELLIPTICAL:
93cdf0e10cSrcweir 				{
94cdf0e10cSrcweir 					texture::GeoTexSvxGradientElliptical aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
95*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
96cdf0e10cSrcweir 					break;
97cdf0e10cSrcweir 				}
98cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_SQUARE:
99cdf0e10cSrcweir 				{
100cdf0e10cSrcweir 					texture::GeoTexSvxGradientSquare aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
101*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
102cdf0e10cSrcweir 					break;
103cdf0e10cSrcweir 				}
104cdf0e10cSrcweir 				case attribute::GRADIENTSTYLE_RECT:
105cdf0e10cSrcweir 				{
106cdf0e10cSrcweir 					texture::GeoTexSvxGradientRect aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
107*96fc4b33SArmin Le Grand 					aGradient.appendTransformationsAndColors(rEntries, rOutmostColor);
108cdf0e10cSrcweir 					break;
109cdf0e10cSrcweir 				}
110cdf0e10cSrcweir 			}
111cdf0e10cSrcweir         }
112cdf0e10cSrcweir 
createOverlappingFill(const std::vector<drawinglayer::texture::B2DHomMatrixAndBColor> & rEntries,const basegfx::BColor & rOutmostColor,const basegfx::B2DPolygon & rUnitPolygon) const113cdf0e10cSrcweir         Primitive2DSequence FillGradientPrimitive2D::createOverlappingFill(
114*96fc4b33SArmin Le Grand             const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
115*96fc4b33SArmin Le Grand             const basegfx::BColor& rOutmostColor,
116cdf0e10cSrcweir             const basegfx::B2DPolygon& rUnitPolygon) const
117cdf0e10cSrcweir         {
118cdf0e10cSrcweir             // prepare return value
119*96fc4b33SArmin Le Grand             Primitive2DSequence aRetval(rEntries.size() + 1);
120cdf0e10cSrcweir 
121*96fc4b33SArmin Le Grand             // create solid fill with outmost color
122*96fc4b33SArmin Le Grand             aRetval[0] = Primitive2DReference(
123cdf0e10cSrcweir                 new PolyPolygonColorPrimitive2D(
124cdf0e10cSrcweir                     basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(getObjectRange())),
125*96fc4b33SArmin Le Grand                     rOutmostColor));
126cdf0e10cSrcweir 
127cdf0e10cSrcweir             // create solid fill steps
128*96fc4b33SArmin Le Grand             for(sal_uInt32 a(0); a < rEntries.size(); a++)
129cdf0e10cSrcweir             {
130cdf0e10cSrcweir                 // create part polygon
131cdf0e10cSrcweir                 basegfx::B2DPolygon aNewPoly(rUnitPolygon);
132*96fc4b33SArmin Le Grand 
133*96fc4b33SArmin Le Grand                 aNewPoly.transform(rEntries[a].maB2DHomMatrix);
134cdf0e10cSrcweir 
135cdf0e10cSrcweir                 // create solid fill
136*96fc4b33SArmin Le Grand                 aRetval[a + 1] = Primitive2DReference(
137cdf0e10cSrcweir                     new PolyPolygonColorPrimitive2D(
138cdf0e10cSrcweir                         basegfx::B2DPolyPolygon(aNewPoly),
139*96fc4b33SArmin Le Grand                         rEntries[a].maBColor));
140cdf0e10cSrcweir             }
141cdf0e10cSrcweir 
142cdf0e10cSrcweir             return aRetval;
143cdf0e10cSrcweir         }
144cdf0e10cSrcweir 
createNonOverlappingFill(const std::vector<drawinglayer::texture::B2DHomMatrixAndBColor> & rEntries,const basegfx::BColor & rOutmostColor,const basegfx::B2DPolygon & rUnitPolygon) const145cdf0e10cSrcweir         Primitive2DSequence FillGradientPrimitive2D::createNonOverlappingFill(
146*96fc4b33SArmin Le Grand             const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries,
147*96fc4b33SArmin Le Grand             const basegfx::BColor& rOutmostColor,
148cdf0e10cSrcweir             const basegfx::B2DPolygon& rUnitPolygon) const
149cdf0e10cSrcweir         {
150cdf0e10cSrcweir             // prepare return value
151*96fc4b33SArmin Le Grand             Primitive2DSequence aRetval(rEntries.size() + 1);
152cdf0e10cSrcweir 
153*96fc4b33SArmin Le Grand             // get outmost range from object
154*96fc4b33SArmin Le Grand             basegfx::B2DRange aOutmostRange(getObjectRange());
155*96fc4b33SArmin Le Grand             basegfx::B2DPolyPolygon aCombinedPolyPoly;
156*96fc4b33SArmin Le Grand 
157*96fc4b33SArmin Le Grand             if(rEntries.size())
158cdf0e10cSrcweir             {
159*96fc4b33SArmin Le Grand                 // extend aOutmostRange with first polygon
160*96fc4b33SArmin Le Grand                 basegfx::B2DPolygon aFirstPoly(rUnitPolygon);
161cdf0e10cSrcweir 
162*96fc4b33SArmin Le Grand                 aFirstPoly.transform(rEntries[0].maB2DHomMatrix);
163*96fc4b33SArmin Le Grand                 aCombinedPolyPoly.append(aFirstPoly);
164*96fc4b33SArmin Le Grand                 aOutmostRange.expand(aFirstPoly.getB2DRange());
165cdf0e10cSrcweir             }
166cdf0e10cSrcweir 
167*96fc4b33SArmin Le Grand             // add outmost range to combined polypolygon (in 1st place), create first primitive
168*96fc4b33SArmin Le Grand             aCombinedPolyPoly.insert(0, basegfx::tools::createPolygonFromRect(aOutmostRange));
169*96fc4b33SArmin Le Grand             aRetval[0] = Primitive2DReference(
170*96fc4b33SArmin Le Grand                 new PolyPolygonColorPrimitive2D(
171*96fc4b33SArmin Le Grand                     aCombinedPolyPoly,
172*96fc4b33SArmin Le Grand                     rOutmostColor));
173*96fc4b33SArmin Le Grand 
174*96fc4b33SArmin Le Grand             if(rEntries.size())
175cdf0e10cSrcweir             {
176*96fc4b33SArmin Le Grand                 // reuse first polygon, it's the second one
177*96fc4b33SArmin Le Grand                 aCombinedPolyPoly.remove(0);
178*96fc4b33SArmin Le Grand 
179*96fc4b33SArmin Le Grand                 for(sal_uInt32 a(0); a < rEntries.size() - 1; a++)
180*96fc4b33SArmin Le Grand                 {
181*96fc4b33SArmin Le Grand                     // create next inner polygon, combinbe with last one
182*96fc4b33SArmin Le Grand                     basegfx::B2DPolygon aNextPoly(rUnitPolygon);
183*96fc4b33SArmin Le Grand 
184*96fc4b33SArmin Le Grand                     aNextPoly.transform(rEntries[a + 1].maB2DHomMatrix);
185*96fc4b33SArmin Le Grand                     aCombinedPolyPoly.append(aNextPoly);
186*96fc4b33SArmin Le Grand 
187*96fc4b33SArmin Le Grand                     // create primitive with correct color
188*96fc4b33SArmin Le Grand                     aRetval[a + 1] = Primitive2DReference(
189*96fc4b33SArmin Le Grand                         new PolyPolygonColorPrimitive2D(
190*96fc4b33SArmin Le Grand                             aCombinedPolyPoly,
191*96fc4b33SArmin Le Grand                             rEntries[a].maBColor));
192*96fc4b33SArmin Le Grand 
193*96fc4b33SArmin Le Grand                     // reuse inner polygon, it's the 2nd one
194*96fc4b33SArmin Le Grand                     aCombinedPolyPoly.remove(0);
195cdf0e10cSrcweir                 }
196cdf0e10cSrcweir 
197*96fc4b33SArmin Le Grand                 // add last inner polygon with last color
198*96fc4b33SArmin Le Grand                 aRetval[rEntries.size()] = Primitive2DReference(
199*96fc4b33SArmin Le Grand                     new PolyPolygonColorPrimitive2D(
200*96fc4b33SArmin Le Grand                         aCombinedPolyPoly,
201*96fc4b33SArmin Le Grand                         rEntries[rEntries.size() - 1].maBColor));
202cdf0e10cSrcweir             }
203cdf0e10cSrcweir 
204cdf0e10cSrcweir             return aRetval;
205cdf0e10cSrcweir         }
206cdf0e10cSrcweir 
createFill(bool bOverlapping) const207cdf0e10cSrcweir 		Primitive2DSequence FillGradientPrimitive2D::createFill(bool bOverlapping) const
208cdf0e10cSrcweir 		{
209cdf0e10cSrcweir             // prepare shape of the Unit Polygon
210cdf0e10cSrcweir 			basegfx::B2DPolygon aUnitPolygon;
211cdf0e10cSrcweir 
212*96fc4b33SArmin Le Grand             switch(getFillGradient().getStyle())
213cdf0e10cSrcweir             {
214*96fc4b33SArmin Le Grand                 case attribute::GRADIENTSTYLE_RADIAL:
215*96fc4b33SArmin Le Grand                 case attribute::GRADIENTSTYLE_ELLIPTICAL:
216*96fc4b33SArmin Le Grand                 {
217*96fc4b33SArmin Le Grand                     aUnitPolygon = basegfx::tools::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0);
218*96fc4b33SArmin Le Grand                     break;
219cdf0e10cSrcweir                 }
220*96fc4b33SArmin Le Grand                 default: // GRADIENTSTYLE_LINEAR, attribute::GRADIENTSTYLE_AXIAL, attribute::GRADIENTSTYLE_SQUARE, attribute::GRADIENTSTYLE_RECT
221cdf0e10cSrcweir                 {
222*96fc4b33SArmin Le Grand                     aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0));
223*96fc4b33SArmin Le Grand                     break;
224cdf0e10cSrcweir                 }
225cdf0e10cSrcweir             }
226cdf0e10cSrcweir 
227cdf0e10cSrcweir             // get the transform matrices and colors (where colors
228cdf0e10cSrcweir             // will have one more entry that matrices)
229*96fc4b33SArmin Le Grand             std::vector< drawinglayer::texture::B2DHomMatrixAndBColor > aEntries;
230*96fc4b33SArmin Le Grand             basegfx::BColor aOutmostColor;
231*96fc4b33SArmin Le Grand 
232*96fc4b33SArmin Le Grand             generateMatricesAndColors(aEntries, aOutmostColor);
233cdf0e10cSrcweir 
234cdf0e10cSrcweir             if(bOverlapping)
235cdf0e10cSrcweir             {
236*96fc4b33SArmin Le Grand                 return createOverlappingFill(aEntries, aOutmostColor, aUnitPolygon);
237cdf0e10cSrcweir             }
238cdf0e10cSrcweir             else
239cdf0e10cSrcweir             {
240*96fc4b33SArmin Le Grand                 return createNonOverlappingFill(aEntries, aOutmostColor, aUnitPolygon);
241cdf0e10cSrcweir             }
242cdf0e10cSrcweir         }
243cdf0e10cSrcweir 
create2DDecomposition(const geometry::ViewInformation2D &) const244cdf0e10cSrcweir 		Primitive2DSequence FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
245cdf0e10cSrcweir 		{
246cdf0e10cSrcweir             // default creates overlapping fill which works with AntiAliasing and without.
247cdf0e10cSrcweir             // The non-overlapping version does not create single filled polygons, but
248cdf0e10cSrcweir             // PolyPolygons where each one describes a 'ring' for the gradient such
249cdf0e10cSrcweir             // that the rings will not overlap. This is useful fir the old XOR-paint
250cdf0e10cSrcweir             // 'trick' of VCL which is recorded in Metafiles; so this version may be
251cdf0e10cSrcweir             // used from the MetafilePrimitive2D in it's decomposition.
252cdf0e10cSrcweir 
253cdf0e10cSrcweir             if(!getFillGradient().isDefault())
254cdf0e10cSrcweir             {
255*96fc4b33SArmin Le Grand                 static bool bOverlapping(true); // allow to test non-overlapping in the debugger
256*96fc4b33SArmin Le Grand 
257*96fc4b33SArmin Le Grand         		return createFill(bOverlapping);
258cdf0e10cSrcweir             }
259cdf0e10cSrcweir             else
260cdf0e10cSrcweir             {
261cdf0e10cSrcweir                 return Primitive2DSequence();
262cdf0e10cSrcweir             }
263cdf0e10cSrcweir 		}
264cdf0e10cSrcweir 
FillGradientPrimitive2D(const basegfx::B2DRange & rObjectRange,const attribute::FillGradientAttribute & rFillGradient)265cdf0e10cSrcweir 		FillGradientPrimitive2D::FillGradientPrimitive2D(
266cdf0e10cSrcweir 			const basegfx::B2DRange& rObjectRange,
267cdf0e10cSrcweir 			const attribute::FillGradientAttribute& rFillGradient)
268cdf0e10cSrcweir 		:	BufferedDecompositionPrimitive2D(),
269cdf0e10cSrcweir 			maObjectRange(rObjectRange),
270cdf0e10cSrcweir 			maFillGradient(rFillGradient)
271cdf0e10cSrcweir 		{
272cdf0e10cSrcweir 		}
273cdf0e10cSrcweir 
operator ==(const BasePrimitive2D & rPrimitive) const274cdf0e10cSrcweir 		bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
275cdf0e10cSrcweir 		{
276cdf0e10cSrcweir 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
277cdf0e10cSrcweir 			{
278cdf0e10cSrcweir 				const FillGradientPrimitive2D& rCompare = (FillGradientPrimitive2D&)rPrimitive;
279cdf0e10cSrcweir 
280cdf0e10cSrcweir 				return (getObjectRange() == rCompare.getObjectRange()
281cdf0e10cSrcweir 					&& getFillGradient() == rCompare.getFillGradient());
282cdf0e10cSrcweir 			}
283cdf0e10cSrcweir 
284cdf0e10cSrcweir 			return false;
285cdf0e10cSrcweir 		}
286cdf0e10cSrcweir 
getB2DRange(const geometry::ViewInformation2D &) const287cdf0e10cSrcweir 		basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
288cdf0e10cSrcweir 		{
289cdf0e10cSrcweir 			// return ObjectRange
290cdf0e10cSrcweir 			return getObjectRange();
291cdf0e10cSrcweir 		}
292cdf0e10cSrcweir 
293cdf0e10cSrcweir 		// provide unique ID
294cdf0e10cSrcweir 		ImplPrimitrive2DIDBlock(FillGradientPrimitive2D, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D)
295cdf0e10cSrcweir 
296cdf0e10cSrcweir 	} // end of namespace primitive2d
297cdf0e10cSrcweir } // end of namespace drawinglayer
298cdf0e10cSrcweir 
299cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
300cdf0e10cSrcweir // eof
301