xref: /trunk/main/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
1ddde725dSArmin Le Grand /**************************************************************
2ddde725dSArmin Le Grand  *
3ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5ddde725dSArmin Le Grand  * distributed with this work for additional information
6ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10ddde725dSArmin Le Grand  *
112b45cf47SArmin Le Grand  *   http://www.apache.org/licenses/LICENSE-2.0
12ddde725dSArmin Le Grand  *
13ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18ddde725dSArmin Le Grand  * under the License.
19ddde725dSArmin Le Grand  *
20ddde725dSArmin Le Grand  *************************************************************/
21ddde725dSArmin Le Grand 
22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23ddde725dSArmin Le Grand #include "precompiled_drawinglayer.hxx"
24ddde725dSArmin Le Grand 
25ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
26ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
29ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
30ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx>
31ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx>
32ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx>
33ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
34ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
35ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
36ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx>
37ddde725dSArmin Le Grand 
38ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
39ddde725dSArmin Le Grand 
40ddde725dSArmin Le Grand using namespace com::sun::star;
41ddde725dSArmin Le Grand 
42ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
43ddde725dSArmin Le Grand 
4439551d71SArmin Le Grand namespace
4539551d71SArmin Le Grand {
calculateStepsForSvgGradient(const basegfx::BColor & rColorA,const basegfx::BColor & rColorB,double fDelta,double fDiscreteUnit)4639551d71SArmin Le Grand     sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA, const basegfx::BColor& rColorB, double fDelta, double fDiscreteUnit)
4739551d71SArmin Le Grand     {
4839551d71SArmin Le Grand         // use color distance, assume to do every color step (full quality)
4939551d71SArmin Le Grand         sal_uInt32 nSteps(basegfx::fround(rColorA.getDistance(rColorB) * 255.0));
5039551d71SArmin Le Grand 
5139551d71SArmin Le Grand         if(nSteps)
5239551d71SArmin Le Grand         {
5339551d71SArmin Le Grand             // calc discrete length to change color all 1.5 disctete units (pixels)
5439551d71SArmin Le Grand             const sal_uInt32 nDistSteps(basegfx::fround(fDelta / (fDiscreteUnit * 1.5)));
5539551d71SArmin Le Grand 
5639551d71SArmin Le Grand             nSteps = std::min(nSteps, nDistSteps);
5739551d71SArmin Le Grand         }
5839551d71SArmin Le Grand 
5939551d71SArmin Le Grand         // roughly cut when too big or too small
6039551d71SArmin Le Grand         nSteps = std::min(nSteps, sal_uInt32(255));
6139551d71SArmin Le Grand         nSteps = std::max(nSteps, sal_uInt32(1));
6239551d71SArmin Le Grand 
6339551d71SArmin Le Grand         return nSteps;
6439551d71SArmin Le Grand     }
6539551d71SArmin Le Grand } // end of anonymous namespace
6639551d71SArmin Le Grand 
6739551d71SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
6839551d71SArmin Le Grand 
69ddde725dSArmin Le Grand namespace drawinglayer
70ddde725dSArmin Le Grand {
71ddde725dSArmin Le Grand     namespace primitive2d
72ddde725dSArmin Le Grand     {
createSingleGradientEntryFill() const73ddde725dSArmin Le Grand         Primitive2DSequence SvgGradientHelper::createSingleGradientEntryFill() const
74ddde725dSArmin Le Grand         {
75ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries = getGradientEntries();
76ddde725dSArmin Le Grand             const sal_uInt32 nCount(rEntries.size());
77ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
78ddde725dSArmin Le Grand 
79ddde725dSArmin Le Grand             if(nCount)
80ddde725dSArmin Le Grand             {
81ddde725dSArmin Le Grand                 const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1];
82ddde725dSArmin Le Grand                 const double fOpacity(rSingleEntry.getOpacity());
83ddde725dSArmin Le Grand 
84ddde725dSArmin Le Grand                 if(fOpacity > 0.0)
85ddde725dSArmin Le Grand                 {
86ddde725dSArmin Le Grand                     Primitive2DReference xRef(
87ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
88ddde725dSArmin Le Grand                             getPolyPolygon(),
89ddde725dSArmin Le Grand                             rSingleEntry.getColor()));
90ddde725dSArmin Le Grand 
91ddde725dSArmin Le Grand                     if(fOpacity < 1.0)
92ddde725dSArmin Le Grand                     {
93ddde725dSArmin Le Grand                         const Primitive2DSequence aContent(&xRef, 1);
94ddde725dSArmin Le Grand 
95ddde725dSArmin Le Grand                         xRef = Primitive2DReference(
96ddde725dSArmin Le Grand                             new UnifiedTransparencePrimitive2D(
97ddde725dSArmin Le Grand                                 aContent,
98ddde725dSArmin Le Grand                                 1.0 - fOpacity));
99ddde725dSArmin Le Grand                     }
100ddde725dSArmin Le Grand 
101ddde725dSArmin Le Grand                     xRetval = Primitive2DSequence(&xRef, 1);
102ddde725dSArmin Le Grand                 }
103ddde725dSArmin Le Grand             }
104ddde725dSArmin Le Grand             else
105ddde725dSArmin Le Grand             {
106ddde725dSArmin Le Grand                 OSL_ENSURE(false, "Single gradient entry construction without entry (!)");
107ddde725dSArmin Le Grand             }
108ddde725dSArmin Le Grand 
109ddde725dSArmin Le Grand             return xRetval;
110ddde725dSArmin Le Grand         }
111ddde725dSArmin Le Grand 
checkPreconditions()112ddde725dSArmin Le Grand         void SvgGradientHelper::checkPreconditions()
113ddde725dSArmin Le Grand         {
114ddde725dSArmin Le Grand             mbPreconditionsChecked = true;
115ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries = getGradientEntries();
116ddde725dSArmin Le Grand 
117ddde725dSArmin Le Grand             if(rEntries.empty())
118ddde725dSArmin Le Grand             {
119ddde725dSArmin Le Grand                 // no fill at all
120ddde725dSArmin Le Grand             }
121ddde725dSArmin Le Grand             else
122ddde725dSArmin Le Grand             {
123ddde725dSArmin Le Grand                 const sal_uInt32 nCount(rEntries.size());
124ddde725dSArmin Le Grand 
125ddde725dSArmin Le Grand                 if(1 == nCount)
126ddde725dSArmin Le Grand                 {
127ddde725dSArmin Le Grand                     // fill with single existing color
128ddde725dSArmin Le Grand                     setSingleEntry();
129ddde725dSArmin Le Grand                 }
130ddde725dSArmin Le Grand                 else
131ddde725dSArmin Le Grand                 {
132ddde725dSArmin Le Grand                     // sort maGradientEntries when more than one
133ddde725dSArmin Le Grand                     std::sort(maGradientEntries.begin(), maGradientEntries.end());
134ddde725dSArmin Le Grand 
135ddde725dSArmin Le Grand                     // gradient with at least two colors
136ddde725dSArmin Le Grand                     bool bAllInvisible(true);
137ddde725dSArmin Le Grand 
138ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nCount; a++)
139ddde725dSArmin Le Grand                     {
140ddde725dSArmin Le Grand                         const SvgGradientEntry& rCandidate = rEntries[a];
141ddde725dSArmin Le Grand 
142ddde725dSArmin Le Grand                         if(basegfx::fTools::equalZero(rCandidate.getOpacity()))
143ddde725dSArmin Le Grand                         {
144ddde725dSArmin Le Grand                             // invisible
145ddde725dSArmin Le Grand                             mbFullyOpaque = false;
146ddde725dSArmin Le Grand                         }
147ddde725dSArmin Le Grand                         else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0))
148ddde725dSArmin Le Grand                         {
149ddde725dSArmin Le Grand                             // completely opaque
150ddde725dSArmin Le Grand                             bAllInvisible = false;
151ddde725dSArmin Le Grand                         }
152ddde725dSArmin Le Grand                         else
153ddde725dSArmin Le Grand                         {
154ddde725dSArmin Le Grand                             // opacity
155ddde725dSArmin Le Grand                             bAllInvisible = false;
156ddde725dSArmin Le Grand                             mbFullyOpaque = false;
157ddde725dSArmin Le Grand                         }
158ddde725dSArmin Le Grand                     }
159ddde725dSArmin Le Grand 
160ddde725dSArmin Le Grand                     if(bAllInvisible)
161ddde725dSArmin Le Grand                     {
162ddde725dSArmin Le Grand                         // all invisible, nothing to do
163ddde725dSArmin Le Grand                     }
164ddde725dSArmin Le Grand                     else
165ddde725dSArmin Le Grand                     {
166ddde725dSArmin Le Grand                         const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
167ddde725dSArmin Le Grand 
168ddde725dSArmin Le Grand                         if(aPolyRange.isEmpty())
169ddde725dSArmin Le Grand                         {
170ddde725dSArmin Le Grand                             // no range to fill, nothing to do
171ddde725dSArmin Le Grand                         }
172ddde725dSArmin Le Grand                         else
173ddde725dSArmin Le Grand                         {
174ddde725dSArmin Le Grand                             const double fPolyWidth(aPolyRange.getWidth());
175ddde725dSArmin Le Grand                             const double fPolyHeight(aPolyRange.getHeight());
176ddde725dSArmin Le Grand 
177ddde725dSArmin Le Grand                             if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight))
178ddde725dSArmin Le Grand                             {
179ddde725dSArmin Le Grand                                 // no width/height to fill, nothing to do
180ddde725dSArmin Le Grand                             }
181ddde725dSArmin Le Grand                             else
182ddde725dSArmin Le Grand                             {
183ddde725dSArmin Le Grand                                 mbCreatesContent = true;
184ddde725dSArmin Le Grand                             }
185ddde725dSArmin Le Grand                         }
186ddde725dSArmin Le Grand                     }
187ddde725dSArmin Le Grand                 }
188ddde725dSArmin Le Grand             }
189ddde725dSArmin Le Grand         }
190ddde725dSArmin Le Grand 
createRun(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,double fPos,double fMax,const SvgGradientEntryVector & rEntries,sal_Int32 nOffset) const191ddde725dSArmin Le Grand         double SvgGradientHelper::createRun(
192ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
193ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
194ddde725dSArmin Le Grand             double fPos,
195ddde725dSArmin Le Grand             double fMax,
196ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries,
197ddde725dSArmin Le Grand             sal_Int32 nOffset) const
198ddde725dSArmin Le Grand         {
199ddde725dSArmin Le Grand             const sal_uInt32 nCount(rEntries.size());
200ddde725dSArmin Le Grand 
201ddde725dSArmin Le Grand             if(nCount)
202ddde725dSArmin Le Grand             {
203ddde725dSArmin Le Grand                 const SvgGradientEntry& rStart = rEntries[0];
204ddde725dSArmin Le Grand                 const bool bCreateStartPad(fPos < 0.0 && Spread_pad == getSpreadMethod());
205ddde725dSArmin Le Grand                 const bool bCreateStartFill(rStart.getOffset() > 0.0);
206ddde725dSArmin Le Grand                 sal_uInt32 nIndex(0);
207ddde725dSArmin Le Grand 
208ddde725dSArmin Le Grand                 if(bCreateStartPad || bCreateStartFill)
209ddde725dSArmin Le Grand                 {
210ddde725dSArmin Le Grand                     const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity());
211ddde725dSArmin Le Grand 
212ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset);
213ddde725dSArmin Le Grand                     fPos = rStart.getOffset();
214ddde725dSArmin Le Grand                 }
215ddde725dSArmin Le Grand 
216ddde725dSArmin Le Grand                 while(fPos < 1.0 && nIndex + 1 < nCount)
217ddde725dSArmin Le Grand                 {
218ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidateA = rEntries[nIndex++];
219ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidateB = rEntries[nIndex];
220ddde725dSArmin Le Grand 
221ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset);
222ddde725dSArmin Le Grand                     fPos = rCandidateB.getOffset();
223ddde725dSArmin Le Grand                 }
224ddde725dSArmin Le Grand 
225ddde725dSArmin Le Grand                 const SvgGradientEntry& rEnd = rEntries[nCount - 1];
226ddde725dSArmin Le Grand                 const bool bCreateEndPad(fPos < fMax && Spread_pad == getSpreadMethod());
227ddde725dSArmin Le Grand                 const bool bCreateEndFill(rEnd.getOffset() < 1.0);
228ddde725dSArmin Le Grand 
229ddde725dSArmin Le Grand                 if(bCreateEndPad || bCreateEndFill)
230ddde725dSArmin Le Grand                 {
231ddde725dSArmin Le Grand                     fPos = bCreateEndPad ? fMax : 1.0;
232ddde725dSArmin Le Grand                     const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity());
233ddde725dSArmin Le Grand 
234ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset);
235ddde725dSArmin Le Grand                 }
236ddde725dSArmin Le Grand             }
237ddde725dSArmin Le Grand             else
238ddde725dSArmin Le Grand             {
239ddde725dSArmin Le Grand                 OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)");
240ddde725dSArmin Le Grand                 fPos = fMax;
241ddde725dSArmin Le Grand             }
242ddde725dSArmin Le Grand 
243ddde725dSArmin Le Grand             return fPos;
244ddde725dSArmin Le Grand         }
245ddde725dSArmin Le Grand 
createResult(const Primitive2DVector & rTargetColor,const Primitive2DVector & rTargetOpacity,const basegfx::B2DHomMatrix & rUnitGradientToObject,bool bInvert) const246ddde725dSArmin Le Grand         Primitive2DSequence SvgGradientHelper::createResult(
247ddde725dSArmin Le Grand             const Primitive2DVector& rTargetColor,
248ddde725dSArmin Le Grand             const Primitive2DVector& rTargetOpacity,
249ddde725dSArmin Le Grand             const basegfx::B2DHomMatrix& rUnitGradientToObject,
250ddde725dSArmin Le Grand             bool bInvert) const
251ddde725dSArmin Le Grand         {
252ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
253ddde725dSArmin Le Grand             const Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(rTargetColor, bInvert));
254ddde725dSArmin Le Grand             const Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(rTargetOpacity, bInvert));
255ddde725dSArmin Le Grand 
256ddde725dSArmin Le Grand             if(aTargetColorEntries.hasElements())
257ddde725dSArmin Le Grand             {
258ddde725dSArmin Le Grand                 Primitive2DReference xRefContent;
259ddde725dSArmin Le Grand 
260ddde725dSArmin Le Grand                 if(aTargetOpacityEntries.hasElements())
261ddde725dSArmin Le Grand                 {
262ddde725dSArmin Le Grand                     const Primitive2DReference xRefOpacity = new TransparencePrimitive2D(
263ddde725dSArmin Le Grand                         aTargetColorEntries,
264ddde725dSArmin Le Grand                         aTargetOpacityEntries);
265ddde725dSArmin Le Grand 
266ddde725dSArmin Le Grand                     xRefContent = new TransformPrimitive2D(
267ddde725dSArmin Le Grand                         rUnitGradientToObject,
268ddde725dSArmin Le Grand                         Primitive2DSequence(&xRefOpacity, 1));
269ddde725dSArmin Le Grand                 }
270ddde725dSArmin Le Grand                 else
271ddde725dSArmin Le Grand                 {
272ddde725dSArmin Le Grand                     xRefContent = new TransformPrimitive2D(
273ddde725dSArmin Le Grand                         rUnitGradientToObject,
274ddde725dSArmin Le Grand                         aTargetColorEntries);
275ddde725dSArmin Le Grand                 }
276ddde725dSArmin Le Grand 
277ddde725dSArmin Le Grand                 xRefContent = new MaskPrimitive2D(
278ddde725dSArmin Le Grand                     getPolyPolygon(),
279ddde725dSArmin Le Grand                     Primitive2DSequence(&xRefContent, 1));
280ddde725dSArmin Le Grand 
281ddde725dSArmin Le Grand                 xRetval = Primitive2DSequence(&xRefContent, 1);
282ddde725dSArmin Le Grand             }
283ddde725dSArmin Le Grand 
284ddde725dSArmin Le Grand             return xRetval;
285ddde725dSArmin Le Grand         }
286ddde725dSArmin Le Grand 
SvgGradientHelper(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod)287ddde725dSArmin Le Grand         SvgGradientHelper::SvgGradientHelper(
28801e92ad6SArmin Le Grand             const basegfx::B2DHomMatrix& rGradientTransform,
289ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
290ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
291ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
292804e0487SArmin Le Grand             bool bUseUnitCoordinates,
29339551d71SArmin Le Grand             SpreadMethod aSpreadMethod)
29401e92ad6SArmin Le Grand         :   maGradientTransform(rGradientTransform),
29501e92ad6SArmin Le Grand             maPolyPolygon(rPolyPolygon),
296ddde725dSArmin Le Grand             maGradientEntries(rGradientEntries),
297ddde725dSArmin Le Grand             maStart(rStart),
298ddde725dSArmin Le Grand             maSpreadMethod(aSpreadMethod),
299ddde725dSArmin Le Grand             mbPreconditionsChecked(false),
300ddde725dSArmin Le Grand             mbCreatesContent(false),
301ddde725dSArmin Le Grand             mbSingleEntry(false),
302804e0487SArmin Le Grand             mbFullyOpaque(true),
303804e0487SArmin Le Grand             mbUseUnitCoordinates(bUseUnitCoordinates)
304ddde725dSArmin Le Grand         {
305ddde725dSArmin Le Grand         }
306ddde725dSArmin Le Grand 
~SvgGradientHelper()307*895ed544SArmin Le Grand         SvgGradientHelper::~SvgGradientHelper()
308*895ed544SArmin Le Grand         {
309*895ed544SArmin Le Grand         }
310*895ed544SArmin Le Grand 
operator ==(const SvgGradientHelper & rSvgGradientHelper) const311ddde725dSArmin Le Grand         bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const
312ddde725dSArmin Le Grand         {
313ddde725dSArmin Le Grand             const SvgGradientHelper& rCompare = static_cast< const SvgGradientHelper& >(rSvgGradientHelper);
314ddde725dSArmin Le Grand 
31501e92ad6SArmin Le Grand             return (getGradientTransform() == rCompare.getGradientTransform()
31601e92ad6SArmin Le Grand                 && getPolyPolygon() == rCompare.getPolyPolygon()
317ddde725dSArmin Le Grand                 && getGradientEntries() == rCompare.getGradientEntries()
318ddde725dSArmin Le Grand                 && getStart() == rCompare.getStart()
319804e0487SArmin Le Grand                 && getUseUnitCoordinates() == rCompare.getUseUnitCoordinates()
32039551d71SArmin Le Grand                 && getSpreadMethod() == rCompare.getSpreadMethod());
321ddde725dSArmin Le Grand         }
322ddde725dSArmin Le Grand 
323ddde725dSArmin Le Grand     } // end of namespace primitive2d
324ddde725dSArmin Le Grand } // end of namespace drawinglayer
325ddde725dSArmin Le Grand 
326ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
327ddde725dSArmin Le Grand 
328ddde725dSArmin Le Grand namespace drawinglayer
329ddde725dSArmin Le Grand {
330ddde725dSArmin Le Grand     namespace primitive2d
331ddde725dSArmin Le Grand     {
checkPreconditions()332ddde725dSArmin Le Grand         void SvgLinearGradientPrimitive2D::checkPreconditions()
333ddde725dSArmin Le Grand         {
334ddde725dSArmin Le Grand             // call parent
335ddde725dSArmin Le Grand             SvgGradientHelper::checkPreconditions();
336ddde725dSArmin Le Grand 
337ddde725dSArmin Le Grand             if(getCreatesContent())
338ddde725dSArmin Le Grand             {
339ddde725dSArmin Le Grand                 // Check Vector
340ddde725dSArmin Le Grand                 const basegfx::B2DVector aVector(getEnd() - getStart());
341ddde725dSArmin Le Grand 
342ddde725dSArmin Le Grand                 if(basegfx::fTools::equalZero(aVector.getX()) && basegfx::fTools::equalZero(aVector.getY()))
343ddde725dSArmin Le Grand                 {
344ddde725dSArmin Le Grand                     // fill with single color using last stop color
345ddde725dSArmin Le Grand                     setSingleEntry();
346ddde725dSArmin Le Grand                 }
347ddde725dSArmin Le Grand             }
348ddde725dSArmin Le Grand         }
349ddde725dSArmin Le Grand 
createAtom(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,const SvgGradientEntry & rFrom,const SvgGradientEntry & rTo,sal_Int32 nOffset) const350ddde725dSArmin Le Grand         void SvgLinearGradientPrimitive2D::createAtom(
351ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
352ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
353ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
354ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
355ddde725dSArmin Le Grand             sal_Int32 nOffset) const
356ddde725dSArmin Le Grand         {
357ddde725dSArmin Le Grand             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
358ddde725dSArmin Le Grand             if(rFrom.getOffset() == rTo.getOffset())
359ddde725dSArmin Le Grand             {
360ddde725dSArmin Le Grand                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
361ddde725dSArmin Le Grand             }
362ddde725dSArmin Le Grand             else
363ddde725dSArmin Le Grand             {
364ddde725dSArmin Le Grand                 rTargetColor.push_back(
365ddde725dSArmin Le Grand                     new SvgLinearAtomPrimitive2D(
366ddde725dSArmin Le Grand                         rFrom.getColor(), rFrom.getOffset() + nOffset,
36739551d71SArmin Le Grand                         rTo.getColor(), rTo.getOffset() + nOffset));
368ddde725dSArmin Le Grand 
369025b0597SArmin Le Grand                 if(!getFullyOpaque())
370025b0597SArmin Le Grand                 {
371ddde725dSArmin Le Grand                     const double fTransFrom(1.0 - rFrom.getOpacity());
372ddde725dSArmin Le Grand                     const double fTransTo(1.0 - rTo.getOpacity());
373025b0597SArmin Le Grand                     const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom);
374025b0597SArmin Le Grand                     const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo);
375ddde725dSArmin Le Grand 
376ddde725dSArmin Le Grand                     rTargetOpacity.push_back(
377ddde725dSArmin Le Grand                         new SvgLinearAtomPrimitive2D(
378025b0597SArmin Le Grand                             aColorFrom, rFrom.getOffset() + nOffset,
379025b0597SArmin Le Grand                             aColorTo, rTo.getOffset() + nOffset));
380025b0597SArmin Le Grand                 }
381ddde725dSArmin Le Grand             }
382ddde725dSArmin Le Grand         }
383ddde725dSArmin Le Grand 
create2DDecomposition(const geometry::ViewInformation2D &) const384ddde725dSArmin Le Grand         Primitive2DSequence SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
385ddde725dSArmin Le Grand         {
386ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
387ddde725dSArmin Le Grand 
388ddde725dSArmin Le Grand             if(!getPreconditionsChecked())
389ddde725dSArmin Le Grand             {
390ddde725dSArmin Le Grand                 const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions();
391ddde725dSArmin Le Grand             }
392ddde725dSArmin Le Grand 
393ddde725dSArmin Le Grand             if(getSingleEntry())
394ddde725dSArmin Le Grand             {
395ddde725dSArmin Le Grand                 // fill with last existing color
396ddde725dSArmin Le Grand                 xRetval = createSingleGradientEntryFill();
397ddde725dSArmin Le Grand             }
398ddde725dSArmin Le Grand             else if(getCreatesContent())
399ddde725dSArmin Le Grand             {
400ddde725dSArmin Le Grand                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
401ddde725dSArmin Le Grand                 // invisible, width and height to fill are not empty
402ddde725dSArmin Le Grand                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
403ddde725dSArmin Le Grand                 const double fPolyWidth(aPolyRange.getWidth());
404ddde725dSArmin Le Grand                 const double fPolyHeight(aPolyRange.getHeight());
405ddde725dSArmin Le Grand 
406ddde725dSArmin Le Grand                 // create ObjectTransform based on polygon range
407ddde725dSArmin Le Grand                 const basegfx::B2DHomMatrix aObjectTransform(
408ddde725dSArmin Le Grand                     basegfx::tools::createScaleTranslateB2DHomMatrix(
409ddde725dSArmin Le Grand                         fPolyWidth, fPolyHeight,
410ddde725dSArmin Le Grand                         aPolyRange.getMinX(), aPolyRange.getMinY()));
411804e0487SArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToObject;
412ddde725dSArmin Le Grand 
413804e0487SArmin Le Grand                 if(getUseUnitCoordinates())
414804e0487SArmin Le Grand                 {
415804e0487SArmin Le Grand                     // interpret in unit coordinate system -> object aspect ratio will scale result
416804e0487SArmin Le Grand                     // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given
417804e0487SArmin Le Grand                     // gradient vector defined by Start,End
418804e0487SArmin Le Grand                     const basegfx::B2DVector aVector(getEnd() - getStart());
419804e0487SArmin Le Grand                     const double fVectorLength(aVector.getLength());
420804e0487SArmin Le Grand 
421915dc3acSArmin Le Grand                     aUnitGradientToObject.scale(fVectorLength, 1.0);
422915dc3acSArmin Le Grand                     aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX()));
423915dc3acSArmin Le Grand                     aUnitGradientToObject.translate(getStart().getX(), getStart().getY());
424915dc3acSArmin Le Grand 
425915dc3acSArmin Le Grand                     if(!getGradientTransform().isIdentity())
426915dc3acSArmin Le Grand                     {
427915dc3acSArmin Le Grand                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
428915dc3acSArmin Le Grand                     }
429804e0487SArmin Le Grand 
430804e0487SArmin Le Grand                     // create full transform from unit gradient coordinates to object coordinates
431804e0487SArmin Le Grand                     // including the SvgGradient transformation
432915dc3acSArmin Le Grand                     aUnitGradientToObject = aObjectTransform * aUnitGradientToObject;
433804e0487SArmin Le Grand                 }
434804e0487SArmin Le Grand                 else
435804e0487SArmin Le Grand                 {
436804e0487SArmin Le Grand                     // interpret in object coordinate system -> object aspect ratio will not scale result
43786d97322SArmin Le Grand                     const basegfx::B2DPoint aStart(aObjectTransform * getStart());
43886d97322SArmin Le Grand                     const basegfx::B2DPoint aEnd(aObjectTransform * getEnd());
43986d97322SArmin Le Grand                     const basegfx::B2DVector aVector(aEnd - aStart);
440ddde725dSArmin Le Grand 
441804e0487SArmin Le Grand                     aUnitGradientToObject.scale(aVector.getLength(), 1.0);
44286d97322SArmin Le Grand                     aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX()));
44386d97322SArmin Le Grand                     aUnitGradientToObject.translate(aStart.getX(), aStart.getY());
444ddde725dSArmin Le Grand 
44501e92ad6SArmin Le Grand                     if(!getGradientTransform().isIdentity())
44601e92ad6SArmin Le Grand                     {
44701e92ad6SArmin Le Grand                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
44801e92ad6SArmin Le Grand                     }
449915dc3acSArmin Le Grand                 }
45001e92ad6SArmin Le Grand 
451ddde725dSArmin Le Grand                 // create inverse from it
452ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
453ddde725dSArmin Le Grand                 aObjectToUnitGradient.invert();
454ddde725dSArmin Le Grand 
455ddde725dSArmin Le Grand                 // back-transform polygon to unit gradient coordinates and get
456ddde725dSArmin Le Grand                 // UnitRage. This is the range the gradient has to cover
457ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
458ddde725dSArmin Le Grand                 aUnitPoly.transform(aObjectToUnitGradient);
459ddde725dSArmin Le Grand                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
460ddde725dSArmin Le Grand 
461ddde725dSArmin Le Grand                 // prepare result vectors
462ddde725dSArmin Le Grand                 Primitive2DVector aTargetColor;
463ddde725dSArmin Le Grand                 Primitive2DVector aTargetOpacity;
464ddde725dSArmin Le Grand 
465ddde725dSArmin Le Grand                 if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0))
466ddde725dSArmin Le Grand                 {
467ddde725dSArmin Le Grand                     // add a pre-multiply to aUnitGradientToObject to allow
468ddde725dSArmin Le Grand                     // multiplication of the polygon(xl, 0.0, xr, 1.0)
469ddde725dSArmin Le Grand                     const basegfx::B2DHomMatrix aPreMultiply(
470ddde725dSArmin Le Grand                         basegfx::tools::createScaleTranslateB2DHomMatrix(
471ddde725dSArmin Le Grand                             1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY()));
472ddde725dSArmin Le Grand                     aUnitGradientToObject = aUnitGradientToObject * aPreMultiply;
473ddde725dSArmin Le Grand 
474ddde725dSArmin Le Grand                     // create central run, may also already do all necessary when
475ddde725dSArmin Le Grand                     // Spread_pad is set as SpreadMethod and/or the range is smaller
476ddde725dSArmin Le Grand                     double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0));
477ddde725dSArmin Le Grand 
478ddde725dSArmin Le Grand                     if(fPos < aUnitRange.getMaxX())
479ddde725dSArmin Le Grand                     {
480ddde725dSArmin Le Grand                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
481ddde725dSArmin Le Grand                         // else the start and end pads are already created and fPos == aUnitRange.getMaxX().
482ddde725dSArmin Le Grand                         // Its possible to express the repeated linear gradient by adding the
483ddde725dSArmin Le Grand                         // transformed central run. Crete it this way
484ddde725dSArmin Le Grand                         Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(aTargetColor));
485ddde725dSArmin Le Grand                         Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(aTargetOpacity));
486ddde725dSArmin Le Grand                         aTargetColor.clear();
487ddde725dSArmin Le Grand                         aTargetOpacity.clear();
488ddde725dSArmin Le Grand 
489ddde725dSArmin Le Grand                         if(aTargetColorEntries.hasElements())
490ddde725dSArmin Le Grand                         {
491ddde725dSArmin Le Grand                             // add original central run as group primitive
492ddde725dSArmin Le Grand                             aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries));
493ddde725dSArmin Le Grand 
494ddde725dSArmin Le Grand                             if(aTargetOpacityEntries.hasElements())
495ddde725dSArmin Le Grand                             {
496ddde725dSArmin Le Grand                                 aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries));
497ddde725dSArmin Le Grand                             }
498ddde725dSArmin Le Grand 
499ddde725dSArmin Le Grand                             // add negative runs
500ddde725dSArmin Le Grand                             fPos = 0.0;
501ddde725dSArmin Le Grand                             sal_Int32 nOffset(0);
502ddde725dSArmin Le Grand 
503ddde725dSArmin Le Grand                             while(fPos > aUnitRange.getMinX())
504ddde725dSArmin Le Grand                             {
505ddde725dSArmin Le Grand                                 fPos -= 1.0;
506ddde725dSArmin Le Grand                                 nOffset++;
507ddde725dSArmin Le Grand 
508ddde725dSArmin Le Grand                                 basegfx::B2DHomMatrix aTransform;
509ddde725dSArmin Le Grand                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
510ddde725dSArmin Le Grand 
511ddde725dSArmin Le Grand                                 if(bMirror)
512ddde725dSArmin Le Grand                                 {
513ddde725dSArmin Le Grand                                     aTransform.scale(-1.0, 1.0);
514ddde725dSArmin Le Grand                                     aTransform.translate(fPos + 1.0, 0.0);
515ddde725dSArmin Le Grand                                 }
516ddde725dSArmin Le Grand                                 else
517ddde725dSArmin Le Grand                                 {
518ddde725dSArmin Le Grand                                     aTransform.translate(fPos, 0.0);
519ddde725dSArmin Le Grand                                 }
520ddde725dSArmin Le Grand 
521ddde725dSArmin Le Grand                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
522ddde725dSArmin Le Grand 
523ddde725dSArmin Le Grand                                 if(aTargetOpacityEntries.hasElements())
524ddde725dSArmin Le Grand                                 {
525ddde725dSArmin Le Grand                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
526ddde725dSArmin Le Grand                                 }
527ddde725dSArmin Le Grand                             }
528ddde725dSArmin Le Grand 
529ddde725dSArmin Le Grand                             // add positive runs
530ddde725dSArmin Le Grand                             fPos = 1.0;
531ddde725dSArmin Le Grand                             nOffset = 1;
532ddde725dSArmin Le Grand 
533ddde725dSArmin Le Grand                             while(fPos < aUnitRange.getMaxX())
534ddde725dSArmin Le Grand                             {
535ddde725dSArmin Le Grand                                 basegfx::B2DHomMatrix aTransform;
536ddde725dSArmin Le Grand                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
537ddde725dSArmin Le Grand 
538ddde725dSArmin Le Grand                                 if(bMirror)
539ddde725dSArmin Le Grand                                 {
540ddde725dSArmin Le Grand                                     aTransform.scale(-1.0, 1.0);
541ddde725dSArmin Le Grand                                     aTransform.translate(fPos + 1.0, 0.0);
542ddde725dSArmin Le Grand                                 }
543ddde725dSArmin Le Grand                                 else
544ddde725dSArmin Le Grand                                 {
545ddde725dSArmin Le Grand                                     aTransform.translate(fPos, 0.0);
546ddde725dSArmin Le Grand                                 }
547ddde725dSArmin Le Grand 
548ddde725dSArmin Le Grand                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
549ddde725dSArmin Le Grand 
550ddde725dSArmin Le Grand                                 if(aTargetOpacityEntries.hasElements())
551ddde725dSArmin Le Grand                                 {
552ddde725dSArmin Le Grand                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
553ddde725dSArmin Le Grand                                 }
554ddde725dSArmin Le Grand 
555ddde725dSArmin Le Grand                                 fPos += 1.0;
556ddde725dSArmin Le Grand                                 nOffset++;
557ddde725dSArmin Le Grand                             }
558ddde725dSArmin Le Grand                         }
559ddde725dSArmin Le Grand                     }
560ddde725dSArmin Le Grand                 }
561ddde725dSArmin Le Grand 
562ddde725dSArmin Le Grand                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject);
563ddde725dSArmin Le Grand             }
564ddde725dSArmin Le Grand 
565ddde725dSArmin Le Grand             return xRetval;
566ddde725dSArmin Le Grand         }
567ddde725dSArmin Le Grand 
SvgLinearGradientPrimitive2D(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,const basegfx::B2DPoint & rEnd,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod)568ddde725dSArmin Le Grand         SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D(
56901e92ad6SArmin Le Grand             const basegfx::B2DHomMatrix& rGradientTransform,
570ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
571ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
572ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
573ddde725dSArmin Le Grand             const basegfx::B2DPoint& rEnd,
574804e0487SArmin Le Grand             bool bUseUnitCoordinates,
57539551d71SArmin Le Grand             SpreadMethod aSpreadMethod)
576ddde725dSArmin Le Grand         :   BufferedDecompositionPrimitive2D(),
57701e92ad6SArmin Le Grand             SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod),
578ddde725dSArmin Le Grand             maEnd(rEnd)
579ddde725dSArmin Le Grand         {
580ddde725dSArmin Le Grand         }
581ddde725dSArmin Le Grand 
~SvgLinearGradientPrimitive2D()582025b0597SArmin Le Grand         SvgLinearGradientPrimitive2D::~SvgLinearGradientPrimitive2D()
583025b0597SArmin Le Grand         {
584025b0597SArmin Le Grand         }
585025b0597SArmin Le Grand 
operator ==(const BasePrimitive2D & rPrimitive) const586ddde725dSArmin Le Grand         bool SvgLinearGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
587ddde725dSArmin Le Grand         {
588ddde725dSArmin Le Grand             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
589ddde725dSArmin Le Grand 
590ddde725dSArmin Le Grand             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
591ddde725dSArmin Le Grand             {
592ddde725dSArmin Le Grand                 const SvgLinearGradientPrimitive2D& rCompare = static_cast< const SvgLinearGradientPrimitive2D& >(rPrimitive);
593ddde725dSArmin Le Grand 
594ddde725dSArmin Le Grand                 return (getEnd() == rCompare.getEnd());
595ddde725dSArmin Le Grand             }
596ddde725dSArmin Le Grand 
597ddde725dSArmin Le Grand             return false;
598ddde725dSArmin Le Grand         }
599ddde725dSArmin Le Grand 
getB2DRange(const geometry::ViewInformation2D &) const600ddde725dSArmin Le Grand         basegfx::B2DRange SvgLinearGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
601ddde725dSArmin Le Grand         {
602ddde725dSArmin Le Grand             // return ObjectRange
603ddde725dSArmin Le Grand             return getPolyPolygon().getB2DRange();
604ddde725dSArmin Le Grand         }
605ddde725dSArmin Le Grand 
606ddde725dSArmin Le Grand         // provide unique ID
607ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D)
608ddde725dSArmin Le Grand 
609ddde725dSArmin Le Grand     } // end of namespace primitive2d
610ddde725dSArmin Le Grand } // end of namespace drawinglayer
611ddde725dSArmin Le Grand 
612ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
613ddde725dSArmin Le Grand 
614ddde725dSArmin Le Grand namespace drawinglayer
615ddde725dSArmin Le Grand {
616ddde725dSArmin Le Grand     namespace primitive2d
617ddde725dSArmin Le Grand     {
checkPreconditions()618ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::checkPreconditions()
619ddde725dSArmin Le Grand         {
620ddde725dSArmin Le Grand             // call parent
621ddde725dSArmin Le Grand             SvgGradientHelper::checkPreconditions();
622ddde725dSArmin Le Grand 
623ddde725dSArmin Le Grand             if(getCreatesContent())
624ddde725dSArmin Le Grand             {
625ddde725dSArmin Le Grand                 // Check Radius
626ddde725dSArmin Le Grand                 if(basegfx::fTools::equalZero(getRadius()))
627ddde725dSArmin Le Grand                 {
628ddde725dSArmin Le Grand                     // fill with single color using last stop color
629ddde725dSArmin Le Grand                     setSingleEntry();
630ddde725dSArmin Le Grand                 }
631ddde725dSArmin Le Grand             }
632ddde725dSArmin Le Grand         }
633ddde725dSArmin Le Grand 
createAtom(Primitive2DVector & rTargetColor,Primitive2DVector & rTargetOpacity,const SvgGradientEntry & rFrom,const SvgGradientEntry & rTo,sal_Int32 nOffset) const634ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::createAtom(
635ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
636ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
637ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
638ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
639ddde725dSArmin Le Grand             sal_Int32 nOffset) const
640ddde725dSArmin Le Grand         {
641ddde725dSArmin Le Grand             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
642ddde725dSArmin Le Grand             if(rFrom.getOffset() == rTo.getOffset())
643ddde725dSArmin Le Grand             {
644ddde725dSArmin Le Grand                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
645ddde725dSArmin Le Grand             }
646ddde725dSArmin Le Grand             else
647ddde725dSArmin Le Grand             {
648ddde725dSArmin Le Grand                 const double fScaleFrom(rFrom.getOffset() + nOffset);
649ddde725dSArmin Le Grand                 const double fScaleTo(rTo.getOffset() + nOffset);
650ddde725dSArmin Le Grand 
651ddde725dSArmin Le Grand                 if(isFocalSet())
652ddde725dSArmin Le Grand                 {
653ddde725dSArmin Le Grand                     const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
654ddde725dSArmin Le Grand                     const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
655ddde725dSArmin Le Grand 
656ddde725dSArmin Le Grand                     rTargetColor.push_back(
657ddde725dSArmin Le Grand                         new SvgRadialAtomPrimitive2D(
658ddde725dSArmin Le Grand                             rFrom.getColor(), fScaleFrom, aTranslateFrom,
65939551d71SArmin Le Grand                             rTo.getColor(), fScaleTo, aTranslateTo));
660ddde725dSArmin Le Grand                 }
661ddde725dSArmin Le Grand                 else
662ddde725dSArmin Le Grand                 {
663ddde725dSArmin Le Grand                     rTargetColor.push_back(
664ddde725dSArmin Le Grand                         new SvgRadialAtomPrimitive2D(
665ddde725dSArmin Le Grand                             rFrom.getColor(), fScaleFrom,
66639551d71SArmin Le Grand                             rTo.getColor(), fScaleTo));
667ddde725dSArmin Le Grand                 }
668ddde725dSArmin Le Grand 
669025b0597SArmin Le Grand                 if(!getFullyOpaque())
670025b0597SArmin Le Grand                 {
671ddde725dSArmin Le Grand                     const double fTransFrom(1.0 - rFrom.getOpacity());
672ddde725dSArmin Le Grand                     const double fTransTo(1.0 - rTo.getOpacity());
673ddde725dSArmin Le Grand                     const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom);
674ddde725dSArmin Le Grand                     const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo);
675ddde725dSArmin Le Grand 
676ddde725dSArmin Le Grand                     if(isFocalSet())
677ddde725dSArmin Le Grand                     {
678ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
679ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
680ddde725dSArmin Le Grand 
681ddde725dSArmin Le Grand                         rTargetOpacity.push_back(
682ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
683ddde725dSArmin Le Grand                                 aColorFrom, fScaleFrom, aTranslateFrom,
68439551d71SArmin Le Grand                                 aColorTo, fScaleTo, aTranslateTo));
685ddde725dSArmin Le Grand                     }
686ddde725dSArmin Le Grand                     else
687ddde725dSArmin Le Grand                     {
688ddde725dSArmin Le Grand                         rTargetOpacity.push_back(
689ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
690ddde725dSArmin Le Grand                                 aColorFrom, fScaleFrom,
69139551d71SArmin Le Grand                                 aColorTo, fScaleTo));
692ddde725dSArmin Le Grand                     }
693ddde725dSArmin Le Grand                 }
694ddde725dSArmin Le Grand             }
695025b0597SArmin Le Grand         }
696ddde725dSArmin Le Grand 
getMirroredGradientEntries() const697ddde725dSArmin Le Grand         const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const
698ddde725dSArmin Le Grand         {
699ddde725dSArmin Le Grand             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
700ddde725dSArmin Le Grand             {
701ddde725dSArmin Le Grand                 const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries();
702ddde725dSArmin Le Grand             }
703ddde725dSArmin Le Grand 
704ddde725dSArmin Le Grand             return maMirroredGradientEntries;
705ddde725dSArmin Le Grand         }
706ddde725dSArmin Le Grand 
createMirroredGradientEntries()707ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::createMirroredGradientEntries()
708ddde725dSArmin Le Grand         {
709ddde725dSArmin Le Grand             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
710ddde725dSArmin Le Grand             {
711ddde725dSArmin Le Grand                 const sal_uInt32 nCount(getGradientEntries().size());
712ddde725dSArmin Le Grand                 maMirroredGradientEntries.clear();
713ddde725dSArmin Le Grand                 maMirroredGradientEntries.reserve(nCount);
714ddde725dSArmin Le Grand 
715ddde725dSArmin Le Grand                 for(sal_uInt32 a(0); a < nCount; a++)
716ddde725dSArmin Le Grand                 {
717ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a];
718ddde725dSArmin Le Grand 
719ddde725dSArmin Le Grand                     maMirroredGradientEntries.push_back(
720ddde725dSArmin Le Grand                         SvgGradientEntry(
721ddde725dSArmin Le Grand                             1.0 - rCandidate.getOffset(),
722ddde725dSArmin Le Grand                             rCandidate.getColor(),
723ddde725dSArmin Le Grand                             rCandidate.getOpacity()));
724ddde725dSArmin Le Grand                 }
725ddde725dSArmin Le Grand             }
726ddde725dSArmin Le Grand         }
727ddde725dSArmin Le Grand 
create2DDecomposition(const geometry::ViewInformation2D &) const728ddde725dSArmin Le Grand         Primitive2DSequence SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
729ddde725dSArmin Le Grand         {
730ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
731ddde725dSArmin Le Grand 
732ddde725dSArmin Le Grand             if(!getPreconditionsChecked())
733ddde725dSArmin Le Grand             {
734ddde725dSArmin Le Grand                 const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions();
735ddde725dSArmin Le Grand             }
736ddde725dSArmin Le Grand 
737ddde725dSArmin Le Grand             if(getSingleEntry())
738ddde725dSArmin Le Grand             {
739ddde725dSArmin Le Grand                 // fill with last existing color
740ddde725dSArmin Le Grand                 xRetval = createSingleGradientEntryFill();
741ddde725dSArmin Le Grand             }
742ddde725dSArmin Le Grand             else if(getCreatesContent())
743ddde725dSArmin Le Grand             {
744ddde725dSArmin Le Grand                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
745ddde725dSArmin Le Grand                 // invisible, width and height to fill are not empty
746ddde725dSArmin Le Grand                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
747ddde725dSArmin Le Grand                 const double fPolyWidth(aPolyRange.getWidth());
748ddde725dSArmin Le Grand                 const double fPolyHeight(aPolyRange.getHeight());
749ddde725dSArmin Le Grand 
750ddde725dSArmin Le Grand                 // create ObjectTransform based on polygon range
751ddde725dSArmin Le Grand                 const basegfx::B2DHomMatrix aObjectTransform(
752ddde725dSArmin Le Grand                     basegfx::tools::createScaleTranslateB2DHomMatrix(
753ddde725dSArmin Le Grand                         fPolyWidth, fPolyHeight,
754ddde725dSArmin Le Grand                         aPolyRange.getMinX(), aPolyRange.getMinY()));
755804e0487SArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToObject;
756ddde725dSArmin Le Grand 
757804e0487SArmin Le Grand                 if(getUseUnitCoordinates())
758804e0487SArmin Le Grand                 {
759804e0487SArmin Le Grand                     // interpret in unit coordinate system -> object aspect ratio will scale result
760ddde725dSArmin Le Grand                     // create unit transform from unit vector to given linear gradient vector
761915dc3acSArmin Le Grand                     aUnitGradientToObject.scale(getRadius(), getRadius());
762915dc3acSArmin Le Grand                     aUnitGradientToObject.translate(getStart().getX(), getStart().getY());
763ddde725dSArmin Le Grand 
764915dc3acSArmin Le Grand                     if(!getGradientTransform().isIdentity())
765915dc3acSArmin Le Grand                     {
766915dc3acSArmin Le Grand                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
767915dc3acSArmin Le Grand                     }
768ddde725dSArmin Le Grand 
769ddde725dSArmin Le Grand                     // create full transform from unit gradient coordinates to object coordinates
770ddde725dSArmin Le Grand                     // including the SvgGradient transformation
771915dc3acSArmin Le Grand                     aUnitGradientToObject = aObjectTransform * aUnitGradientToObject;
772804e0487SArmin Le Grand                 }
773804e0487SArmin Le Grand                 else
774804e0487SArmin Le Grand                 {
775804e0487SArmin Le Grand                     // interpret in object coordinate system -> object aspect ratio will not scale result
77601e92ad6SArmin Le Grand                     // use X-Axis with radius, it was already made relative to object width when coming from
77701e92ad6SArmin Le Grand                     // SVG import
778804e0487SArmin Le Grand                     const double fRadius((aObjectTransform * basegfx::B2DVector(getRadius(), 0.0)).getLength());
779804e0487SArmin Le Grand                     const basegfx::B2DPoint aStart(aObjectTransform * getStart());
780804e0487SArmin Le Grand 
781804e0487SArmin Le Grand                     aUnitGradientToObject.scale(fRadius, fRadius);
782804e0487SArmin Le Grand                     aUnitGradientToObject.translate(aStart.getX(), aStart.getY());
783ddde725dSArmin Le Grand 
78401e92ad6SArmin Le Grand                     if(!getGradientTransform().isIdentity())
78501e92ad6SArmin Le Grand                     {
78601e92ad6SArmin Le Grand                         aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject;
78701e92ad6SArmin Le Grand                     }
788915dc3acSArmin Le Grand                 }
78901e92ad6SArmin Le Grand 
790ddde725dSArmin Le Grand                 // create inverse from it
791ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
792ddde725dSArmin Le Grand                 aObjectToUnitGradient.invert();
793ddde725dSArmin Le Grand 
794ddde725dSArmin Le Grand                 // back-transform polygon to unit gradient coordinates and get
795ddde725dSArmin Le Grand                 // UnitRage. This is the range the gradient has to cover
796ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
797ddde725dSArmin Le Grand                 aUnitPoly.transform(aObjectToUnitGradient);
798ddde725dSArmin Le Grand                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
799ddde725dSArmin Le Grand 
800ddde725dSArmin Le Grand                 // create range which the gradient has to cover to cover the whole given geometry.
801ddde725dSArmin Le Grand                 // For circle, go from 0.0 to max radius in all directions (the corners)
802ddde725dSArmin Le Grand                 double fMax(basegfx::B2DVector(aUnitRange.getMinimum()).getLength());
803ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaximum()).getLength());
804ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMinX(), aUnitRange.getMaxY()).getLength());
805ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaxX(), aUnitRange.getMinY()).getLength());
806ddde725dSArmin Le Grand 
807ddde725dSArmin Le Grand                 // prepare result vectors
808ddde725dSArmin Le Grand                 Primitive2DVector aTargetColor;
809ddde725dSArmin Le Grand                 Primitive2DVector aTargetOpacity;
810ddde725dSArmin Le Grand 
811ddde725dSArmin Le Grand                 if(0.0 < fMax)
812ddde725dSArmin Le Grand                 {
813ddde725dSArmin Le Grand                     // prepare maFocalVector
814ddde725dSArmin Le Grand                     if(isFocalSet())
815ddde725dSArmin Le Grand                     {
816ddde725dSArmin Le Grand                         const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax;
817ddde725dSArmin Le Grand                     }
818ddde725dSArmin Le Grand 
819ddde725dSArmin Le Grand                     // create central run, may also already do all necessary when
820ddde725dSArmin Le Grand                     // Spread_pad is set as SpreadMethod and/or the range is smaller
821ddde725dSArmin Le Grand                     double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0));
822ddde725dSArmin Le Grand 
823ddde725dSArmin Le Grand                     if(fPos < fMax)
824ddde725dSArmin Le Grand                     {
825ddde725dSArmin Le Grand                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
826ddde725dSArmin Le Grand                         // else the start and end pads are already created and fPos == fMax.
827ddde725dSArmin Le Grand                         // For radial there is no way to transform the already created
828ddde725dSArmin Le Grand                         // central run, it needs to be created from 1.0 to fMax
829ddde725dSArmin Le Grand                         sal_Int32 nOffset(1);
830ddde725dSArmin Le Grand 
831ddde725dSArmin Le Grand                         while(fPos < fMax)
832ddde725dSArmin Le Grand                         {
833ddde725dSArmin Le Grand                             const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
834ddde725dSArmin Le Grand 
835ddde725dSArmin Le Grand                             if(bMirror)
836ddde725dSArmin Le Grand                             {
837ddde725dSArmin Le Grand                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset);
838ddde725dSArmin Le Grand                             }
839ddde725dSArmin Le Grand                             else
840ddde725dSArmin Le Grand                             {
841ddde725dSArmin Le Grand                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset);
842ddde725dSArmin Le Grand                             }
843ddde725dSArmin Le Grand 
844ddde725dSArmin Le Grand                             nOffset++;
845ddde725dSArmin Le Grand                             fPos += 1.0;
846ddde725dSArmin Le Grand                         }
847ddde725dSArmin Le Grand                     }
848ddde725dSArmin Le Grand                 }
849ddde725dSArmin Le Grand 
850ddde725dSArmin Le Grand                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject, true);
851ddde725dSArmin Le Grand             }
852ddde725dSArmin Le Grand 
853ddde725dSArmin Le Grand             return xRetval;
854ddde725dSArmin Le Grand         }
855ddde725dSArmin Le Grand 
SvgRadialGradientPrimitive2D(const basegfx::B2DHomMatrix & rGradientTransform,const basegfx::B2DPolyPolygon & rPolyPolygon,const SvgGradientEntryVector & rGradientEntries,const basegfx::B2DPoint & rStart,double fRadius,bool bUseUnitCoordinates,SpreadMethod aSpreadMethod,const basegfx::B2DPoint * pFocal)856ddde725dSArmin Le Grand         SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D(
85701e92ad6SArmin Le Grand             const basegfx::B2DHomMatrix& rGradientTransform,
858ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
859ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
860ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
861ddde725dSArmin Le Grand             double fRadius,
862804e0487SArmin Le Grand             bool bUseUnitCoordinates,
863ddde725dSArmin Le Grand             SpreadMethod aSpreadMethod,
86439551d71SArmin Le Grand             const basegfx::B2DPoint* pFocal)
865ddde725dSArmin Le Grand         :   BufferedDecompositionPrimitive2D(),
86601e92ad6SArmin Le Grand             SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod),
867ddde725dSArmin Le Grand             mfRadius(fRadius),
868ddde725dSArmin Le Grand             maFocal(rStart),
869ddde725dSArmin Le Grand             maFocalVector(0.0, 0.0),
870ddde725dSArmin Le Grand             maFocalLength(0.0),
871ddde725dSArmin Le Grand             maMirroredGradientEntries(),
872ddde725dSArmin Le Grand             mbFocalSet(false)
873ddde725dSArmin Le Grand         {
874025b0597SArmin Le Grand             if(pFocal && !pFocal->equal(getStart()))
875ddde725dSArmin Le Grand             {
876ddde725dSArmin Le Grand                 maFocal = *pFocal;
877ddde725dSArmin Le Grand                 maFocalVector = maFocal - getStart();
878ddde725dSArmin Le Grand                 mbFocalSet = true;
879ddde725dSArmin Le Grand             }
880ddde725dSArmin Le Grand         }
881ddde725dSArmin Le Grand 
~SvgRadialGradientPrimitive2D()882025b0597SArmin Le Grand         SvgRadialGradientPrimitive2D::~SvgRadialGradientPrimitive2D()
883025b0597SArmin Le Grand         {
884025b0597SArmin Le Grand         }
885025b0597SArmin Le Grand 
operator ==(const BasePrimitive2D & rPrimitive) const886ddde725dSArmin Le Grand         bool SvgRadialGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
887ddde725dSArmin Le Grand         {
888ddde725dSArmin Le Grand             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
889ddde725dSArmin Le Grand 
890ddde725dSArmin Le Grand             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
891ddde725dSArmin Le Grand             {
892ddde725dSArmin Le Grand                 const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive);
893ddde725dSArmin Le Grand 
894ddde725dSArmin Le Grand                 if(getRadius() == rCompare.getRadius())
895ddde725dSArmin Le Grand                 {
896ddde725dSArmin Le Grand                     if(isFocalSet() == rCompare.isFocalSet())
897ddde725dSArmin Le Grand                     {
898ddde725dSArmin Le Grand                         if(isFocalSet())
899ddde725dSArmin Le Grand                         {
900ddde725dSArmin Le Grand                             return getFocal() == rCompare.getFocal();
901ddde725dSArmin Le Grand                         }
902ddde725dSArmin Le Grand                         else
903ddde725dSArmin Le Grand                         {
904ddde725dSArmin Le Grand                             return true;
905ddde725dSArmin Le Grand                         }
906ddde725dSArmin Le Grand                     }
907ddde725dSArmin Le Grand                 }
908ddde725dSArmin Le Grand             }
909ddde725dSArmin Le Grand 
910ddde725dSArmin Le Grand             return false;
911ddde725dSArmin Le Grand         }
912ddde725dSArmin Le Grand 
getB2DRange(const geometry::ViewInformation2D &) const913ddde725dSArmin Le Grand         basegfx::B2DRange SvgRadialGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
914ddde725dSArmin Le Grand         {
915ddde725dSArmin Le Grand             // return ObjectRange
916ddde725dSArmin Le Grand             return getPolyPolygon().getB2DRange();
917ddde725dSArmin Le Grand         }
918ddde725dSArmin Le Grand 
919ddde725dSArmin Le Grand         // provide unique ID
920ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D)
921ddde725dSArmin Le Grand 
922ddde725dSArmin Le Grand     } // end of namespace primitive2d
923ddde725dSArmin Le Grand } // end of namespace drawinglayer
924ddde725dSArmin Le Grand 
925ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
926ddde725dSArmin Le Grand // SvgLinearAtomPrimitive2D class
927ddde725dSArmin Le Grand 
928ddde725dSArmin Le Grand namespace drawinglayer
929ddde725dSArmin Le Grand {
930ddde725dSArmin Le Grand     namespace primitive2d
931ddde725dSArmin Le Grand     {
create2DDecomposition(const geometry::ViewInformation2D &) const932e2bf1e9dSArmin Le Grand         Primitive2DSequence SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
933ddde725dSArmin Le Grand         {
934ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
935ddde725dSArmin Le Grand             const double fDelta(getOffsetB() - getOffsetA());
936ddde725dSArmin Le Grand 
937ddde725dSArmin Le Grand             if(!basegfx::fTools::equalZero(fDelta))
938ddde725dSArmin Le Grand             {
93939551d71SArmin Le Grand                 // use one discrete unit for overlap (one pixel)
94039551d71SArmin Le Grand                 const double fDiscreteUnit(getDiscreteUnit());
94139551d71SArmin Le Grand 
94239551d71SArmin Le Grand                 // use color distance and discrete lengths to calculate step count
94339551d71SArmin Le Grand                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDelta, fDiscreteUnit));
94439551d71SArmin Le Grand 
945025b0597SArmin Le Grand                 // prepare polygon in needed width at start position (with discrete overlap)
946ddde725dSArmin Le Grand                 const basegfx::B2DPolygon aPolygon(
947ddde725dSArmin Le Grand                     basegfx::tools::createPolygonFromRect(
948ddde725dSArmin Le Grand                         basegfx::B2DRange(
94939551d71SArmin Le Grand                             getOffsetA() - fDiscreteUnit,
950ddde725dSArmin Le Grand                             0.0,
951025b0597SArmin Le Grand                             getOffsetA() + (fDelta / nSteps) + fDiscreteUnit,
952ddde725dSArmin Le Grand                             1.0)));
953ddde725dSArmin Le Grand 
954025b0597SArmin Le Grand                 // prepare loop (inside to outside, [0.0 .. 1.0[)
955025b0597SArmin Le Grand                 double fUnitScale(0.0);
956025b0597SArmin Le Grand                 const double fUnitStep(1.0 / nSteps);
957025b0597SArmin Le Grand 
958025b0597SArmin Le Grand                 // prepare result set (known size)
959ddde725dSArmin Le Grand                 xRetval.realloc(nSteps);
960ddde725dSArmin Le Grand 
961025b0597SArmin Le Grand                 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep)
962ddde725dSArmin Le Grand                 {
96339551d71SArmin Le Grand                     basegfx::B2DPolygon aNew(aPolygon);
964ddde725dSArmin Le Grand 
965025b0597SArmin Le Grand                     aNew.transform(basegfx::tools::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0));
966ddde725dSArmin Le Grand                     xRetval[a] = new PolyPolygonColorPrimitive2D(
96739551d71SArmin Le Grand                         basegfx::B2DPolyPolygon(aNew),
968025b0597SArmin Le Grand                         basegfx::interpolate(getColorA(), getColorB(), fUnitScale));
969ddde725dSArmin Le Grand                 }
970ddde725dSArmin Le Grand             }
971ddde725dSArmin Le Grand 
972ddde725dSArmin Le Grand             return xRetval;
973ddde725dSArmin Le Grand         }
974ddde725dSArmin Le Grand 
SvgLinearAtomPrimitive2D(const basegfx::BColor & aColorA,double fOffsetA,const basegfx::BColor & aColorB,double fOffsetB)97539551d71SArmin Le Grand         SvgLinearAtomPrimitive2D::SvgLinearAtomPrimitive2D(
97639551d71SArmin Le Grand             const basegfx::BColor& aColorA, double fOffsetA,
97739551d71SArmin Le Grand             const basegfx::BColor& aColorB, double fOffsetB)
97839551d71SArmin Le Grand         :   DiscreteMetricDependentPrimitive2D(),
97939551d71SArmin Le Grand             maColorA(aColorA),
98039551d71SArmin Le Grand             maColorB(aColorB),
98139551d71SArmin Le Grand             mfOffsetA(fOffsetA),
98239551d71SArmin Le Grand             mfOffsetB(fOffsetB)
98339551d71SArmin Le Grand         {
98439551d71SArmin Le Grand             if(mfOffsetA > mfOffsetB)
98539551d71SArmin Le Grand             {
98639551d71SArmin Le Grand                 OSL_ENSURE(false, "Wrong offset order (!)");
98739551d71SArmin Le Grand                 ::std::swap(mfOffsetA, mfOffsetB);
98839551d71SArmin Le Grand             }
98939551d71SArmin Le Grand         }
99039551d71SArmin Le Grand 
operator ==(const BasePrimitive2D & rPrimitive) const991ddde725dSArmin Le Grand         bool SvgLinearAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
992ddde725dSArmin Le Grand         {
993ddde725dSArmin Le Grand             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
994ddde725dSArmin Le Grand             {
995ddde725dSArmin Le Grand                 const SvgLinearAtomPrimitive2D& rCompare = static_cast< const SvgLinearAtomPrimitive2D& >(rPrimitive);
996ddde725dSArmin Le Grand 
997ddde725dSArmin Le Grand                 return (getColorA() == rCompare.getColorA()
998ddde725dSArmin Le Grand                     && getColorB() == rCompare.getColorB()
999ddde725dSArmin Le Grand                     && getOffsetA() == rCompare.getOffsetA()
100039551d71SArmin Le Grand                     && getOffsetB() == rCompare.getOffsetB());
1001ddde725dSArmin Le Grand             }
1002ddde725dSArmin Le Grand 
1003ddde725dSArmin Le Grand             return false;
1004ddde725dSArmin Le Grand         }
1005ddde725dSArmin Le Grand 
1006ddde725dSArmin Le Grand         // provide unique ID
1007ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D)
1008ddde725dSArmin Le Grand 
1009ddde725dSArmin Le Grand     } // end of namespace primitive2d
1010ddde725dSArmin Le Grand } // end of namespace drawinglayer
1011ddde725dSArmin Le Grand 
1012ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1013ddde725dSArmin Le Grand // SvgRadialAtomPrimitive2D class
1014ddde725dSArmin Le Grand 
1015ddde725dSArmin Le Grand namespace drawinglayer
1016ddde725dSArmin Le Grand {
1017ddde725dSArmin Le Grand     namespace primitive2d
1018ddde725dSArmin Le Grand     {
create2DDecomposition(const geometry::ViewInformation2D &) const1019ddde725dSArmin Le Grand         Primitive2DSequence SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
1020ddde725dSArmin Le Grand         {
1021ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
1022ddde725dSArmin Le Grand             const double fDeltaScale(getScaleB() - getScaleA());
1023ddde725dSArmin Le Grand 
1024ddde725dSArmin Le Grand             if(!basegfx::fTools::equalZero(fDeltaScale))
1025ddde725dSArmin Le Grand             {
102639551d71SArmin Le Grand                 // use one discrete unit for overlap (one pixel)
102739551d71SArmin Le Grand                 const double fDiscreteUnit(getDiscreteUnit());
1028ddde725dSArmin Le Grand 
102939551d71SArmin Le Grand                 // use color distance and discrete lengths to calculate step count
103039551d71SArmin Le Grand                 const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDeltaScale, fDiscreteUnit));
1031ddde725dSArmin Le Grand 
1032025b0597SArmin Le Grand                 // prepare loop ([0.0 .. 1.0[, full polygons, no polypolygons with holes)
1033025b0597SArmin Le Grand                 double fUnitScale(0.0);
1034025b0597SArmin Le Grand                 const double fUnitStep(1.0 / nSteps);
1035ddde725dSArmin Le Grand 
1036025b0597SArmin Le Grand                 // prepare result set (known size)
1037ddde725dSArmin Le Grand                 xRetval.realloc(nSteps);
1038ddde725dSArmin Le Grand 
1039025b0597SArmin Le Grand                 for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep)
1040ddde725dSArmin Le Grand                 {
104139551d71SArmin Le Grand                     basegfx::B2DHomMatrix aTransform;
1042025b0597SArmin Le Grand                     const double fEndScale(getScaleB() - (fDeltaScale * fUnitScale));
1043ddde725dSArmin Le Grand 
104439551d71SArmin Le Grand                     if(isTranslateSet())
1045ddde725dSArmin Le Grand                     {
104639551d71SArmin Le Grand                         const basegfx::B2DVector aTranslate(
104739551d71SArmin Le Grand                             basegfx::interpolate(
104839551d71SArmin Le Grand                                 getTranslateB(),
1049025b0597SArmin Le Grand                                 getTranslateA(),
105039551d71SArmin Le Grand                                 fUnitScale));
1051ddde725dSArmin Le Grand 
105239551d71SArmin Le Grand                         aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
105339551d71SArmin Le Grand                             fEndScale,
105439551d71SArmin Le Grand                             fEndScale,
105539551d71SArmin Le Grand                             aTranslate.getX(),
105639551d71SArmin Le Grand                             aTranslate.getY());
1057ddde725dSArmin Le Grand                     }
1058ddde725dSArmin Le Grand                     else
1059ddde725dSArmin Le Grand                     {
106039551d71SArmin Le Grand                         aTransform = basegfx::tools::createScaleB2DHomMatrix(
106139551d71SArmin Le Grand                             fEndScale,
106239551d71SArmin Le Grand                             fEndScale);
1063ddde725dSArmin Le Grand                     }
1064ddde725dSArmin Le Grand 
106539551d71SArmin Le Grand                     basegfx::B2DPolygon aNew(basegfx::tools::createPolygonFromUnitCircle());
1066ddde725dSArmin Le Grand 
106739551d71SArmin Le Grand                     aNew.transform(aTransform);
106839551d71SArmin Le Grand                     xRetval[a] = new PolyPolygonColorPrimitive2D(
106939551d71SArmin Le Grand                         basegfx::B2DPolyPolygon(aNew),
1070025b0597SArmin Le Grand                         basegfx::interpolate(getColorB(), getColorA(), fUnitScale));
1071ddde725dSArmin Le Grand                 }
1072ddde725dSArmin Le Grand             }
1073ddde725dSArmin Le Grand 
1074ddde725dSArmin Le Grand             return xRetval;
1075ddde725dSArmin Le Grand         }
1076ddde725dSArmin Le Grand 
SvgRadialAtomPrimitive2D(const basegfx::BColor & aColorA,double fScaleA,const basegfx::B2DVector & rTranslateA,const basegfx::BColor & aColorB,double fScaleB,const basegfx::B2DVector & rTranslateB)107739551d71SArmin Le Grand         SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D(
107839551d71SArmin Le Grand             const basegfx::BColor& aColorA, double fScaleA, const basegfx::B2DVector& rTranslateA,
107939551d71SArmin Le Grand             const basegfx::BColor& aColorB, double fScaleB, const basegfx::B2DVector& rTranslateB)
108039551d71SArmin Le Grand         :   DiscreteMetricDependentPrimitive2D(),
108139551d71SArmin Le Grand             maColorA(aColorA),
108239551d71SArmin Le Grand             maColorB(aColorB),
108339551d71SArmin Le Grand             mfScaleA(fScaleA),
108439551d71SArmin Le Grand             mfScaleB(fScaleB),
108539551d71SArmin Le Grand             mpTranslate(0)
108639551d71SArmin Le Grand         {
108739551d71SArmin Le Grand             // check and evtl. set translations
108839551d71SArmin Le Grand             if(!rTranslateA.equal(rTranslateB))
108939551d71SArmin Le Grand             {
109039551d71SArmin Le Grand                 mpTranslate = new VectorPair(rTranslateA, rTranslateB);
109139551d71SArmin Le Grand             }
109239551d71SArmin Le Grand 
109339551d71SArmin Le Grand             // scale A and B have to be positive
109439551d71SArmin Le Grand             mfScaleA = ::std::max(mfScaleA, 0.0);
109539551d71SArmin Le Grand             mfScaleB = ::std::max(mfScaleB, 0.0);
109639551d71SArmin Le Grand 
109739551d71SArmin Le Grand             // scale B has to be bigger than scale A; swap if different
109839551d71SArmin Le Grand             if(mfScaleA > mfScaleB)
109939551d71SArmin Le Grand             {
110039551d71SArmin Le Grand                 OSL_ENSURE(false, "Wrong offset order (!)");
110139551d71SArmin Le Grand                 ::std::swap(mfScaleA, mfScaleB);
110239551d71SArmin Le Grand 
110339551d71SArmin Le Grand                 if(mpTranslate)
110439551d71SArmin Le Grand                 {
110539551d71SArmin Le Grand                     ::std::swap(mpTranslate->maTranslateA, mpTranslate->maTranslateB);
110639551d71SArmin Le Grand                 }
110739551d71SArmin Le Grand             }
110839551d71SArmin Le Grand         }
110939551d71SArmin Le Grand 
SvgRadialAtomPrimitive2D(const basegfx::BColor & aColorA,double fScaleA,const basegfx::BColor & aColorB,double fScaleB)111039551d71SArmin Le Grand         SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D(
111139551d71SArmin Le Grand             const basegfx::BColor& aColorA, double fScaleA,
111239551d71SArmin Le Grand             const basegfx::BColor& aColorB, double fScaleB)
111339551d71SArmin Le Grand         :   DiscreteMetricDependentPrimitive2D(),
111439551d71SArmin Le Grand             maColorA(aColorA),
111539551d71SArmin Le Grand             maColorB(aColorB),
111639551d71SArmin Le Grand             mfScaleA(fScaleA),
111739551d71SArmin Le Grand             mfScaleB(fScaleB),
111839551d71SArmin Le Grand             mpTranslate(0)
111939551d71SArmin Le Grand         {
112039551d71SArmin Le Grand             // scale A and B have to be positive
112139551d71SArmin Le Grand             mfScaleA = ::std::max(mfScaleA, 0.0);
112239551d71SArmin Le Grand             mfScaleB = ::std::max(mfScaleB, 0.0);
112339551d71SArmin Le Grand 
112439551d71SArmin Le Grand             // scale B has to be bigger than scale A; swap if different
112539551d71SArmin Le Grand             if(mfScaleA > mfScaleB)
112639551d71SArmin Le Grand             {
112739551d71SArmin Le Grand                 OSL_ENSURE(false, "Wrong offset order (!)");
112839551d71SArmin Le Grand                 ::std::swap(mfScaleA, mfScaleB);
112939551d71SArmin Le Grand             }
113039551d71SArmin Le Grand         }
113139551d71SArmin Le Grand 
~SvgRadialAtomPrimitive2D()113239551d71SArmin Le Grand         SvgRadialAtomPrimitive2D::~SvgRadialAtomPrimitive2D()
113339551d71SArmin Le Grand         {
113439551d71SArmin Le Grand             if(mpTranslate)
113539551d71SArmin Le Grand             {
113639551d71SArmin Le Grand                 delete mpTranslate;
113739551d71SArmin Le Grand                 mpTranslate = 0;
113839551d71SArmin Le Grand             }
113939551d71SArmin Le Grand         }
114039551d71SArmin Le Grand 
operator ==(const BasePrimitive2D & rPrimitive) const1141ddde725dSArmin Le Grand         bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1142ddde725dSArmin Le Grand         {
1143ddde725dSArmin Le Grand             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
1144ddde725dSArmin Le Grand             {
1145ddde725dSArmin Le Grand                 const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive);
1146ddde725dSArmin Le Grand 
114739551d71SArmin Le Grand                 if(getColorA() == rCompare.getColorA()
1148ddde725dSArmin Le Grand                     && getColorB() == rCompare.getColorB()
1149ddde725dSArmin Le Grand                     && getScaleA() == rCompare.getScaleA()
115039551d71SArmin Le Grand                     && getScaleB() == rCompare.getScaleB())
115139551d71SArmin Le Grand                 {
115239551d71SArmin Le Grand                     if(isTranslateSet() && rCompare.isTranslateSet())
115339551d71SArmin Le Grand                     {
115439551d71SArmin Le Grand                         return (getTranslateA() == rCompare.getTranslateA()
115539551d71SArmin Le Grand                             && getTranslateB() == rCompare.getTranslateB());
115639551d71SArmin Le Grand                     }
115739551d71SArmin Le Grand                     else if(!isTranslateSet() && !rCompare.isTranslateSet())
115839551d71SArmin Le Grand                     {
115939551d71SArmin Le Grand                         return true;
116039551d71SArmin Le Grand                     }
116139551d71SArmin Le Grand                 }
1162ddde725dSArmin Le Grand             }
1163ddde725dSArmin Le Grand 
1164ddde725dSArmin Le Grand             return false;
1165ddde725dSArmin Le Grand         }
1166ddde725dSArmin Le Grand 
1167ddde725dSArmin Le Grand         // provide unique ID
1168ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D)
1169ddde725dSArmin Le Grand 
1170ddde725dSArmin Le Grand     } // end of namespace primitive2d
1171ddde725dSArmin Le Grand } // end of namespace drawinglayer
1172ddde725dSArmin Le Grand 
1173ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1174ddde725dSArmin Le Grand // eof
1175