xref: /trunk/main/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx (revision e2bf1e9da236996a1b93912513a09414a2616846)
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  *
11ddde725dSArmin 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 
44ddde725dSArmin Le Grand namespace drawinglayer
45ddde725dSArmin Le Grand {
46ddde725dSArmin Le Grand     namespace primitive2d
47ddde725dSArmin Le Grand     {
48ddde725dSArmin Le Grand         Primitive2DSequence SvgGradientHelper::createSingleGradientEntryFill() const
49ddde725dSArmin Le Grand         {
50ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries = getGradientEntries();
51ddde725dSArmin Le Grand             const sal_uInt32 nCount(rEntries.size());
52ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
53ddde725dSArmin Le Grand 
54ddde725dSArmin Le Grand             if(nCount)
55ddde725dSArmin Le Grand             {
56ddde725dSArmin Le Grand                 const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1];
57ddde725dSArmin Le Grand                 const double fOpacity(rSingleEntry.getOpacity());
58ddde725dSArmin Le Grand 
59ddde725dSArmin Le Grand                 if(fOpacity > 0.0)
60ddde725dSArmin Le Grand                 {
61ddde725dSArmin Le Grand                     Primitive2DReference xRef(
62ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
63ddde725dSArmin Le Grand                             getPolyPolygon(),
64ddde725dSArmin Le Grand                             rSingleEntry.getColor()));
65ddde725dSArmin Le Grand 
66ddde725dSArmin Le Grand                     if(fOpacity < 1.0)
67ddde725dSArmin Le Grand                     {
68ddde725dSArmin Le Grand                         const Primitive2DSequence aContent(&xRef, 1);
69ddde725dSArmin Le Grand 
70ddde725dSArmin Le Grand                         xRef = Primitive2DReference(
71ddde725dSArmin Le Grand                             new UnifiedTransparencePrimitive2D(
72ddde725dSArmin Le Grand                                 aContent,
73ddde725dSArmin Le Grand                                 1.0 - fOpacity));
74ddde725dSArmin Le Grand                     }
75ddde725dSArmin Le Grand 
76ddde725dSArmin Le Grand                     xRetval = Primitive2DSequence(&xRef, 1);
77ddde725dSArmin Le Grand                 }
78ddde725dSArmin Le Grand             }
79ddde725dSArmin Le Grand             else
80ddde725dSArmin Le Grand             {
81ddde725dSArmin Le Grand                 OSL_ENSURE(false, "Single gradient entry construction without entry (!)");
82ddde725dSArmin Le Grand             }
83ddde725dSArmin Le Grand 
84ddde725dSArmin Le Grand             return xRetval;
85ddde725dSArmin Le Grand         }
86ddde725dSArmin Le Grand 
87ddde725dSArmin Le Grand         void SvgGradientHelper::checkPreconditions()
88ddde725dSArmin Le Grand         {
89ddde725dSArmin Le Grand             mbPreconditionsChecked = true;
90ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries = getGradientEntries();
91ddde725dSArmin Le Grand 
92ddde725dSArmin Le Grand             if(rEntries.empty())
93ddde725dSArmin Le Grand             {
94ddde725dSArmin Le Grand                 // no fill at all
95ddde725dSArmin Le Grand             }
96ddde725dSArmin Le Grand             else
97ddde725dSArmin Le Grand             {
98ddde725dSArmin Le Grand                 const sal_uInt32 nCount(rEntries.size());
99ddde725dSArmin Le Grand 
100ddde725dSArmin Le Grand                 if(1 == nCount)
101ddde725dSArmin Le Grand                 {
102ddde725dSArmin Le Grand                     // fill with single existing color
103ddde725dSArmin Le Grand                     setSingleEntry();
104ddde725dSArmin Le Grand                 }
105ddde725dSArmin Le Grand                 else
106ddde725dSArmin Le Grand                 {
107ddde725dSArmin Le Grand                     // sort maGradientEntries when more than one
108ddde725dSArmin Le Grand                     std::sort(maGradientEntries.begin(), maGradientEntries.end());
109ddde725dSArmin Le Grand 
110ddde725dSArmin Le Grand                     // gradient with at least two colors
111ddde725dSArmin Le Grand                     bool bAllInvisible(true);
112ddde725dSArmin Le Grand 
113ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nCount; a++)
114ddde725dSArmin Le Grand                     {
115ddde725dSArmin Le Grand                         const SvgGradientEntry& rCandidate = rEntries[a];
116ddde725dSArmin Le Grand 
117ddde725dSArmin Le Grand                         if(basegfx::fTools::equalZero(rCandidate.getOpacity()))
118ddde725dSArmin Le Grand                         {
119ddde725dSArmin Le Grand                             // invisible
120ddde725dSArmin Le Grand                             mbFullyOpaque = false;
121ddde725dSArmin Le Grand                         }
122ddde725dSArmin Le Grand                         else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0))
123ddde725dSArmin Le Grand                         {
124ddde725dSArmin Le Grand                             // completely opaque
125ddde725dSArmin Le Grand                             bAllInvisible = false;
126ddde725dSArmin Le Grand                         }
127ddde725dSArmin Le Grand                         else
128ddde725dSArmin Le Grand                         {
129ddde725dSArmin Le Grand                             // opacity
130ddde725dSArmin Le Grand                             bAllInvisible = false;
131ddde725dSArmin Le Grand                             mbFullyOpaque = false;
132ddde725dSArmin Le Grand                         }
133ddde725dSArmin Le Grand                     }
134ddde725dSArmin Le Grand 
135ddde725dSArmin Le Grand                     if(bAllInvisible)
136ddde725dSArmin Le Grand                     {
137ddde725dSArmin Le Grand                         // all invisible, nothing to do
138ddde725dSArmin Le Grand                     }
139ddde725dSArmin Le Grand                     else
140ddde725dSArmin Le Grand                     {
141ddde725dSArmin Le Grand                         const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
142ddde725dSArmin Le Grand 
143ddde725dSArmin Le Grand                         if(aPolyRange.isEmpty())
144ddde725dSArmin Le Grand                         {
145ddde725dSArmin Le Grand                             // no range to fill, nothing to do
146ddde725dSArmin Le Grand                         }
147ddde725dSArmin Le Grand                         else
148ddde725dSArmin Le Grand                         {
149ddde725dSArmin Le Grand                             const double fPolyWidth(aPolyRange.getWidth());
150ddde725dSArmin Le Grand                             const double fPolyHeight(aPolyRange.getHeight());
151ddde725dSArmin Le Grand 
152ddde725dSArmin Le Grand                             if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight))
153ddde725dSArmin Le Grand                             {
154ddde725dSArmin Le Grand                                 // no width/height to fill, nothing to do
155ddde725dSArmin Le Grand                             }
156ddde725dSArmin Le Grand                             else
157ddde725dSArmin Le Grand                             {
158ddde725dSArmin Le Grand                                 mbCreatesContent = true;
159ddde725dSArmin Le Grand                             }
160ddde725dSArmin Le Grand                         }
161ddde725dSArmin Le Grand                     }
162ddde725dSArmin Le Grand                 }
163ddde725dSArmin Le Grand             }
164ddde725dSArmin Le Grand         }
165ddde725dSArmin Le Grand 
166ddde725dSArmin Le Grand         double SvgGradientHelper::createRun(
167ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
168ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
169ddde725dSArmin Le Grand             double fPos,
170ddde725dSArmin Le Grand             double fMax,
171ddde725dSArmin Le Grand             const SvgGradientEntryVector& rEntries,
172ddde725dSArmin Le Grand             sal_Int32 nOffset) const
173ddde725dSArmin Le Grand         {
174ddde725dSArmin Le Grand             const sal_uInt32 nCount(rEntries.size());
175ddde725dSArmin Le Grand 
176ddde725dSArmin Le Grand             if(nCount)
177ddde725dSArmin Le Grand             {
178ddde725dSArmin Le Grand                 const SvgGradientEntry& rStart = rEntries[0];
179ddde725dSArmin Le Grand                 const bool bCreateStartPad(fPos < 0.0 && Spread_pad == getSpreadMethod());
180ddde725dSArmin Le Grand                 const bool bCreateStartFill(rStart.getOffset() > 0.0);
181ddde725dSArmin Le Grand                 sal_uInt32 nIndex(0);
182ddde725dSArmin Le Grand 
183ddde725dSArmin Le Grand                 if(bCreateStartPad || bCreateStartFill)
184ddde725dSArmin Le Grand                 {
185ddde725dSArmin Le Grand                     const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity());
186ddde725dSArmin Le Grand 
187ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset);
188ddde725dSArmin Le Grand                     fPos = rStart.getOffset();
189ddde725dSArmin Le Grand                 }
190ddde725dSArmin Le Grand 
191ddde725dSArmin Le Grand                 while(fPos < 1.0 && nIndex + 1 < nCount)
192ddde725dSArmin Le Grand                 {
193ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidateA = rEntries[nIndex++];
194ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidateB = rEntries[nIndex];
195ddde725dSArmin Le Grand 
196ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset);
197ddde725dSArmin Le Grand                     fPos = rCandidateB.getOffset();
198ddde725dSArmin Le Grand                 }
199ddde725dSArmin Le Grand 
200ddde725dSArmin Le Grand                 const SvgGradientEntry& rEnd = rEntries[nCount - 1];
201ddde725dSArmin Le Grand                 const bool bCreateEndPad(fPos < fMax && Spread_pad == getSpreadMethod());
202ddde725dSArmin Le Grand                 const bool bCreateEndFill(rEnd.getOffset() < 1.0);
203ddde725dSArmin Le Grand 
204ddde725dSArmin Le Grand                 if(bCreateEndPad || bCreateEndFill)
205ddde725dSArmin Le Grand                 {
206ddde725dSArmin Le Grand                     fPos = bCreateEndPad ? fMax : 1.0;
207ddde725dSArmin Le Grand                     const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity());
208ddde725dSArmin Le Grand 
209ddde725dSArmin Le Grand                     createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset);
210ddde725dSArmin Le Grand                 }
211ddde725dSArmin Le Grand             }
212ddde725dSArmin Le Grand             else
213ddde725dSArmin Le Grand             {
214ddde725dSArmin Le Grand                 OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)");
215ddde725dSArmin Le Grand                 fPos = fMax;
216ddde725dSArmin Le Grand             }
217ddde725dSArmin Le Grand 
218ddde725dSArmin Le Grand             return fPos;
219ddde725dSArmin Le Grand         }
220ddde725dSArmin Le Grand 
221ddde725dSArmin Le Grand         Primitive2DSequence SvgGradientHelper::createResult(
222ddde725dSArmin Le Grand             const Primitive2DVector& rTargetColor,
223ddde725dSArmin Le Grand             const Primitive2DVector& rTargetOpacity,
224ddde725dSArmin Le Grand             const basegfx::B2DHomMatrix& rUnitGradientToObject,
225ddde725dSArmin Le Grand             bool bInvert) const
226ddde725dSArmin Le Grand         {
227ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
228ddde725dSArmin Le Grand             const Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(rTargetColor, bInvert));
229ddde725dSArmin Le Grand             const Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(rTargetOpacity, bInvert));
230ddde725dSArmin Le Grand 
231ddde725dSArmin Le Grand             if(aTargetColorEntries.hasElements())
232ddde725dSArmin Le Grand             {
233ddde725dSArmin Le Grand                 Primitive2DReference xRefContent;
234ddde725dSArmin Le Grand 
235ddde725dSArmin Le Grand                 if(aTargetOpacityEntries.hasElements())
236ddde725dSArmin Le Grand                 {
237ddde725dSArmin Le Grand                     const Primitive2DReference xRefOpacity = new TransparencePrimitive2D(
238ddde725dSArmin Le Grand                         aTargetColorEntries,
239ddde725dSArmin Le Grand                         aTargetOpacityEntries);
240ddde725dSArmin Le Grand 
241ddde725dSArmin Le Grand                     xRefContent = new TransformPrimitive2D(
242ddde725dSArmin Le Grand                         rUnitGradientToObject,
243ddde725dSArmin Le Grand                         Primitive2DSequence(&xRefOpacity, 1));
244ddde725dSArmin Le Grand                 }
245ddde725dSArmin Le Grand                 else
246ddde725dSArmin Le Grand                 {
247ddde725dSArmin Le Grand                     xRefContent = new TransformPrimitive2D(
248ddde725dSArmin Le Grand                         rUnitGradientToObject,
249ddde725dSArmin Le Grand                         aTargetColorEntries);
250ddde725dSArmin Le Grand                 }
251ddde725dSArmin Le Grand 
252ddde725dSArmin Le Grand                 xRefContent = new MaskPrimitive2D(
253ddde725dSArmin Le Grand                     getPolyPolygon(),
254ddde725dSArmin Le Grand                     Primitive2DSequence(&xRefContent, 1));
255ddde725dSArmin Le Grand 
256ddde725dSArmin Le Grand                 xRetval = Primitive2DSequence(&xRefContent, 1);
257ddde725dSArmin Le Grand             }
258ddde725dSArmin Le Grand 
259ddde725dSArmin Le Grand             return xRetval;
260ddde725dSArmin Le Grand         }
261ddde725dSArmin Le Grand 
262ddde725dSArmin Le Grand         SvgGradientHelper::SvgGradientHelper(
263ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
264ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
265ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
266ddde725dSArmin Le Grand             SpreadMethod aSpreadMethod,
267ddde725dSArmin Le Grand             double fOverlapping)
268ddde725dSArmin Le Grand         :   maPolyPolygon(rPolyPolygon),
269ddde725dSArmin Le Grand             maGradientEntries(rGradientEntries),
270ddde725dSArmin Le Grand             maStart(rStart),
271ddde725dSArmin Le Grand             maSpreadMethod(aSpreadMethod),
272ddde725dSArmin Le Grand             mfOverlapping(fOverlapping),
273ddde725dSArmin Le Grand             mbPreconditionsChecked(false),
274ddde725dSArmin Le Grand             mbCreatesContent(false),
275ddde725dSArmin Le Grand             mbSingleEntry(false),
276ddde725dSArmin Le Grand             mbFullyOpaque(true)
277ddde725dSArmin Le Grand         {
278ddde725dSArmin Le Grand         }
279ddde725dSArmin Le Grand 
280ddde725dSArmin Le Grand         bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const
281ddde725dSArmin Le Grand         {
282ddde725dSArmin Le Grand             const SvgGradientHelper& rCompare = static_cast< const SvgGradientHelper& >(rSvgGradientHelper);
283ddde725dSArmin Le Grand 
284ddde725dSArmin Le Grand             return (getPolyPolygon() == rCompare.getPolyPolygon()
285ddde725dSArmin Le Grand                 && getGradientEntries() == rCompare.getGradientEntries()
286ddde725dSArmin Le Grand                 && getStart() == rCompare.getStart()
287ddde725dSArmin Le Grand                 && getSpreadMethod() == rCompare.getSpreadMethod()
288ddde725dSArmin Le Grand                 && getOverlapping() == rCompare.getOverlapping());
289ddde725dSArmin Le Grand         }
290ddde725dSArmin Le Grand 
291ddde725dSArmin Le Grand     } // end of namespace primitive2d
292ddde725dSArmin Le Grand } // end of namespace drawinglayer
293ddde725dSArmin Le Grand 
294ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
295ddde725dSArmin Le Grand 
296ddde725dSArmin Le Grand namespace drawinglayer
297ddde725dSArmin Le Grand {
298ddde725dSArmin Le Grand     namespace primitive2d
299ddde725dSArmin Le Grand     {
300ddde725dSArmin Le Grand         void SvgLinearGradientPrimitive2D::checkPreconditions()
301ddde725dSArmin Le Grand         {
302ddde725dSArmin Le Grand             // call parent
303ddde725dSArmin Le Grand             SvgGradientHelper::checkPreconditions();
304ddde725dSArmin Le Grand 
305ddde725dSArmin Le Grand             if(getCreatesContent())
306ddde725dSArmin Le Grand             {
307ddde725dSArmin Le Grand                 // Check Vector
308ddde725dSArmin Le Grand                 const basegfx::B2DVector aVector(getEnd() - getStart());
309ddde725dSArmin Le Grand 
310ddde725dSArmin Le Grand                 if(basegfx::fTools::equalZero(aVector.getX()) && basegfx::fTools::equalZero(aVector.getY()))
311ddde725dSArmin Le Grand                 {
312ddde725dSArmin Le Grand                     // fill with single color using last stop color
313ddde725dSArmin Le Grand                     setSingleEntry();
314ddde725dSArmin Le Grand                 }
315ddde725dSArmin Le Grand             }
316ddde725dSArmin Le Grand         }
317ddde725dSArmin Le Grand 
318ddde725dSArmin Le Grand         void SvgLinearGradientPrimitive2D::ensureGeometry(
319ddde725dSArmin Le Grand             basegfx::B2DPolyPolygon& rPolyPolygon,
320ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
321ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
322ddde725dSArmin Le Grand             sal_Int32 nOffset) const
323ddde725dSArmin Le Grand         {
324ddde725dSArmin Le Grand             if(!rPolyPolygon.count())
325ddde725dSArmin Le Grand             {
326ddde725dSArmin Le Grand                 rPolyPolygon.append(
327ddde725dSArmin Le Grand                     basegfx::tools::createPolygonFromRect(
328ddde725dSArmin Le Grand                         basegfx::B2DRange(
329ddde725dSArmin Le Grand                             rFrom.getOffset() - getOverlapping() + nOffset,
330ddde725dSArmin Le Grand                             0.0,
331ddde725dSArmin Le Grand                             rTo.getOffset() + getOverlapping() + nOffset,
332ddde725dSArmin Le Grand                             1.0)));
333ddde725dSArmin Le Grand             }
334ddde725dSArmin Le Grand         }
335ddde725dSArmin Le Grand 
336ddde725dSArmin Le Grand         void SvgLinearGradientPrimitive2D::createAtom(
337ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
338ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
339ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
340ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
341ddde725dSArmin Le Grand             sal_Int32 nOffset) const
342ddde725dSArmin Le Grand         {
343ddde725dSArmin Le Grand             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
344ddde725dSArmin Le Grand             if(rFrom.getOffset() == rTo.getOffset())
345ddde725dSArmin Le Grand             {
346ddde725dSArmin Le Grand                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
347ddde725dSArmin Le Grand             }
348ddde725dSArmin Le Grand             else
349ddde725dSArmin Le Grand             {
350ddde725dSArmin Le Grand                 const bool bColorChange(rFrom.getColor() != rTo.getColor());
351ddde725dSArmin Le Grand                 const bool bOpacityChange(rFrom.getOpacity() != rTo.getOpacity());
352ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aPolyPolygon;
353ddde725dSArmin Le Grand 
354ddde725dSArmin Le Grand                 if(bColorChange)
355ddde725dSArmin Le Grand                 {
356ddde725dSArmin Le Grand                     rTargetColor.push_back(
357ddde725dSArmin Le Grand                         new SvgLinearAtomPrimitive2D(
358ddde725dSArmin Le Grand                             rFrom.getColor(), rFrom.getOffset() + nOffset,
359ddde725dSArmin Le Grand                             rTo.getColor(), rTo.getOffset() + nOffset,
360ddde725dSArmin Le Grand                             getOverlapping()));
361ddde725dSArmin Le Grand                 }
362ddde725dSArmin Le Grand                 else
363ddde725dSArmin Le Grand                 {
364ddde725dSArmin Le Grand                     ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset);
365ddde725dSArmin Le Grand                     rTargetColor.push_back(
366ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
367ddde725dSArmin Le Grand                             aPolyPolygon,
368ddde725dSArmin Le Grand                             rFrom.getColor()));
369ddde725dSArmin Le Grand                 }
370ddde725dSArmin Le Grand 
371ddde725dSArmin Le Grand                 if(bOpacityChange)
372ddde725dSArmin Le Grand                 {
373ddde725dSArmin Le Grand                     const double fTransFrom(1.0 - rFrom.getOpacity());
374ddde725dSArmin Le Grand                     const double fTransTo(1.0 - rTo.getOpacity());
375ddde725dSArmin Le Grand 
376ddde725dSArmin Le Grand                     rTargetOpacity.push_back(
377ddde725dSArmin Le Grand                         new SvgLinearAtomPrimitive2D(
378ddde725dSArmin Le Grand                             basegfx::BColor(fTransFrom, fTransFrom, fTransFrom), rFrom.getOffset() + nOffset,
379ddde725dSArmin Le Grand                             basegfx::BColor(fTransTo,fTransTo, fTransTo), rTo.getOffset() + nOffset,
380ddde725dSArmin Le Grand                             getOverlapping()));
381ddde725dSArmin Le Grand                 }
382ddde725dSArmin Le Grand                 else if(!getFullyOpaque())
383ddde725dSArmin Le Grand                 {
384ddde725dSArmin Le Grand                     const double fTransparence(1.0 - rFrom.getOpacity());
385ddde725dSArmin Le Grand 
386ddde725dSArmin Le Grand                     ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset);
387ddde725dSArmin Le Grand                     rTargetOpacity.push_back(
388ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
389ddde725dSArmin Le Grand                             aPolyPolygon,
390ddde725dSArmin Le Grand                             basegfx::BColor(fTransparence, fTransparence, fTransparence)));
391ddde725dSArmin Le Grand                 }
392ddde725dSArmin Le Grand             }
393ddde725dSArmin Le Grand         }
394ddde725dSArmin Le Grand 
395ddde725dSArmin Le Grand         Primitive2DSequence SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
396ddde725dSArmin Le Grand         {
397ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
398ddde725dSArmin Le Grand 
399ddde725dSArmin Le Grand             if(!getPreconditionsChecked())
400ddde725dSArmin Le Grand             {
401ddde725dSArmin Le Grand                 const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions();
402ddde725dSArmin Le Grand             }
403ddde725dSArmin Le Grand 
404ddde725dSArmin Le Grand             if(getSingleEntry())
405ddde725dSArmin Le Grand             {
406ddde725dSArmin Le Grand                 // fill with last existing color
407ddde725dSArmin Le Grand                 xRetval = createSingleGradientEntryFill();
408ddde725dSArmin Le Grand             }
409ddde725dSArmin Le Grand             else if(getCreatesContent())
410ddde725dSArmin Le Grand             {
411ddde725dSArmin Le Grand                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
412ddde725dSArmin Le Grand                 // invisible, width and height to fill are not empty
413ddde725dSArmin Le Grand                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
414ddde725dSArmin Le Grand                 const double fPolyWidth(aPolyRange.getWidth());
415ddde725dSArmin Le Grand                 const double fPolyHeight(aPolyRange.getHeight());
416ddde725dSArmin Le Grand 
417ddde725dSArmin Le Grand                 // create ObjectTransform based on polygon range
418ddde725dSArmin Le Grand                 const basegfx::B2DHomMatrix aObjectTransform(
419ddde725dSArmin Le Grand                     basegfx::tools::createScaleTranslateB2DHomMatrix(
420ddde725dSArmin Le Grand                         fPolyWidth, fPolyHeight,
421ddde725dSArmin Le Grand                         aPolyRange.getMinX(), aPolyRange.getMinY()));
422ddde725dSArmin Le Grand 
423ddde725dSArmin Le Grand                 // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given
424ddde725dSArmin Le Grand                 // gradient vector defined by Start,End
425ddde725dSArmin Le Grand                 const basegfx::B2DVector aVector(getEnd() - getStart());
426ddde725dSArmin Le Grand                 const double fVectorLength(aVector.getLength());
427ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToGradient;
428ddde725dSArmin Le Grand 
429ddde725dSArmin Le Grand                 aUnitGradientToGradient.scale(fVectorLength, 1.0);
430ddde725dSArmin Le Grand                 aUnitGradientToGradient.rotate(atan2(aVector.getY(), aVector.getX()));
431ddde725dSArmin Le Grand                 aUnitGradientToGradient.translate(getStart().getX(), getStart().getY());
432ddde725dSArmin Le Grand 
433ddde725dSArmin Le Grand                 // create full transform from unit gradient coordinates to object coordinates
434ddde725dSArmin Le Grand                 // including the SvgGradient transformation
435ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToObject(aObjectTransform * aUnitGradientToGradient);
436ddde725dSArmin Le Grand 
437ddde725dSArmin Le Grand                 // create inverse from it
438ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
439ddde725dSArmin Le Grand                 aObjectToUnitGradient.invert();
440ddde725dSArmin Le Grand 
441ddde725dSArmin Le Grand                 // back-transform polygon to unit gradient coordinates and get
442ddde725dSArmin Le Grand                 // UnitRage. This is the range the gradient has to cover
443ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
444ddde725dSArmin Le Grand                 aUnitPoly.transform(aObjectToUnitGradient);
445ddde725dSArmin Le Grand                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
446ddde725dSArmin Le Grand 
447ddde725dSArmin Le Grand                 // prepare result vectors
448ddde725dSArmin Le Grand                 Primitive2DVector aTargetColor;
449ddde725dSArmin Le Grand                 Primitive2DVector aTargetOpacity;
450ddde725dSArmin Le Grand 
451ddde725dSArmin Le Grand                 if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0))
452ddde725dSArmin Le Grand                 {
453ddde725dSArmin Le Grand                     // add a pre-multiply to aUnitGradientToObject to allow
454ddde725dSArmin Le Grand                     // multiplication of the polygon(xl, 0.0, xr, 1.0)
455ddde725dSArmin Le Grand                     const basegfx::B2DHomMatrix aPreMultiply(
456ddde725dSArmin Le Grand                         basegfx::tools::createScaleTranslateB2DHomMatrix(
457ddde725dSArmin Le Grand                             1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY()));
458ddde725dSArmin Le Grand                     aUnitGradientToObject = aUnitGradientToObject * aPreMultiply;
459ddde725dSArmin Le Grand 
460ddde725dSArmin Le Grand                     // create central run, may also already do all necessary when
461ddde725dSArmin Le Grand                     // Spread_pad is set as SpreadMethod and/or the range is smaller
462ddde725dSArmin Le Grand                     double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0));
463ddde725dSArmin Le Grand 
464ddde725dSArmin Le Grand                     if(fPos < aUnitRange.getMaxX())
465ddde725dSArmin Le Grand                     {
466ddde725dSArmin Le Grand                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
467ddde725dSArmin Le Grand                         // else the start and end pads are already created and fPos == aUnitRange.getMaxX().
468ddde725dSArmin Le Grand                         // Its possible to express the repeated linear gradient by adding the
469ddde725dSArmin Le Grand                         // transformed central run. Crete it this way
470ddde725dSArmin Le Grand                         Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(aTargetColor));
471ddde725dSArmin Le Grand                         Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(aTargetOpacity));
472ddde725dSArmin Le Grand                         aTargetColor.clear();
473ddde725dSArmin Le Grand                         aTargetOpacity.clear();
474ddde725dSArmin Le Grand 
475ddde725dSArmin Le Grand                         if(aTargetColorEntries.hasElements())
476ddde725dSArmin Le Grand                         {
477ddde725dSArmin Le Grand                             // add original central run as group primitive
478ddde725dSArmin Le Grand                             aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries));
479ddde725dSArmin Le Grand 
480ddde725dSArmin Le Grand                             if(aTargetOpacityEntries.hasElements())
481ddde725dSArmin Le Grand                             {
482ddde725dSArmin Le Grand                                 aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries));
483ddde725dSArmin Le Grand                             }
484ddde725dSArmin Le Grand 
485ddde725dSArmin Le Grand                             // add negative runs
486ddde725dSArmin Le Grand                             fPos = 0.0;
487ddde725dSArmin Le Grand                             sal_Int32 nOffset(0);
488ddde725dSArmin Le Grand 
489ddde725dSArmin Le Grand                             while(fPos > aUnitRange.getMinX())
490ddde725dSArmin Le Grand                             {
491ddde725dSArmin Le Grand                                 fPos -= 1.0;
492ddde725dSArmin Le Grand                                 nOffset++;
493ddde725dSArmin Le Grand 
494ddde725dSArmin Le Grand                                 basegfx::B2DHomMatrix aTransform;
495ddde725dSArmin Le Grand                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
496ddde725dSArmin Le Grand 
497ddde725dSArmin Le Grand                                 if(bMirror)
498ddde725dSArmin Le Grand                                 {
499ddde725dSArmin Le Grand                                     aTransform.scale(-1.0, 1.0);
500ddde725dSArmin Le Grand                                     aTransform.translate(fPos + 1.0, 0.0);
501ddde725dSArmin Le Grand                                 }
502ddde725dSArmin Le Grand                                 else
503ddde725dSArmin Le Grand                                 {
504ddde725dSArmin Le Grand                                     aTransform.translate(fPos, 0.0);
505ddde725dSArmin Le Grand                                 }
506ddde725dSArmin Le Grand 
507ddde725dSArmin Le Grand                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
508ddde725dSArmin Le Grand 
509ddde725dSArmin Le Grand                                 if(aTargetOpacityEntries.hasElements())
510ddde725dSArmin Le Grand                                 {
511ddde725dSArmin Le Grand                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
512ddde725dSArmin Le Grand                                 }
513ddde725dSArmin Le Grand                             }
514ddde725dSArmin Le Grand 
515ddde725dSArmin Le Grand                             // add positive runs
516ddde725dSArmin Le Grand                             fPos = 1.0;
517ddde725dSArmin Le Grand                             nOffset = 1;
518ddde725dSArmin Le Grand 
519ddde725dSArmin Le Grand                             while(fPos < aUnitRange.getMaxX())
520ddde725dSArmin Le Grand                             {
521ddde725dSArmin Le Grand                                 basegfx::B2DHomMatrix aTransform;
522ddde725dSArmin Le Grand                                 const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
523ddde725dSArmin Le Grand 
524ddde725dSArmin Le Grand                                 if(bMirror)
525ddde725dSArmin Le Grand                                 {
526ddde725dSArmin Le Grand                                     aTransform.scale(-1.0, 1.0);
527ddde725dSArmin Le Grand                                     aTransform.translate(fPos + 1.0, 0.0);
528ddde725dSArmin Le Grand                                 }
529ddde725dSArmin Le Grand                                 else
530ddde725dSArmin Le Grand                                 {
531ddde725dSArmin Le Grand                                     aTransform.translate(fPos, 0.0);
532ddde725dSArmin Le Grand                                 }
533ddde725dSArmin Le Grand 
534ddde725dSArmin Le Grand                                 aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries));
535ddde725dSArmin Le Grand 
536ddde725dSArmin Le Grand                                 if(aTargetOpacityEntries.hasElements())
537ddde725dSArmin Le Grand                                 {
538ddde725dSArmin Le Grand                                     aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries));
539ddde725dSArmin Le Grand                                 }
540ddde725dSArmin Le Grand 
541ddde725dSArmin Le Grand                                 fPos += 1.0;
542ddde725dSArmin Le Grand                                 nOffset++;
543ddde725dSArmin Le Grand                             }
544ddde725dSArmin Le Grand                         }
545ddde725dSArmin Le Grand                     }
546ddde725dSArmin Le Grand                 }
547ddde725dSArmin Le Grand 
548ddde725dSArmin Le Grand                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject);
549ddde725dSArmin Le Grand             }
550ddde725dSArmin Le Grand 
551ddde725dSArmin Le Grand             return xRetval;
552ddde725dSArmin Le Grand         }
553ddde725dSArmin Le Grand 
554ddde725dSArmin Le Grand         SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D(
555ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
556ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
557ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
558ddde725dSArmin Le Grand             const basegfx::B2DPoint& rEnd,
559ddde725dSArmin Le Grand             SpreadMethod aSpreadMethod,
560ddde725dSArmin Le Grand             double fOverlapping)
561ddde725dSArmin Le Grand         :   BufferedDecompositionPrimitive2D(),
562ddde725dSArmin Le Grand             SvgGradientHelper(rPolyPolygon, rGradientEntries, rStart, aSpreadMethod, fOverlapping),
563ddde725dSArmin Le Grand             maEnd(rEnd)
564ddde725dSArmin Le Grand         {
565ddde725dSArmin Le Grand         }
566ddde725dSArmin Le Grand 
567ddde725dSArmin Le Grand         bool SvgLinearGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
568ddde725dSArmin Le Grand         {
569ddde725dSArmin Le Grand             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
570ddde725dSArmin Le Grand 
571ddde725dSArmin Le Grand             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
572ddde725dSArmin Le Grand             {
573ddde725dSArmin Le Grand                 const SvgLinearGradientPrimitive2D& rCompare = static_cast< const SvgLinearGradientPrimitive2D& >(rPrimitive);
574ddde725dSArmin Le Grand 
575ddde725dSArmin Le Grand                 return (getEnd() == rCompare.getEnd());
576ddde725dSArmin Le Grand             }
577ddde725dSArmin Le Grand 
578ddde725dSArmin Le Grand             return false;
579ddde725dSArmin Le Grand         }
580ddde725dSArmin Le Grand 
581ddde725dSArmin Le Grand         basegfx::B2DRange SvgLinearGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
582ddde725dSArmin Le Grand         {
583ddde725dSArmin Le Grand             // return ObjectRange
584ddde725dSArmin Le Grand             return getPolyPolygon().getB2DRange();
585ddde725dSArmin Le Grand         }
586ddde725dSArmin Le Grand 
587ddde725dSArmin Le Grand         // provide unique ID
588ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D)
589ddde725dSArmin Le Grand 
590ddde725dSArmin Le Grand     } // end of namespace primitive2d
591ddde725dSArmin Le Grand } // end of namespace drawinglayer
592ddde725dSArmin Le Grand 
593ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
594ddde725dSArmin Le Grand 
595ddde725dSArmin Le Grand namespace drawinglayer
596ddde725dSArmin Le Grand {
597ddde725dSArmin Le Grand     namespace primitive2d
598ddde725dSArmin Le Grand     {
599ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::checkPreconditions()
600ddde725dSArmin Le Grand         {
601ddde725dSArmin Le Grand             // call parent
602ddde725dSArmin Le Grand             SvgGradientHelper::checkPreconditions();
603ddde725dSArmin Le Grand 
604ddde725dSArmin Le Grand             if(getCreatesContent())
605ddde725dSArmin Le Grand             {
606ddde725dSArmin Le Grand                 // Check Radius
607ddde725dSArmin Le Grand                 if(basegfx::fTools::equalZero(getRadius()))
608ddde725dSArmin Le Grand                 {
609ddde725dSArmin Le Grand                     // fill with single color using last stop color
610ddde725dSArmin Le Grand                     setSingleEntry();
611ddde725dSArmin Le Grand                 }
612ddde725dSArmin Le Grand             }
613ddde725dSArmin Le Grand         }
614ddde725dSArmin Le Grand 
615ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::ensureGeometry(
616ddde725dSArmin Le Grand             basegfx::B2DPolyPolygon& rPolyPolygon,
617ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
618ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
619ddde725dSArmin Le Grand             sal_Int32 nOffset) const
620ddde725dSArmin Le Grand         {
621ddde725dSArmin Le Grand             if(!rPolyPolygon.count())
622ddde725dSArmin Le Grand             {
623ddde725dSArmin Le Grand                 basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle());
624ddde725dSArmin Le Grand                 basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle());
625ddde725dSArmin Le Grand                 double fScaleFrom(rFrom.getOffset() + nOffset);
626ddde725dSArmin Le Grand                 const double fScaleTo(rTo.getOffset() + nOffset);
627ddde725dSArmin Le Grand 
628ddde725dSArmin Le Grand                 if(fScaleFrom > getOverlapping())
629ddde725dSArmin Le Grand                 {
630ddde725dSArmin Le Grand                     fScaleFrom -= getOverlapping();
631ddde725dSArmin Le Grand                 }
632ddde725dSArmin Le Grand 
633ddde725dSArmin Le Grand                 if(isFocalSet())
634ddde725dSArmin Le Grand                 {
635ddde725dSArmin Le Grand                     const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
636ddde725dSArmin Le Grand                     const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
637ddde725dSArmin Le Grand 
638ddde725dSArmin Le Grand                     aPolygonA.transform(
639ddde725dSArmin Le Grand                         basegfx::tools::createScaleTranslateB2DHomMatrix(
640ddde725dSArmin Le Grand                             fScaleFrom,
641ddde725dSArmin Le Grand                             fScaleFrom,
642ddde725dSArmin Le Grand                             aTranslateFrom.getX(),
643ddde725dSArmin Le Grand                             aTranslateFrom.getY()));
644ddde725dSArmin Le Grand                     aPolygonB.transform(
645ddde725dSArmin Le Grand                         basegfx::tools::createScaleTranslateB2DHomMatrix(
646ddde725dSArmin Le Grand                             fScaleTo,
647ddde725dSArmin Le Grand                             fScaleTo,
648ddde725dSArmin Le Grand                             aTranslateTo.getX(),
649ddde725dSArmin Le Grand                             aTranslateTo.getY()));
650ddde725dSArmin Le Grand                 }
651ddde725dSArmin Le Grand                 else
652ddde725dSArmin Le Grand                 {
653ddde725dSArmin Le Grand                     aPolygonA.transform(
654ddde725dSArmin Le Grand                         basegfx::tools::createScaleB2DHomMatrix(
655ddde725dSArmin Le Grand                             fScaleFrom,
656ddde725dSArmin Le Grand                             fScaleFrom));
657ddde725dSArmin Le Grand                     aPolygonB.transform(
658ddde725dSArmin Le Grand                         basegfx::tools::createScaleB2DHomMatrix(
659ddde725dSArmin Le Grand                             fScaleTo,
660ddde725dSArmin Le Grand                             fScaleTo));
661ddde725dSArmin Le Grand                 }
662ddde725dSArmin Le Grand 
663ddde725dSArmin Le Grand                 // add the outer polygon first
664ddde725dSArmin Le Grand                 rPolyPolygon.append(aPolygonB);
665ddde725dSArmin Le Grand                 rPolyPolygon.append(aPolygonA);
666ddde725dSArmin Le Grand             }
667ddde725dSArmin Le Grand         }
668ddde725dSArmin Le Grand 
669ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::createAtom(
670ddde725dSArmin Le Grand             Primitive2DVector& rTargetColor,
671ddde725dSArmin Le Grand             Primitive2DVector& rTargetOpacity,
672ddde725dSArmin Le Grand             const SvgGradientEntry& rFrom,
673ddde725dSArmin Le Grand             const SvgGradientEntry& rTo,
674ddde725dSArmin Le Grand             sal_Int32 nOffset) const
675ddde725dSArmin Le Grand         {
676ddde725dSArmin Le Grand             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset())
677ddde725dSArmin Le Grand             if(rFrom.getOffset() == rTo.getOffset())
678ddde725dSArmin Le Grand             {
679ddde725dSArmin Le Grand                 OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)");
680ddde725dSArmin Le Grand             }
681ddde725dSArmin Le Grand             else
682ddde725dSArmin Le Grand             {
683ddde725dSArmin Le Grand                 const bool bColorChange(rFrom.getColor() != rTo.getColor());
684ddde725dSArmin Le Grand                 const bool bOpacityChange(rFrom.getOpacity() != rTo.getOpacity());
685ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aPolyPolygon;
686ddde725dSArmin Le Grand 
687ddde725dSArmin Le Grand                 if(bColorChange)
688ddde725dSArmin Le Grand                 {
689ddde725dSArmin Le Grand                     const double fScaleFrom(rFrom.getOffset() + nOffset);
690ddde725dSArmin Le Grand                     const double fScaleTo(rTo.getOffset() + nOffset);
691ddde725dSArmin Le Grand 
692ddde725dSArmin Le Grand                     if(isFocalSet())
693ddde725dSArmin Le Grand                     {
694ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
695ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
696ddde725dSArmin Le Grand 
697ddde725dSArmin Le Grand                         rTargetColor.push_back(
698ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
699ddde725dSArmin Le Grand                                 rFrom.getColor(), fScaleFrom, aTranslateFrom,
700ddde725dSArmin Le Grand                                 rTo.getColor(), fScaleTo, aTranslateTo,
701ddde725dSArmin Le Grand                                 getOverlapping()));
702ddde725dSArmin Le Grand                     }
703ddde725dSArmin Le Grand                     else
704ddde725dSArmin Le Grand                     {
705ddde725dSArmin Le Grand                         rTargetColor.push_back(
706ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
707ddde725dSArmin Le Grand                                 rFrom.getColor(), fScaleFrom,
708ddde725dSArmin Le Grand                                 rTo.getColor(), fScaleTo,
709ddde725dSArmin Le Grand                                 getOverlapping()));
710ddde725dSArmin Le Grand                     }
711ddde725dSArmin Le Grand                 }
712ddde725dSArmin Le Grand                 else
713ddde725dSArmin Le Grand                 {
714ddde725dSArmin Le Grand                     ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset);
715ddde725dSArmin Le Grand                     rTargetColor.push_back(
716ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
717ddde725dSArmin Le Grand                             aPolyPolygon,
718ddde725dSArmin Le Grand                             rFrom.getColor()));
719ddde725dSArmin Le Grand                 }
720ddde725dSArmin Le Grand 
721ddde725dSArmin Le Grand                 if(bOpacityChange)
722ddde725dSArmin Le Grand                 {
723ddde725dSArmin Le Grand                     const double fTransFrom(1.0 - rFrom.getOpacity());
724ddde725dSArmin Le Grand                     const double fTransTo(1.0 - rTo.getOpacity());
725ddde725dSArmin Le Grand                     const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom);
726ddde725dSArmin Le Grand                     const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo);
727ddde725dSArmin Le Grand                     const double fScaleFrom(rFrom.getOffset() + nOffset);
728ddde725dSArmin Le Grand                     const double fScaleTo(rTo.getOffset() + nOffset);
729ddde725dSArmin Le Grand 
730ddde725dSArmin Le Grand                     if(isFocalSet())
731ddde725dSArmin Le Grand                     {
732ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom));
733ddde725dSArmin Le Grand                         const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo));
734ddde725dSArmin Le Grand 
735ddde725dSArmin Le Grand                         rTargetOpacity.push_back(
736ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
737ddde725dSArmin Le Grand                                 aColorFrom, fScaleFrom, aTranslateFrom,
738ddde725dSArmin Le Grand                                 aColorTo, fScaleTo, aTranslateTo,
739ddde725dSArmin Le Grand                                 getOverlapping()));
740ddde725dSArmin Le Grand                     }
741ddde725dSArmin Le Grand                     else
742ddde725dSArmin Le Grand                     {
743ddde725dSArmin Le Grand                         rTargetOpacity.push_back(
744ddde725dSArmin Le Grand                             new SvgRadialAtomPrimitive2D(
745ddde725dSArmin Le Grand                                 aColorFrom, fScaleFrom,
746ddde725dSArmin Le Grand                                 aColorTo, fScaleTo,
747ddde725dSArmin Le Grand                                 getOverlapping()));
748ddde725dSArmin Le Grand                     }
749ddde725dSArmin Le Grand                 }
750ddde725dSArmin Le Grand                 else if(!getFullyOpaque())
751ddde725dSArmin Le Grand                 {
752ddde725dSArmin Le Grand                     const double fTransparence(1.0 - rFrom.getOpacity());
753ddde725dSArmin Le Grand 
754ddde725dSArmin Le Grand                     ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset);
755ddde725dSArmin Le Grand                     rTargetOpacity.push_back(
756ddde725dSArmin Le Grand                         new PolyPolygonColorPrimitive2D(
757ddde725dSArmin Le Grand                             aPolyPolygon,
758ddde725dSArmin Le Grand                             basegfx::BColor(fTransparence, fTransparence, fTransparence)));
759ddde725dSArmin Le Grand                 }
760ddde725dSArmin Le Grand             }
761ddde725dSArmin Le Grand         }
762ddde725dSArmin Le Grand 
763ddde725dSArmin Le Grand         const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const
764ddde725dSArmin Le Grand         {
765ddde725dSArmin Le Grand             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
766ddde725dSArmin Le Grand             {
767ddde725dSArmin Le Grand                 const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries();
768ddde725dSArmin Le Grand             }
769ddde725dSArmin Le Grand 
770ddde725dSArmin Le Grand             return maMirroredGradientEntries;
771ddde725dSArmin Le Grand         }
772ddde725dSArmin Le Grand 
773ddde725dSArmin Le Grand         void SvgRadialGradientPrimitive2D::createMirroredGradientEntries()
774ddde725dSArmin Le Grand         {
775ddde725dSArmin Le Grand             if(maMirroredGradientEntries.empty() && !getGradientEntries().empty())
776ddde725dSArmin Le Grand             {
777ddde725dSArmin Le Grand                 const sal_uInt32 nCount(getGradientEntries().size());
778ddde725dSArmin Le Grand                 maMirroredGradientEntries.clear();
779ddde725dSArmin Le Grand                 maMirroredGradientEntries.reserve(nCount);
780ddde725dSArmin Le Grand 
781ddde725dSArmin Le Grand                 for(sal_uInt32 a(0); a < nCount; a++)
782ddde725dSArmin Le Grand                 {
783ddde725dSArmin Le Grand                     const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a];
784ddde725dSArmin Le Grand 
785ddde725dSArmin Le Grand                     maMirroredGradientEntries.push_back(
786ddde725dSArmin Le Grand                         SvgGradientEntry(
787ddde725dSArmin Le Grand                             1.0 - rCandidate.getOffset(),
788ddde725dSArmin Le Grand                             rCandidate.getColor(),
789ddde725dSArmin Le Grand                             rCandidate.getOpacity()));
790ddde725dSArmin Le Grand                 }
791ddde725dSArmin Le Grand             }
792ddde725dSArmin Le Grand         }
793ddde725dSArmin Le Grand 
794ddde725dSArmin Le Grand         Primitive2DSequence SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
795ddde725dSArmin Le Grand         {
796ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
797ddde725dSArmin Le Grand 
798ddde725dSArmin Le Grand             if(!getPreconditionsChecked())
799ddde725dSArmin Le Grand             {
800ddde725dSArmin Le Grand                 const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions();
801ddde725dSArmin Le Grand             }
802ddde725dSArmin Le Grand 
803ddde725dSArmin Le Grand             if(getSingleEntry())
804ddde725dSArmin Le Grand             {
805ddde725dSArmin Le Grand                 // fill with last existing color
806ddde725dSArmin Le Grand                 xRetval = createSingleGradientEntryFill();
807ddde725dSArmin Le Grand             }
808ddde725dSArmin Le Grand             else if(getCreatesContent())
809ddde725dSArmin Le Grand             {
810ddde725dSArmin Le Grand                 // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely
811ddde725dSArmin Le Grand                 // invisible, width and height to fill are not empty
812ddde725dSArmin Le Grand                 const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
813ddde725dSArmin Le Grand                 const double fPolyWidth(aPolyRange.getWidth());
814ddde725dSArmin Le Grand                 const double fPolyHeight(aPolyRange.getHeight());
815ddde725dSArmin Le Grand 
816ddde725dSArmin Le Grand                 // create ObjectTransform based on polygon range
817ddde725dSArmin Le Grand                 const basegfx::B2DHomMatrix aObjectTransform(
818ddde725dSArmin Le Grand                     basegfx::tools::createScaleTranslateB2DHomMatrix(
819ddde725dSArmin Le Grand                         fPolyWidth, fPolyHeight,
820ddde725dSArmin Le Grand                         aPolyRange.getMinX(), aPolyRange.getMinY()));
821ddde725dSArmin Le Grand 
822ddde725dSArmin Le Grand                 // create unit transform from unit vector to given linear gradient vector
823ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToGradient;
824ddde725dSArmin Le Grand 
825ddde725dSArmin Le Grand                 aUnitGradientToGradient.scale(getRadius(), getRadius());
826ddde725dSArmin Le Grand                 aUnitGradientToGradient.translate(getStart().getX(), getStart().getY());
827ddde725dSArmin Le Grand 
828ddde725dSArmin Le Grand                 // create full transform from unit gradient coordinates to object coordinates
829ddde725dSArmin Le Grand                 // including the SvgGradient transformation
830ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aUnitGradientToObject(aObjectTransform * aUnitGradientToGradient);
831ddde725dSArmin Le Grand 
832ddde725dSArmin Le Grand                 // create inverse from it
833ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject);
834ddde725dSArmin Le Grand                 aObjectToUnitGradient.invert();
835ddde725dSArmin Le Grand 
836ddde725dSArmin Le Grand                 // back-transform polygon to unit gradient coordinates and get
837ddde725dSArmin Le Grand                 // UnitRage. This is the range the gradient has to cover
838ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon());
839ddde725dSArmin Le Grand                 aUnitPoly.transform(aObjectToUnitGradient);
840ddde725dSArmin Le Grand                 const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange());
841ddde725dSArmin Le Grand 
842ddde725dSArmin Le Grand                 // create range which the gradient has to cover to cover the whole given geometry.
843ddde725dSArmin Le Grand                 // For circle, go from 0.0 to max radius in all directions (the corners)
844ddde725dSArmin Le Grand                 double fMax(basegfx::B2DVector(aUnitRange.getMinimum()).getLength());
845ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaximum()).getLength());
846ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMinX(), aUnitRange.getMaxY()).getLength());
847ddde725dSArmin Le Grand                 fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaxX(), aUnitRange.getMinY()).getLength());
848ddde725dSArmin Le Grand 
849ddde725dSArmin Le Grand                 // prepare result vectors
850ddde725dSArmin Le Grand                 Primitive2DVector aTargetColor;
851ddde725dSArmin Le Grand                 Primitive2DVector aTargetOpacity;
852ddde725dSArmin Le Grand 
853ddde725dSArmin Le Grand                 if(0.0 < fMax)
854ddde725dSArmin Le Grand                 {
855ddde725dSArmin Le Grand                     // prepare maFocalVector
856ddde725dSArmin Le Grand                     if(isFocalSet())
857ddde725dSArmin Le Grand                     {
858ddde725dSArmin Le Grand                         const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax;
859ddde725dSArmin Le Grand                     }
860ddde725dSArmin Le Grand 
861ddde725dSArmin Le Grand                     // create central run, may also already do all necessary when
862ddde725dSArmin Le Grand                     // Spread_pad is set as SpreadMethod and/or the range is smaller
863ddde725dSArmin Le Grand                     double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0));
864ddde725dSArmin Le Grand 
865ddde725dSArmin Le Grand                     if(fPos < fMax)
866ddde725dSArmin Le Grand                     {
867ddde725dSArmin Le Grand                         // can only happen when SpreadMethod is Spread_reflect or Spread_repeat,
868ddde725dSArmin Le Grand                         // else the start and end pads are already created and fPos == fMax.
869ddde725dSArmin Le Grand                         // For radial there is no way to transform the already created
870ddde725dSArmin Le Grand                         // central run, it needs to be created from 1.0 to fMax
871ddde725dSArmin Le Grand                         sal_Int32 nOffset(1);
872ddde725dSArmin Le Grand 
873ddde725dSArmin Le Grand                         while(fPos < fMax)
874ddde725dSArmin Le Grand                         {
875ddde725dSArmin Le Grand                             const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2));
876ddde725dSArmin Le Grand 
877ddde725dSArmin Le Grand                             if(bMirror)
878ddde725dSArmin Le Grand                             {
879ddde725dSArmin Le Grand                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset);
880ddde725dSArmin Le Grand                             }
881ddde725dSArmin Le Grand                             else
882ddde725dSArmin Le Grand                             {
883ddde725dSArmin Le Grand                                 createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset);
884ddde725dSArmin Le Grand                             }
885ddde725dSArmin Le Grand 
886ddde725dSArmin Le Grand                             nOffset++;
887ddde725dSArmin Le Grand                             fPos += 1.0;
888ddde725dSArmin Le Grand                         }
889ddde725dSArmin Le Grand                     }
890ddde725dSArmin Le Grand                 }
891ddde725dSArmin Le Grand 
892ddde725dSArmin Le Grand                 xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject, true);
893ddde725dSArmin Le Grand             }
894ddde725dSArmin Le Grand 
895ddde725dSArmin Le Grand             return xRetval;
896ddde725dSArmin Le Grand         }
897ddde725dSArmin Le Grand 
898ddde725dSArmin Le Grand         SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D(
899ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPolyPolygon,
900ddde725dSArmin Le Grand             const SvgGradientEntryVector& rGradientEntries,
901ddde725dSArmin Le Grand             const basegfx::B2DPoint& rStart,
902ddde725dSArmin Le Grand             double fRadius,
903ddde725dSArmin Le Grand             SpreadMethod aSpreadMethod,
904ddde725dSArmin Le Grand             const basegfx::B2DPoint* pFocal,
905ddde725dSArmin Le Grand             double fOverlapping)
906ddde725dSArmin Le Grand         :   BufferedDecompositionPrimitive2D(),
907ddde725dSArmin Le Grand             SvgGradientHelper(rPolyPolygon, rGradientEntries, rStart, aSpreadMethod, fOverlapping),
908ddde725dSArmin Le Grand             mfRadius(fRadius),
909ddde725dSArmin Le Grand             maFocal(rStart),
910ddde725dSArmin Le Grand             maFocalVector(0.0, 0.0),
911ddde725dSArmin Le Grand             maFocalLength(0.0),
912ddde725dSArmin Le Grand             maMirroredGradientEntries(),
913ddde725dSArmin Le Grand             mbFocalSet(false)
914ddde725dSArmin Le Grand         {
915ddde725dSArmin Le Grand             if(pFocal)
916ddde725dSArmin Le Grand             {
917ddde725dSArmin Le Grand                 maFocal = *pFocal;
918ddde725dSArmin Le Grand                 maFocalVector = maFocal - getStart();
919ddde725dSArmin Le Grand                 mbFocalSet = true;
920ddde725dSArmin Le Grand             }
921ddde725dSArmin Le Grand         }
922ddde725dSArmin Le Grand 
923ddde725dSArmin Le Grand         bool SvgRadialGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
924ddde725dSArmin Le Grand         {
925ddde725dSArmin Le Grand             const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive);
926ddde725dSArmin Le Grand 
927ddde725dSArmin Le Grand             if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper))
928ddde725dSArmin Le Grand             {
929ddde725dSArmin Le Grand                 const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive);
930ddde725dSArmin Le Grand 
931ddde725dSArmin Le Grand                 if(getRadius() == rCompare.getRadius())
932ddde725dSArmin Le Grand                 {
933ddde725dSArmin Le Grand                     if(isFocalSet() == rCompare.isFocalSet())
934ddde725dSArmin Le Grand                     {
935ddde725dSArmin Le Grand                         if(isFocalSet())
936ddde725dSArmin Le Grand                         {
937ddde725dSArmin Le Grand                             return getFocal() == rCompare.getFocal();
938ddde725dSArmin Le Grand                         }
939ddde725dSArmin Le Grand                         else
940ddde725dSArmin Le Grand                         {
941ddde725dSArmin Le Grand                             return true;
942ddde725dSArmin Le Grand                         }
943ddde725dSArmin Le Grand                     }
944ddde725dSArmin Le Grand                 }
945ddde725dSArmin Le Grand             }
946ddde725dSArmin Le Grand 
947ddde725dSArmin Le Grand             return false;
948ddde725dSArmin Le Grand         }
949ddde725dSArmin Le Grand 
950ddde725dSArmin Le Grand         basegfx::B2DRange SvgRadialGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
951ddde725dSArmin Le Grand         {
952ddde725dSArmin Le Grand             // return ObjectRange
953ddde725dSArmin Le Grand             return getPolyPolygon().getB2DRange();
954ddde725dSArmin Le Grand         }
955ddde725dSArmin Le Grand 
956ddde725dSArmin Le Grand         // provide unique ID
957ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D)
958ddde725dSArmin Le Grand 
959ddde725dSArmin Le Grand     } // end of namespace primitive2d
960ddde725dSArmin Le Grand } // end of namespace drawinglayer
961ddde725dSArmin Le Grand 
962ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
963ddde725dSArmin Le Grand // SvgLinearAtomPrimitive2D class
964ddde725dSArmin Le Grand 
965ddde725dSArmin Le Grand namespace drawinglayer
966ddde725dSArmin Le Grand {
967ddde725dSArmin Le Grand     namespace primitive2d
968ddde725dSArmin Le Grand     {
969*e2bf1e9dSArmin Le Grand         Primitive2DSequence SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
970ddde725dSArmin Le Grand         {
971ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
972ddde725dSArmin Le Grand             const double fDelta(getOffsetB() - getOffsetA());
973ddde725dSArmin Le Grand 
974ddde725dSArmin Le Grand             if(!basegfx::fTools::equalZero(fDelta))
975ddde725dSArmin Le Grand             {
976ddde725dSArmin Le Grand                 if(getColorA() == getColorB())
977ddde725dSArmin Le Grand                 {
978ddde725dSArmin Le Grand                     const basegfx::B2DPolygon aPolygon(
979ddde725dSArmin Le Grand                         basegfx::tools::createPolygonFromRect(
980ddde725dSArmin Le Grand                             basegfx::B2DRange(
981ddde725dSArmin Le Grand                                 getOffsetA() - getOverlapping(),
982ddde725dSArmin Le Grand                                 0.0,
983ddde725dSArmin Le Grand                                 getOffsetB() + getOverlapping(),
984ddde725dSArmin Le Grand                                 1.0)));
985ddde725dSArmin Le Grand 
986ddde725dSArmin Le Grand                     xRetval.realloc(1);
987ddde725dSArmin Le Grand                     xRetval[0] = new PolyPolygonColorPrimitive2D(
988ddde725dSArmin Le Grand                         basegfx::B2DPolyPolygon(aPolygon),
989ddde725dSArmin Le Grand                         getColorA());
990ddde725dSArmin Le Grand                 }
991ddde725dSArmin Le Grand                 else
992ddde725dSArmin Le Grand                 {
993ddde725dSArmin Le Grand                     // calc discrete length to change color all 2.5 pixels
994ddde725dSArmin Le Grand                     sal_uInt32 nSteps(basegfx::fround(fDelta / (getDiscreteUnit() * 2.5)));
995ddde725dSArmin Le Grand 
996ddde725dSArmin Le Grand                     // use color distance, assume to do every 3rd
997ddde725dSArmin Le Grand                     const double fColorDistance(getColorA().getDistance(getColorB()));
998ddde725dSArmin Le Grand                     const sal_uInt32 nColorSteps(basegfx::fround(fColorDistance * (255.0 * 0.3)));
999ddde725dSArmin Le Grand                     nSteps = std::min(nSteps, nColorSteps);
1000ddde725dSArmin Le Grand 
1001ddde725dSArmin Le Grand                     // roughly cut when too big
1002ddde725dSArmin Le Grand                     nSteps = std::min(nSteps, sal_uInt32(100));
1003ddde725dSArmin Le Grand                     nSteps = std::max(nSteps, sal_uInt32(1));
1004ddde725dSArmin Le Grand 
1005ddde725dSArmin Le Grand                     // preapare iteration
1006ddde725dSArmin Le Grand                     double fStart(0.0);
1007ddde725dSArmin Le Grand                     double fStep(fDelta / nSteps);
1008ddde725dSArmin Le Grand 
1009ddde725dSArmin Le Grand                     xRetval.realloc(nSteps);
1010ddde725dSArmin Le Grand 
1011ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nSteps; a++, fStart += fStep)
1012ddde725dSArmin Le Grand                     {
1013ddde725dSArmin Le Grand                         const double fLeft(getOffsetA() + fStart);
1014ddde725dSArmin Le Grand                         const double fRight(fLeft + fStep);
1015ddde725dSArmin Le Grand                         const basegfx::B2DPolygon aPolygon(
1016ddde725dSArmin Le Grand                             basegfx::tools::createPolygonFromRect(
1017ddde725dSArmin Le Grand                                 basegfx::B2DRange(
1018ddde725dSArmin Le Grand                                     fLeft - getOverlapping(),
1019ddde725dSArmin Le Grand                                     0.0,
1020ddde725dSArmin Le Grand                                     fRight + getOverlapping(),
1021ddde725dSArmin Le Grand                                     1.0)));
1022ddde725dSArmin Le Grand 
1023ddde725dSArmin Le Grand                         xRetval[a] = new PolyPolygonColorPrimitive2D(
1024ddde725dSArmin Le Grand                             basegfx::B2DPolyPolygon(aPolygon),
1025ddde725dSArmin Le Grand                             basegfx::interpolate(getColorA(), getColorB(), fStart/fDelta));
1026ddde725dSArmin Le Grand                     }
1027ddde725dSArmin Le Grand                 }
1028ddde725dSArmin Le Grand             }
1029ddde725dSArmin Le Grand 
1030ddde725dSArmin Le Grand             return xRetval;
1031ddde725dSArmin Le Grand         }
1032ddde725dSArmin Le Grand 
1033ddde725dSArmin Le Grand         bool SvgLinearAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1034ddde725dSArmin Le Grand         {
1035ddde725dSArmin Le Grand             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
1036ddde725dSArmin Le Grand             {
1037ddde725dSArmin Le Grand                 const SvgLinearAtomPrimitive2D& rCompare = static_cast< const SvgLinearAtomPrimitive2D& >(rPrimitive);
1038ddde725dSArmin Le Grand 
1039ddde725dSArmin Le Grand                 return (getColorA() == rCompare.getColorA()
1040ddde725dSArmin Le Grand                     && getColorB() == rCompare.getColorB()
1041ddde725dSArmin Le Grand                     && getOffsetA() == rCompare.getOffsetA()
1042ddde725dSArmin Le Grand                     && getOffsetB() == rCompare.getOffsetB()
1043ddde725dSArmin Le Grand                     && getOverlapping() == rCompare.getOverlapping());
1044ddde725dSArmin Le Grand             }
1045ddde725dSArmin Le Grand 
1046ddde725dSArmin Le Grand             return false;
1047ddde725dSArmin Le Grand         }
1048ddde725dSArmin Le Grand 
1049ddde725dSArmin Le Grand         // provide unique ID
1050ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D)
1051ddde725dSArmin Le Grand 
1052ddde725dSArmin Le Grand     } // end of namespace primitive2d
1053ddde725dSArmin Le Grand } // end of namespace drawinglayer
1054ddde725dSArmin Le Grand 
1055ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1056ddde725dSArmin Le Grand // SvgRadialAtomPrimitive2D class
1057ddde725dSArmin Le Grand 
1058ddde725dSArmin Le Grand namespace drawinglayer
1059ddde725dSArmin Le Grand {
1060ddde725dSArmin Le Grand     namespace primitive2d
1061ddde725dSArmin Le Grand     {
1062ddde725dSArmin Le Grand         Primitive2DSequence SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
1063ddde725dSArmin Le Grand         {
1064ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
1065ddde725dSArmin Le Grand             const double fDeltaScale(getScaleB() - getScaleA());
1066ddde725dSArmin Le Grand 
1067ddde725dSArmin Le Grand             if(!basegfx::fTools::equalZero(fDeltaScale))
1068ddde725dSArmin Le Grand             {
1069ddde725dSArmin Le Grand                 if(getColorA() == getColorB())
1070ddde725dSArmin Le Grand                 {
1071ddde725dSArmin Le Grand                     basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle());
1072ddde725dSArmin Le Grand                     basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle());
1073ddde725dSArmin Le Grand                     double fScaleA(getScaleA());
1074ddde725dSArmin Le Grand                     const double fScaleB(getScaleB());
1075ddde725dSArmin Le Grand 
1076ddde725dSArmin Le Grand                     if(fScaleA > getOverlapping())
1077ddde725dSArmin Le Grand                     {
1078ddde725dSArmin Le Grand                         fScaleA -= getOverlapping();
1079ddde725dSArmin Le Grand                     }
1080ddde725dSArmin Le Grand 
1081ddde725dSArmin Le Grand                     const bool bUseA(basegfx::fTools::equalZero(fScaleA));
1082ddde725dSArmin Le Grand 
1083ddde725dSArmin Le Grand                     if(getTranslateSet())
1084ddde725dSArmin Le Grand                     {
1085ddde725dSArmin Le Grand                         if(bUseA)
1086ddde725dSArmin Le Grand                         {
1087ddde725dSArmin Le Grand                             aPolygonA.transform(
1088ddde725dSArmin Le Grand                                 basegfx::tools::createScaleTranslateB2DHomMatrix(
1089ddde725dSArmin Le Grand                                     fScaleA,
1090ddde725dSArmin Le Grand                                     fScaleA,
1091ddde725dSArmin Le Grand                                     getTranslateA().getX(),
1092ddde725dSArmin Le Grand                                     getTranslateA().getY()));
1093ddde725dSArmin Le Grand                         }
1094ddde725dSArmin Le Grand 
1095ddde725dSArmin Le Grand                         aPolygonB.transform(
1096ddde725dSArmin Le Grand                             basegfx::tools::createScaleTranslateB2DHomMatrix(
1097ddde725dSArmin Le Grand                                 fScaleB,
1098ddde725dSArmin Le Grand                                 fScaleB,
1099ddde725dSArmin Le Grand                                 getTranslateB().getX(),
1100ddde725dSArmin Le Grand                                 getTranslateB().getY()));
1101ddde725dSArmin Le Grand                     }
1102ddde725dSArmin Le Grand                     else
1103ddde725dSArmin Le Grand                     {
1104ddde725dSArmin Le Grand                         if(bUseA)
1105ddde725dSArmin Le Grand                         {
1106ddde725dSArmin Le Grand                             aPolygonA.transform(
1107ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
1108ddde725dSArmin Le Grand                                     fScaleA,
1109ddde725dSArmin Le Grand                                     fScaleA));
1110ddde725dSArmin Le Grand                         }
1111ddde725dSArmin Le Grand 
1112ddde725dSArmin Le Grand                         aPolygonB.transform(
1113ddde725dSArmin Le Grand                             basegfx::tools::createScaleB2DHomMatrix(
1114ddde725dSArmin Le Grand                                 fScaleB,
1115ddde725dSArmin Le Grand                                 fScaleB));
1116ddde725dSArmin Le Grand                     }
1117ddde725dSArmin Le Grand 
1118ddde725dSArmin Le Grand                     basegfx::B2DPolyPolygon aPolyPolygon(aPolygonB);
1119ddde725dSArmin Le Grand 
1120ddde725dSArmin Le Grand                     if(bUseA)
1121ddde725dSArmin Le Grand                     {
1122ddde725dSArmin Le Grand                         aPolyPolygon.append(aPolygonA);
1123ddde725dSArmin Le Grand                     }
1124ddde725dSArmin Le Grand 
1125ddde725dSArmin Le Grand                     xRetval.realloc(1);
1126ddde725dSArmin Le Grand 
1127ddde725dSArmin Le Grand                     xRetval[0] = new PolyPolygonColorPrimitive2D(
1128ddde725dSArmin Le Grand                         aPolyPolygon,
1129ddde725dSArmin Le Grand                         getColorA());
1130ddde725dSArmin Le Grand                 }
1131ddde725dSArmin Le Grand                 else
1132ddde725dSArmin Le Grand                 {
1133ddde725dSArmin Le Grand                     // calc discrete length to change color all 2.5 pixels
1134ddde725dSArmin Le Grand                     sal_uInt32 nSteps(basegfx::fround(fDeltaScale / (getDiscreteUnit() * 2.5)));
1135ddde725dSArmin Le Grand 
1136ddde725dSArmin Le Grand                     // use color distance, assume to do every 3rd
1137ddde725dSArmin Le Grand                     const double fColorDistance(getColorA().getDistance(getColorB()));
1138ddde725dSArmin Le Grand                     const sal_uInt32 nColorSteps(basegfx::fround(fColorDistance * (255.0 * 0.3)));
1139ddde725dSArmin Le Grand                     nSteps = std::min(nSteps, nColorSteps);
1140ddde725dSArmin Le Grand 
1141ddde725dSArmin Le Grand                     // roughly cut when too big
1142ddde725dSArmin Le Grand                     nSteps = std::min(nSteps, sal_uInt32(100));
1143ddde725dSArmin Le Grand                     nSteps = std::max(nSteps, sal_uInt32(1));
1144ddde725dSArmin Le Grand 
1145ddde725dSArmin Le Grand                     // preapare iteration
1146ddde725dSArmin Le Grand                     double fStartScale(0.0);
1147ddde725dSArmin Le Grand                     double fStepScale(fDeltaScale / nSteps);
1148ddde725dSArmin Le Grand 
1149ddde725dSArmin Le Grand                     xRetval.realloc(nSteps);
1150ddde725dSArmin Le Grand 
1151ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nSteps; a++, fStartScale += fStepScale)
1152ddde725dSArmin Le Grand                     {
1153ddde725dSArmin Le Grand                         double fScaleA(getScaleA() + fStartScale);
1154ddde725dSArmin Le Grand                         const double fScaleB(fScaleA + fStepScale);
1155ddde725dSArmin Le Grand                         const double fUnitScale(fStartScale/fDeltaScale);
1156ddde725dSArmin Le Grand                         basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle());
1157ddde725dSArmin Le Grand                         basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle());
1158ddde725dSArmin Le Grand 
1159ddde725dSArmin Le Grand                         if(fScaleA > getOverlapping())
1160ddde725dSArmin Le Grand                         {
1161ddde725dSArmin Le Grand                             fScaleA -= getOverlapping();
1162ddde725dSArmin Le Grand                         }
1163ddde725dSArmin Le Grand 
1164ddde725dSArmin Le Grand                         const bool bUseA(basegfx::fTools::equalZero(fScaleA));
1165ddde725dSArmin Le Grand 
1166ddde725dSArmin Le Grand                         if(getTranslateSet())
1167ddde725dSArmin Le Grand                         {
1168ddde725dSArmin Le Grand                             const double fUnitScaleEnd((fStartScale + fStepScale)/fDeltaScale);
1169ddde725dSArmin Le Grand                             const basegfx::B2DVector aTranslateB(basegfx::interpolate(getTranslateA(), getTranslateB(), fUnitScaleEnd));
1170ddde725dSArmin Le Grand 
1171ddde725dSArmin Le Grand                             if(bUseA)
1172ddde725dSArmin Le Grand                             {
1173ddde725dSArmin Le Grand                                 const basegfx::B2DVector aTranslateA(basegfx::interpolate(getTranslateA(), getTranslateB(), fUnitScale));
1174ddde725dSArmin Le Grand 
1175ddde725dSArmin Le Grand                                 aPolygonA.transform(
1176ddde725dSArmin Le Grand                                     basegfx::tools::createScaleTranslateB2DHomMatrix(
1177ddde725dSArmin Le Grand                                         fScaleA,
1178ddde725dSArmin Le Grand                                         fScaleA,
1179ddde725dSArmin Le Grand                                         aTranslateA.getX(),
1180ddde725dSArmin Le Grand                                         aTranslateA.getY()));
1181ddde725dSArmin Le Grand                             }
1182ddde725dSArmin Le Grand 
1183ddde725dSArmin Le Grand                             aPolygonB.transform(
1184ddde725dSArmin Le Grand                                 basegfx::tools::createScaleTranslateB2DHomMatrix(
1185ddde725dSArmin Le Grand                                     fScaleB,
1186ddde725dSArmin Le Grand                                     fScaleB,
1187ddde725dSArmin Le Grand                                     aTranslateB.getX(),
1188ddde725dSArmin Le Grand                                     aTranslateB.getY()));
1189ddde725dSArmin Le Grand                         }
1190ddde725dSArmin Le Grand                         else
1191ddde725dSArmin Le Grand                         {
1192ddde725dSArmin Le Grand                             if(bUseA)
1193ddde725dSArmin Le Grand                             {
1194ddde725dSArmin Le Grand                                 aPolygonA.transform(
1195ddde725dSArmin Le Grand                                     basegfx::tools::createScaleB2DHomMatrix(
1196ddde725dSArmin Le Grand                                         fScaleA,
1197ddde725dSArmin Le Grand                                         fScaleA));
1198ddde725dSArmin Le Grand                             }
1199ddde725dSArmin Le Grand 
1200ddde725dSArmin Le Grand                             aPolygonB.transform(
1201ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
1202ddde725dSArmin Le Grand                                     fScaleB,
1203ddde725dSArmin Le Grand                                     fScaleB));
1204ddde725dSArmin Le Grand                         }
1205ddde725dSArmin Le Grand 
1206ddde725dSArmin Le Grand                         basegfx::B2DPolyPolygon aPolyPolygon(aPolygonB);
1207ddde725dSArmin Le Grand 
1208ddde725dSArmin Le Grand                         if(bUseA)
1209ddde725dSArmin Le Grand                         {
1210ddde725dSArmin Le Grand                             aPolyPolygon.append(aPolygonA);
1211ddde725dSArmin Le Grand                         }
1212ddde725dSArmin Le Grand 
1213ddde725dSArmin Le Grand                         xRetval[nSteps - 1 - a] = new PolyPolygonColorPrimitive2D(
1214ddde725dSArmin Le Grand                             aPolyPolygon,
1215ddde725dSArmin Le Grand                             basegfx::interpolate(getColorA(), getColorB(), fUnitScale));
1216ddde725dSArmin Le Grand                     }
1217ddde725dSArmin Le Grand                 }
1218ddde725dSArmin Le Grand             }
1219ddde725dSArmin Le Grand 
1220ddde725dSArmin Le Grand             return xRetval;
1221ddde725dSArmin Le Grand         }
1222ddde725dSArmin Le Grand 
1223ddde725dSArmin Le Grand         bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
1224ddde725dSArmin Le Grand         {
1225ddde725dSArmin Le Grand             if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
1226ddde725dSArmin Le Grand             {
1227ddde725dSArmin Le Grand                 const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive);
1228ddde725dSArmin Le Grand 
1229ddde725dSArmin Le Grand                 return (getColorA() == rCompare.getColorA()
1230ddde725dSArmin Le Grand                     && getColorB() == rCompare.getColorB()
1231ddde725dSArmin Le Grand                     && getScaleA() == rCompare.getScaleA()
1232ddde725dSArmin Le Grand                     && getScaleB() == rCompare.getScaleB()
1233ddde725dSArmin Le Grand                     && getTranslateA() == rCompare.getTranslateA()
1234ddde725dSArmin Le Grand                     && getTranslateB() == rCompare.getTranslateB()
1235ddde725dSArmin Le Grand                     && getOverlapping() == rCompare.getOverlapping());
1236ddde725dSArmin Le Grand             }
1237ddde725dSArmin Le Grand 
1238ddde725dSArmin Le Grand             return false;
1239ddde725dSArmin Le Grand         }
1240ddde725dSArmin Le Grand 
1241ddde725dSArmin Le Grand         // provide unique ID
1242ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D)
1243ddde725dSArmin Le Grand 
1244ddde725dSArmin Le Grand     } // end of namespace primitive2d
1245ddde725dSArmin Le Grand } // end of namespace drawinglayer
1246ddde725dSArmin Le Grand 
1247ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1248ddde725dSArmin Le Grand // eof
1249