xref: /AOO41X/main/svgio/source/svgreader/svgstyleattributes.cxx (revision 2600a567d4487837fa24bc1fcc659baa34fd3380)
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_svgio.hxx"
24ddde725dSArmin Le Grand 
25ddde725dSArmin Le Grand #include <svgio/svgreader/svgstyleattributes.hxx>
26ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
28ddde725dSArmin Le Grand #include <svgio/svgreader/svgnode.hxx>
29ddde725dSArmin Le Grand #include <svgio/svgreader/svgdocument.hxx>
30ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
31ddde725dSArmin Le Grand #include <svgio/svgreader/svggradientnode.hxx>
32ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
33ddde725dSArmin Le Grand #include <basegfx/vector/b2enums.hxx>
34ddde725dSArmin Le Grand #include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
35ddde725dSArmin Le Grand #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
36ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
37ddde725dSArmin Le Grand #include <svgio/svgreader/svgclippathnode.hxx>
38ddde725dSArmin Le Grand #include <svgio/svgreader/svgmasknode.hxx>
39ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
40ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolypolygontools.hxx>
41ddde725dSArmin Le Grand #include <svgio/svgreader/svgmarkernode.hxx>
42ddde725dSArmin Le Grand #include <basegfx/curve/b2dcubicbezier.hxx>
43ddde725dSArmin Le Grand #include <svgio/svgreader/svgpatternnode.hxx>
44ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
45ddde725dSArmin Le Grand 
46ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
47ddde725dSArmin Le Grand 
48ddde725dSArmin Le Grand namespace svgio
49ddde725dSArmin Le Grand {
50ddde725dSArmin Le Grand     namespace svgreader
51ddde725dSArmin Le Grand     {
52ddde725dSArmin Le Grand         basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin)
53ddde725dSArmin Le Grand         {
54ddde725dSArmin Le Grand             if(StrokeLinejoin_round == aStrokeLinejoin)
55ddde725dSArmin Le Grand             {
56ddde725dSArmin Le Grand                 return basegfx::B2DLINEJOIN_ROUND;
57ddde725dSArmin Le Grand             }
58ddde725dSArmin Le Grand             else if(StrokeLinejoin_bevel == aStrokeLinejoin)
59ddde725dSArmin Le Grand             {
60ddde725dSArmin Le Grand                 return basegfx::B2DLINEJOIN_BEVEL;
61ddde725dSArmin Le Grand             }
62ddde725dSArmin Le Grand 
63ddde725dSArmin Le Grand             return basegfx::B2DLINEJOIN_MITER;
64ddde725dSArmin Le Grand         }
65ddde725dSArmin Le Grand 
66ddde725dSArmin Le Grand         FontStretch getWider(FontStretch aSource)
67ddde725dSArmin Le Grand         {
68ddde725dSArmin Le Grand             switch(aSource)
69ddde725dSArmin Le Grand             {
70ddde725dSArmin Le Grand                 case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break;
71ddde725dSArmin Le Grand                 case FontStretch_extra_condensed: aSource = FontStretch_condensed; break;
72ddde725dSArmin Le Grand                 case FontStretch_condensed: aSource = FontStretch_semi_condensed; break;
73ddde725dSArmin Le Grand                 case FontStretch_semi_condensed: aSource = FontStretch_normal; break;
74ddde725dSArmin Le Grand                 case FontStretch_normal: aSource = FontStretch_semi_expanded; break;
75ddde725dSArmin Le Grand                 case FontStretch_semi_expanded: aSource = FontStretch_expanded; break;
76ddde725dSArmin Le Grand                 case FontStretch_expanded: aSource = FontStretch_extra_expanded; break;
77ddde725dSArmin Le Grand                 case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break;
78e2bf1e9dSArmin Le Grand                 default: break;
79ddde725dSArmin Le Grand             }
80ddde725dSArmin Le Grand 
81ddde725dSArmin Le Grand             return aSource;
82ddde725dSArmin Le Grand         }
83ddde725dSArmin Le Grand 
84ddde725dSArmin Le Grand         FontStretch getNarrower(FontStretch aSource)
85ddde725dSArmin Le Grand         {
86ddde725dSArmin Le Grand             switch(aSource)
87ddde725dSArmin Le Grand             {
88ddde725dSArmin Le Grand                 case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break;
89ddde725dSArmin Le Grand                 case FontStretch_condensed: aSource = FontStretch_extra_condensed; break;
90ddde725dSArmin Le Grand                 case FontStretch_semi_condensed: aSource = FontStretch_condensed; break;
91ddde725dSArmin Le Grand                 case FontStretch_normal: aSource = FontStretch_semi_condensed; break;
92ddde725dSArmin Le Grand                 case FontStretch_semi_expanded: aSource = FontStretch_normal; break;
93ddde725dSArmin Le Grand                 case FontStretch_expanded: aSource = FontStretch_semi_expanded; break;
94ddde725dSArmin Le Grand                 case FontStretch_extra_expanded: aSource = FontStretch_expanded; break;
95ddde725dSArmin Le Grand                 case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break;
96e2bf1e9dSArmin Le Grand                 default: break;
97ddde725dSArmin Le Grand             }
98ddde725dSArmin Le Grand 
99ddde725dSArmin Le Grand             return aSource;
100ddde725dSArmin Le Grand         }
101ddde725dSArmin Le Grand 
102ddde725dSArmin Le Grand         FontWeight getBolder(FontWeight aSource)
103ddde725dSArmin Le Grand         {
104ddde725dSArmin Le Grand             switch(aSource)
105ddde725dSArmin Le Grand             {
106ddde725dSArmin Le Grand                 case FontWeight_100: aSource = FontWeight_200; break;
107ddde725dSArmin Le Grand                 case FontWeight_200: aSource = FontWeight_300; break;
108ddde725dSArmin Le Grand                 case FontWeight_300: aSource = FontWeight_400; break;
109ddde725dSArmin Le Grand                 case FontWeight_400: aSource = FontWeight_500; break;
110ddde725dSArmin Le Grand                 case FontWeight_500: aSource = FontWeight_600; break;
111ddde725dSArmin Le Grand                 case FontWeight_600: aSource = FontWeight_700; break;
112ddde725dSArmin Le Grand                 case FontWeight_700: aSource = FontWeight_800; break;
113ddde725dSArmin Le Grand                 case FontWeight_800: aSource = FontWeight_900; break;
114e2bf1e9dSArmin Le Grand                 default: break;
115ddde725dSArmin Le Grand             }
116ddde725dSArmin Le Grand 
117ddde725dSArmin Le Grand             return aSource;
118ddde725dSArmin Le Grand         }
119ddde725dSArmin Le Grand 
120ddde725dSArmin Le Grand         FontWeight getLighter(FontWeight aSource)
121ddde725dSArmin Le Grand         {
122ddde725dSArmin Le Grand             switch(aSource)
123ddde725dSArmin Le Grand             {
124ddde725dSArmin Le Grand                 case FontWeight_200: aSource = FontWeight_100; break;
125ddde725dSArmin Le Grand                 case FontWeight_300: aSource = FontWeight_200; break;
126ddde725dSArmin Le Grand                 case FontWeight_400: aSource = FontWeight_300; break;
127ddde725dSArmin Le Grand                 case FontWeight_500: aSource = FontWeight_400; break;
128ddde725dSArmin Le Grand                 case FontWeight_600: aSource = FontWeight_500; break;
129ddde725dSArmin Le Grand                 case FontWeight_700: aSource = FontWeight_600; break;
130ddde725dSArmin Le Grand                 case FontWeight_800: aSource = FontWeight_700; break;
131ddde725dSArmin Le Grand                 case FontWeight_900: aSource = FontWeight_800; break;
132e2bf1e9dSArmin Le Grand                 default: break;
133ddde725dSArmin Le Grand             }
134ddde725dSArmin Le Grand 
135ddde725dSArmin Le Grand             return aSource;
136ddde725dSArmin Le Grand         }
137ddde725dSArmin Le Grand 
138ddde725dSArmin Le Grand         ::FontWeight getVclFontWeight(FontWeight aSource)
139ddde725dSArmin Le Grand         {
140ddde725dSArmin Le Grand             ::FontWeight nRetval(WEIGHT_NORMAL);
141ddde725dSArmin Le Grand 
142ddde725dSArmin Le Grand             switch(aSource)
143ddde725dSArmin Le Grand             {
144ddde725dSArmin Le Grand                 case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break;
145ddde725dSArmin Le Grand                 case FontWeight_200: nRetval = WEIGHT_LIGHT; break;
146ddde725dSArmin Le Grand                 case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break;
147ddde725dSArmin Le Grand                 case FontWeight_400: nRetval = WEIGHT_NORMAL; break;
148ddde725dSArmin Le Grand                 case FontWeight_500: nRetval = WEIGHT_MEDIUM; break;
149ddde725dSArmin Le Grand                 case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break;
150ddde725dSArmin Le Grand                 case FontWeight_700: nRetval = WEIGHT_BOLD; break;
151ddde725dSArmin Le Grand                 case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break;
152ddde725dSArmin Le Grand                 case FontWeight_900: nRetval = WEIGHT_BLACK; break;
153e2bf1e9dSArmin Le Grand                 default: break;
154ddde725dSArmin Le Grand             }
155ddde725dSArmin Le Grand 
156ddde725dSArmin Le Grand             return nRetval;
157ddde725dSArmin Le Grand         }
158ddde725dSArmin Le Grand 
159ddde725dSArmin Le Grand         void SvgStyleAttributes::readStyle(const rtl::OUString& rCandidate)
160ddde725dSArmin Le Grand         {
161ddde725dSArmin Le Grand             const sal_Int32 nLen(rCandidate.getLength());
162ddde725dSArmin Le Grand             sal_Int32 nPos(0);
163ddde725dSArmin Le Grand 
164ddde725dSArmin Le Grand             while(nPos < nLen)
165ddde725dSArmin Le Grand             {
166ddde725dSArmin Le Grand                 const sal_Int32 nInitPos(nPos);
167ddde725dSArmin Le Grand                 skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
168ddde725dSArmin Le Grand                 rtl::OUStringBuffer aTokenName;
169ddde725dSArmin Le Grand                 copyString(rCandidate, nPos, aTokenName, nLen);
170ddde725dSArmin Le Grand 
171ddde725dSArmin Le Grand                 if(aTokenName.getLength())
172ddde725dSArmin Le Grand                 {
173ddde725dSArmin Le Grand                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(':'), nPos, nLen);
174ddde725dSArmin Le Grand                     rtl::OUStringBuffer aTokenValue;
175ddde725dSArmin Le Grand                     copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aTokenValue, nLen);
176ddde725dSArmin Le Grand                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
177ddde725dSArmin Le Grand                     const rtl::OUString aOUTokenName(aTokenName.makeStringAndClear());
178ddde725dSArmin Le Grand                     const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
179ddde725dSArmin Le Grand 
180ddde725dSArmin Le Grand                     parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue);
181ddde725dSArmin Le Grand                 }
182ddde725dSArmin Le Grand 
183ddde725dSArmin Le Grand                 if(nInitPos == nPos)
184ddde725dSArmin Le Grand                 {
185ddde725dSArmin Le Grand                     OSL_ENSURE(false, "Could not interpret on current position (!)");
186ddde725dSArmin Le Grand                     nPos++;
187ddde725dSArmin Le Grand                 }
188ddde725dSArmin Le Grand             }
189ddde725dSArmin Le Grand         }
190ddde725dSArmin Le Grand 
191ddde725dSArmin Le Grand         void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const
192ddde725dSArmin Le Grand         {
193ddde725dSArmin Le Grand             if(!mpCssStyleParent)
194ddde725dSArmin Le Grand             {
195ddde725dSArmin Le Grand                 const SvgDocument& rDocument = mrOwner.getDocument();
196ddde725dSArmin Le Grand                 const SvgStyleAttributes* pNew = 0;
197ddde725dSArmin Le Grand 
198ddde725dSArmin Le Grand                 if(rDocument.hasSvgStyleAttributesById())
199ddde725dSArmin Le Grand                 {
200ddde725dSArmin Le Grand                     if(mrOwner.getClass())
201ddde725dSArmin Le Grand                     {
202ddde725dSArmin Le Grand                         rtl::OUString aId(rtl::OUString::createFromAscii("."));
203ddde725dSArmin Le Grand                         aId = aId + *mrOwner.getClass();
204ddde725dSArmin Le Grand                         pNew = rDocument.findSvgStyleAttributesById(aId);
205ddde725dSArmin Le Grand 
2063aaca8a3SArmin Le Grand                         if(!pNew && rClassStr.getLength())
207ddde725dSArmin Le Grand                         {
208ddde725dSArmin Le Grand                             aId = rClassStr + aId;
209ddde725dSArmin Le Grand 
210ddde725dSArmin Le Grand                             pNew = rDocument.findSvgStyleAttributesById(aId);
211ddde725dSArmin Le Grand                         }
212ddde725dSArmin Le Grand                     }
213*2600a567SArmin Le Grand 
214*2600a567SArmin Le Grand                     if(!pNew && mrOwner.getId())
215ddde725dSArmin Le Grand                     {
216ddde725dSArmin Le Grand                         pNew = rDocument.findSvgStyleAttributesById(*mrOwner.getId());
217ddde725dSArmin Le Grand                     }
218*2600a567SArmin Le Grand 
219*2600a567SArmin Le Grand                     if(!pNew && rClassStr.getLength())
2203aaca8a3SArmin Le Grand                     {
2213aaca8a3SArmin Le Grand                         pNew = rDocument.findSvgStyleAttributesById(rClassStr);
2223aaca8a3SArmin Le Grand                     }
223ddde725dSArmin Le Grand 
224ddde725dSArmin Le Grand                     if(pNew)
225ddde725dSArmin Le Grand                     {
226ddde725dSArmin Le Grand                         // found css style, set as parent
227ddde725dSArmin Le Grand                         const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew;
228ddde725dSArmin Le Grand                     }
229ddde725dSArmin Le Grand                 }
230ddde725dSArmin Le Grand             }
231ddde725dSArmin Le Grand         }
232ddde725dSArmin Le Grand 
233ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
234ddde725dSArmin Le Grand         {
235ddde725dSArmin Le Grand             if(mpCssStyleParent)
236ddde725dSArmin Le Grand             {
237ddde725dSArmin Le Grand                 return mpCssStyleParent;
238ddde725dSArmin Le Grand             }
239ddde725dSArmin Le Grand 
240ddde725dSArmin Le Grand             if(mrOwner.getParent())
241ddde725dSArmin Le Grand             {
242ddde725dSArmin Le Grand                 return mrOwner.getParent()->getSvgStyleAttributes();
243ddde725dSArmin Le Grand             }
244ddde725dSArmin Le Grand 
245ddde725dSArmin Le Grand             return 0;
246ddde725dSArmin Le Grand         }
247ddde725dSArmin Le Grand 
248ddde725dSArmin Le Grand         void SvgStyleAttributes::add_text(
249ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
250ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rSource) const
251ddde725dSArmin Le Grand         {
252ddde725dSArmin Le Grand             if(rSource.hasElements())
253ddde725dSArmin Le Grand             {
254ddde725dSArmin Le Grand                 // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D
255ddde725dSArmin Le Grand                 // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill())
256ddde725dSArmin Le Grand                 // set. When another fill is used and also evtl. stroke is set it gets necessary to
257ddde725dSArmin Le Grand                 // dismantle to geometry and add needed primitives
258ddde725dSArmin Le Grand                 const basegfx::BColor* pFill = getFill();
259ddde725dSArmin Le Grand                 const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
260ddde725dSArmin Le Grand                 const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
261ddde725dSArmin Le Grand                 const basegfx::BColor* pStroke = getStroke();
262ddde725dSArmin Le Grand                 const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
263ddde725dSArmin Le Grand                 const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
264ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aMergedArea;
265ddde725dSArmin Le Grand 
266ddde725dSArmin Le Grand                 if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern)
267ddde725dSArmin Le Grand                 {
268ddde725dSArmin Le Grand                     // text geometry is needed, create
269ddde725dSArmin Le Grand                     // use neutral ViewInformation and create LineGeometryExtractor2D
270ddde725dSArmin Le Grand                     const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
271ddde725dSArmin Le Grand                     drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
272ddde725dSArmin Le Grand 
273ddde725dSArmin Le Grand                     // proccess
274ddde725dSArmin Le Grand                     aExtractor.process(rSource);
275ddde725dSArmin Le Grand 
276ddde725dSArmin Le Grand                     // get results
277ddde725dSArmin Le Grand                     const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
278ddde725dSArmin Le Grand                     const sal_uInt32 nResultCount(rResult.size());
279ddde725dSArmin Le Grand                     basegfx::B2DPolyPolygonVector aTextFillVector;
280ddde725dSArmin Le Grand                     aTextFillVector.reserve(nResultCount);
281ddde725dSArmin Le Grand 
282ddde725dSArmin Le Grand                     for(sal_uInt32 a(0); a < nResultCount; a++)
283ddde725dSArmin Le Grand                     {
284ddde725dSArmin Le Grand                         const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
285ddde725dSArmin Le Grand 
286ddde725dSArmin Le Grand                         if(rCandidate.getIsFilled())
287ddde725dSArmin Le Grand                         {
288ddde725dSArmin Le Grand                             aTextFillVector.push_back(rCandidate.getB2DPolyPolygon());
289ddde725dSArmin Le Grand                         }
290ddde725dSArmin Le Grand                     }
291ddde725dSArmin Le Grand 
292ddde725dSArmin Le Grand                     if(!aTextFillVector.empty())
293ddde725dSArmin Le Grand                     {
294ddde725dSArmin Le Grand                         aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector);
295ddde725dSArmin Le Grand                     }
296ddde725dSArmin Le Grand                 }
297ddde725dSArmin Le Grand 
298ddde725dSArmin Le Grand                 const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern);
299ddde725dSArmin Le Grand 
300ddde725dSArmin Le Grand                 // add fill. Use geometry even for simple color fill when stroke
301ddde725dSArmin Le Grand                 // is used, else text rendering and the geometry-based stroke will
302ddde725dSArmin Le Grand                 // normally not really match optically due to divrese system text
303ddde725dSArmin Le Grand                 // renderers
304ddde725dSArmin Le Grand                 if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed))
305ddde725dSArmin Le Grand                 {
306ddde725dSArmin Le Grand                     // create text fill content based on geometry
307ddde725dSArmin Le Grand                     add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange());
308ddde725dSArmin Le Grand                 }
309ddde725dSArmin Le Grand                 else if(pFill)
310ddde725dSArmin Le Grand                 {
311ddde725dSArmin Le Grand                     // add the already prepared primitives for single color fill
312ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
313ddde725dSArmin Le Grand                 }
314ddde725dSArmin Le Grand 
315ddde725dSArmin Le Grand                 // add stroke
316ddde725dSArmin Le Grand                 if(aMergedArea.count() && bStrokeUsed)
317ddde725dSArmin Le Grand                 {
318ddde725dSArmin Le Grand                     // create text stroke content
319ddde725dSArmin Le Grand                     add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange());
320ddde725dSArmin Le Grand                 }
321ddde725dSArmin Le Grand             }
322ddde725dSArmin Le Grand         }
323ddde725dSArmin Le Grand 
324ddde725dSArmin Le Grand         void SvgStyleAttributes::add_fillGradient(
325ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
326ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
327ddde725dSArmin Le Grand             const SvgGradientNode& rFillGradient,
328ddde725dSArmin Le Grand             const basegfx::B2DRange& rGeoRange) const
329ddde725dSArmin Le Grand         {
330ddde725dSArmin Le Grand             // create fill content
331ddde725dSArmin Le Grand             drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector;
332ddde725dSArmin Le Grand 
333ddde725dSArmin Le Grand             // get the color stops
334ddde725dSArmin Le Grand             rFillGradient.collectGradientEntries(aSvgGradientEntryVector);
335ddde725dSArmin Le Grand 
336ddde725dSArmin Le Grand             if(!aSvgGradientEntryVector.empty())
337ddde725dSArmin Le Grand             {
338ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aGeoToUnit;
339ddde725dSArmin Le Grand 
340ddde725dSArmin Le Grand                 if(rFillGradient.getGradientTransform())
341ddde725dSArmin Le Grand                 {
342ddde725dSArmin Le Grand                     aGeoToUnit = *rFillGradient.getGradientTransform();
343ddde725dSArmin Le Grand                 }
344ddde725dSArmin Le Grand 
345ddde725dSArmin Le Grand                 if(userSpaceOnUse == rFillGradient.getGradientUnits())
346ddde725dSArmin Le Grand                 {
347ddde725dSArmin Le Grand                     aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY());
348ddde725dSArmin Le Grand                     aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight());
349ddde725dSArmin Le Grand                 }
350ddde725dSArmin Le Grand 
351ddde725dSArmin Le Grand                 if(SVGTokenLinearGradient == rFillGradient.getType())
352ddde725dSArmin Le Grand                 {
353ddde725dSArmin Le Grand                     basegfx::B2DPoint aStart(0.0, 0.0);
354ddde725dSArmin Le Grand                     basegfx::B2DPoint aEnd(1.0, 0.0);
355ddde725dSArmin Le Grand 
356ddde725dSArmin Le Grand                     if(userSpaceOnUse == rFillGradient.getGradientUnits())
357ddde725dSArmin Le Grand                     {
358ddde725dSArmin Le Grand                         // all possible units
359ddde725dSArmin Le Grand                         aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate));
360ddde725dSArmin Le Grand                         aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate));
361ddde725dSArmin Le Grand                         aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate));
362ddde725dSArmin Le Grand                         aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate));
363ddde725dSArmin Le Grand                     }
364ddde725dSArmin Le Grand                     else
365ddde725dSArmin Le Grand                     {
366ddde725dSArmin Le Grand                         // fractions or percent relative to object bounds
367ddde725dSArmin Le Grand                         const SvgNumber X1(rFillGradient.getX1());
368ddde725dSArmin Le Grand                         const SvgNumber Y1(rFillGradient.getY1());
369ddde725dSArmin Le Grand                         const SvgNumber X2(rFillGradient.getX2());
370ddde725dSArmin Le Grand                         const SvgNumber Y2(rFillGradient.getY2());
371ddde725dSArmin Le Grand 
372ddde725dSArmin Le Grand                         aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber());
373ddde725dSArmin Le Grand                         aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber());
374ddde725dSArmin Le Grand                         aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber());
375ddde725dSArmin Le Grand                         aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber());
376ddde725dSArmin Le Grand                     }
377ddde725dSArmin Le Grand 
378ddde725dSArmin Le Grand                     if(!aGeoToUnit.isIdentity())
379ddde725dSArmin Le Grand                     {
380ddde725dSArmin Le Grand                         aStart *= aGeoToUnit;
381ddde725dSArmin Le Grand                         aEnd *= aGeoToUnit;
382ddde725dSArmin Le Grand                     }
383ddde725dSArmin Le Grand 
384ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
385ddde725dSArmin Le Grand                         rTarget,
386ddde725dSArmin Le Grand                         new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
387ddde725dSArmin Le Grand                             rPath,
388ddde725dSArmin Le Grand                             aSvgGradientEntryVector,
389ddde725dSArmin Le Grand                             aStart,
390ddde725dSArmin Le Grand                             aEnd,
391ddde725dSArmin Le Grand                             rFillGradient.getSpreadMethod()));
392ddde725dSArmin Le Grand                 }
393ddde725dSArmin Le Grand                 else
394ddde725dSArmin Le Grand                 {
395ddde725dSArmin Le Grand                     basegfx::B2DPoint aStart(0.5, 0.5);
396ddde725dSArmin Le Grand                     basegfx::B2DPoint aFocal;
397ddde725dSArmin Le Grand                     double fRadius(0.5);
398ddde725dSArmin Le Grand                     const SvgNumber* pFx = rFillGradient.getFx();
399ddde725dSArmin Le Grand                     const SvgNumber* pFy = rFillGradient.getFy();
400ddde725dSArmin Le Grand                     const bool bFocal(pFx || pFy);
401ddde725dSArmin Le Grand 
402ddde725dSArmin Le Grand                     if(userSpaceOnUse == rFillGradient.getGradientUnits())
403ddde725dSArmin Le Grand                     {
404ddde725dSArmin Le Grand                         // all possible units
405ddde725dSArmin Le Grand                         aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate));
406ddde725dSArmin Le Grand                         aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate));
407ddde725dSArmin Le Grand                         fRadius = rFillGradient.getR().solve(mrOwner, length);
408ddde725dSArmin Le Grand 
409ddde725dSArmin Le Grand                         if(bFocal)
410ddde725dSArmin Le Grand                         {
411ddde725dSArmin Le Grand                             aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX());
412ddde725dSArmin Le Grand                             aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY());
413ddde725dSArmin Le Grand                         }
414ddde725dSArmin Le Grand                     }
415ddde725dSArmin Le Grand                     else
416ddde725dSArmin Le Grand                     {
417ddde725dSArmin Le Grand                         // fractions or percent relative to object bounds
418ddde725dSArmin Le Grand                         const SvgNumber Cx(rFillGradient.getCx());
419ddde725dSArmin Le Grand                         const SvgNumber Cy(rFillGradient.getCy());
420ddde725dSArmin Le Grand                         const SvgNumber R(rFillGradient.getR());
421ddde725dSArmin Le Grand 
422ddde725dSArmin Le Grand                         aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber());
423ddde725dSArmin Le Grand                         aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber());
424ddde725dSArmin Le Grand                         fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber();
425ddde725dSArmin Le Grand 
426ddde725dSArmin Le Grand                         if(bFocal)
427ddde725dSArmin Le Grand                         {
428ddde725dSArmin Le Grand                             aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX());
429ddde725dSArmin Le Grand                             aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY());
430ddde725dSArmin Le Grand                         }
431ddde725dSArmin Le Grand                     }
432ddde725dSArmin Le Grand 
433ddde725dSArmin Le Grand                     if(!aGeoToUnit.isIdentity())
434ddde725dSArmin Le Grand                     {
435ddde725dSArmin Le Grand                         aStart *= aGeoToUnit;
436ddde725dSArmin Le Grand                         fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength();
437ddde725dSArmin Le Grand 
438ddde725dSArmin Le Grand                         if(bFocal)
439ddde725dSArmin Le Grand                         {
440ddde725dSArmin Le Grand                             aFocal *= aGeoToUnit;
441ddde725dSArmin Le Grand                         }
442ddde725dSArmin Le Grand                     }
443ddde725dSArmin Le Grand 
444ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
445ddde725dSArmin Le Grand                         rTarget,
446ddde725dSArmin Le Grand                         new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
447ddde725dSArmin Le Grand                             rPath,
448ddde725dSArmin Le Grand                             aSvgGradientEntryVector,
449ddde725dSArmin Le Grand                             aStart,
450ddde725dSArmin Le Grand                             fRadius,
451ddde725dSArmin Le Grand                             rFillGradient.getSpreadMethod(),
452ddde725dSArmin Le Grand                             bFocal ? &aFocal : 0));
453ddde725dSArmin Le Grand                 }
454ddde725dSArmin Le Grand             }
455ddde725dSArmin Le Grand         }
456ddde725dSArmin Le Grand 
457ddde725dSArmin Le Grand         void SvgStyleAttributes::add_fillPatternTransform(
458ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
459ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
460ddde725dSArmin Le Grand             const SvgPatternNode& rFillPattern,
461ddde725dSArmin Le Grand             const basegfx::B2DRange& rGeoRange) const
462ddde725dSArmin Le Grand         {
463ddde725dSArmin Le Grand             // prepare fill polyPolygon with given pattern, check for patternTransform
464ddde725dSArmin Le Grand             if(rFillPattern.getPatternTransform() && !rFillPattern.getPatternTransform()->isIdentity())
465ddde725dSArmin Le Grand             {
466ddde725dSArmin Le Grand                 // PatternTransform is active; Handle by filling the inverse transformed
467ddde725dSArmin Le Grand                 // path and back-transforming the result
468ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aPath(rPath);
469ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aInv(*rFillPattern.getPatternTransform());
470ddde725dSArmin Le Grand                 drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
471ddde725dSArmin Le Grand 
472ddde725dSArmin Le Grand                 aInv.invert();
473ddde725dSArmin Le Grand                 aPath.transform(aInv);
474ddde725dSArmin Le Grand                 add_fillPattern(aPath, aNewTarget, rFillPattern, aPath.getB2DRange());
475ddde725dSArmin Le Grand 
476ddde725dSArmin Le Grand                 if(aNewTarget.hasElements())
477ddde725dSArmin Le Grand                 {
478ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
479ddde725dSArmin Le Grand                         rTarget,
480ddde725dSArmin Le Grand                         new drawinglayer::primitive2d::TransformPrimitive2D(
481ddde725dSArmin Le Grand                             *rFillPattern.getPatternTransform(),
482ddde725dSArmin Le Grand                             aNewTarget));
483ddde725dSArmin Le Grand                 }
484ddde725dSArmin Le Grand             }
485ddde725dSArmin Le Grand             else
486ddde725dSArmin Le Grand             {
487ddde725dSArmin Le Grand                 // no patternTransform, create fillPattern directly
488ddde725dSArmin Le Grand                 add_fillPattern(rPath, rTarget, rFillPattern, rGeoRange);
489ddde725dSArmin Le Grand             }
490ddde725dSArmin Le Grand         }
491ddde725dSArmin Le Grand 
492ddde725dSArmin Le Grand         void SvgStyleAttributes::add_fillPattern(
493ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
494ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
495ddde725dSArmin Le Grand             const SvgPatternNode& rFillPattern,
496ddde725dSArmin Le Grand             const basegfx::B2DRange& rGeoRange) const
497ddde725dSArmin Le Grand         {
498ddde725dSArmin Le Grand             // fill polyPolygon with given pattern
499ddde725dSArmin Le Grand             const drawinglayer::primitive2d::Primitive2DSequence& rPrimitives = rFillPattern.getPatternPrimitives();
500ddde725dSArmin Le Grand 
501ddde725dSArmin Le Grand             if(rPrimitives.hasElements())
502ddde725dSArmin Le Grand             {
503ddde725dSArmin Le Grand                 double fTargetWidth(rGeoRange.getWidth());
504ddde725dSArmin Le Grand                 double fTargetHeight(rGeoRange.getHeight());
505ddde725dSArmin Le Grand 
506ddde725dSArmin Le Grand                 if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
507ddde725dSArmin Le Grand                 {
508ddde725dSArmin Le Grand                     // get relative values from pattern
509ddde725dSArmin Le Grand                     double fX(0.0);
510ddde725dSArmin Le Grand                     double fY(0.0);
511ddde725dSArmin Le Grand                     double fW(0.0);
512ddde725dSArmin Le Grand                     double fH(0.0);
513ddde725dSArmin Le Grand 
514ddde725dSArmin Le Grand                     rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner);
515ddde725dSArmin Le Grand 
516ddde725dSArmin Le Grand                     if(fW > 0.0 && fH > 0.0)
517ddde725dSArmin Le Grand                     {
518ddde725dSArmin Le Grand                         // build the reference range relative to the rGeoRange
519ddde725dSArmin Le Grand                         const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH);
520ddde725dSArmin Le Grand 
521ddde725dSArmin Le Grand                         // find out how the content is mapped to the reference range
522ddde725dSArmin Le Grand                         basegfx::B2DHomMatrix aMapPrimitivesToUnitRange;
523ddde725dSArmin Le Grand                         const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox();
524ddde725dSArmin Le Grand 
525ddde725dSArmin Le Grand                         if(pViewBox)
526ddde725dSArmin Le Grand                         {
527ddde725dSArmin Le Grand                             // use viewBox/preserveAspectRatio
528ddde725dSArmin Le Grand                             const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio();
529ddde725dSArmin Le Grand                             const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
530ddde725dSArmin Le Grand 
531ddde725dSArmin Le Grand                             if(rRatio.isSet())
532ddde725dSArmin Le Grand                             {
533ddde725dSArmin Le Grand                                 // let mapping be created from SvgAspectRatio
534ddde725dSArmin Le Grand                                 aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox);
535ddde725dSArmin Le Grand                             }
536ddde725dSArmin Le Grand                             else
537ddde725dSArmin Le Grand                             {
538ddde725dSArmin Le Grand                                 // choose default mapping
539ddde725dSArmin Le Grand                                 aMapPrimitivesToUnitRange = rRatio.createLinearMapping(aUnitRange, *pViewBox);
540ddde725dSArmin Le Grand                             }
541ddde725dSArmin Le Grand                         }
542ddde725dSArmin Le Grand                         else
543ddde725dSArmin Le Grand                         {
544ddde725dSArmin Le Grand                             // use patternContentUnits
545ddde725dSArmin Le Grand                             const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse);
546ddde725dSArmin Le Grand 
547ddde725dSArmin Le Grand                             if(userSpaceOnUse == aPatternContentUnits)
548ddde725dSArmin Le Grand                             {
549ddde725dSArmin Le Grand                                 // create relative mapping to unit coordinates
550ddde725dSArmin Le Grand                                 aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight));
551ddde725dSArmin Le Grand                             }
552ddde725dSArmin Le Grand                             else
553ddde725dSArmin Le Grand                             {
554ddde725dSArmin Le Grand                                 aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH);
555ddde725dSArmin Le Grand                             }
556ddde725dSArmin Le Grand                         }
557ddde725dSArmin Le Grand 
558ddde725dSArmin Le Grand                         // apply aMapPrimitivesToUnitRange to content when used
559ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aPrimitives(rPrimitives);
560ddde725dSArmin Le Grand 
561ddde725dSArmin Le Grand                         if(!aMapPrimitivesToUnitRange.isIdentity())
562ddde725dSArmin Le Grand                         {
563ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xRef(
564ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
565ddde725dSArmin Le Grand                                     aMapPrimitivesToUnitRange,
566ddde725dSArmin Le Grand                                     aPrimitives));
567ddde725dSArmin Le Grand 
568ddde725dSArmin Le Grand                             aPrimitives = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
569ddde725dSArmin Le Grand                         }
570ddde725dSArmin Le Grand 
571ddde725dSArmin Le Grand                         // embed in PatternFillPrimitive2D
572ddde725dSArmin Le Grand                         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
573ddde725dSArmin Le Grand                             rTarget,
574ddde725dSArmin Le Grand                             new drawinglayer::primitive2d::PatternFillPrimitive2D(
575ddde725dSArmin Le Grand                                 rPath,
576ddde725dSArmin Le Grand                                 aPrimitives,
577ddde725dSArmin Le Grand                                 aReferenceRange));
578ddde725dSArmin Le Grand                     }
579ddde725dSArmin Le Grand                 }
580ddde725dSArmin Le Grand             }
581ddde725dSArmin Le Grand         }
582ddde725dSArmin Le Grand 
583ddde725dSArmin Le Grand         void SvgStyleAttributes::add_fill(
584ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
585ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
586ddde725dSArmin Le Grand             const basegfx::B2DRange& rGeoRange) const
587ddde725dSArmin Le Grand         {
588ddde725dSArmin Le Grand             const basegfx::BColor* pFill = getFill();
589ddde725dSArmin Le Grand             const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
590ddde725dSArmin Le Grand             const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
591ddde725dSArmin Le Grand 
592ddde725dSArmin Le Grand             if(pFill || pFillGradient || pFillPattern)
593ddde725dSArmin Le Grand             {
594ddde725dSArmin Le Grand                 const double fFillOpacity(getFillOpacity().solve(mrOwner, length));
595ddde725dSArmin Le Grand 
596ddde725dSArmin Le Grand                 if(basegfx::fTools::more(fFillOpacity, 0.0))
597ddde725dSArmin Le Grand                 {
598ddde725dSArmin Le Grand                     drawinglayer::primitive2d::Primitive2DSequence aNewFill;
599ddde725dSArmin Le Grand 
600ddde725dSArmin Le Grand                     if(pFillGradient)
601ddde725dSArmin Le Grand                     {
602ddde725dSArmin Le Grand                         // create fill content with SVG gradient primitive
603ddde725dSArmin Le Grand                         add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange);
604ddde725dSArmin Le Grand                     }
605ddde725dSArmin Le Grand                     else if(pFillPattern)
606ddde725dSArmin Le Grand                     {
607ddde725dSArmin Le Grand                         // create fill content with SVG pattern primitive
608ddde725dSArmin Le Grand                         add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange);
609ddde725dSArmin Le Grand                     }
610ddde725dSArmin Le Grand                     else // if(pFill)
611ddde725dSArmin Le Grand                     {
612ddde725dSArmin Le Grand                         // create fill content
613ddde725dSArmin Le Grand                         aNewFill.realloc(1);
614ddde725dSArmin Le Grand                         aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
615ddde725dSArmin Le Grand                             rPath,
616ddde725dSArmin Le Grand                             *pFill);
617ddde725dSArmin Le Grand                     }
618ddde725dSArmin Le Grand 
619ddde725dSArmin Le Grand                     if(aNewFill.hasElements())
620ddde725dSArmin Le Grand                     {
621ddde725dSArmin Le Grand                         if(basegfx::fTools::less(fFillOpacity, 1.0))
622ddde725dSArmin Le Grand                         {
623ddde725dSArmin Le Grand                             // embed in UnifiedTransparencePrimitive2D
624ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
625ddde725dSArmin Le Grand                                 rTarget,
626ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
627ddde725dSArmin Le Grand                                     aNewFill,
628ddde725dSArmin Le Grand                                     1.0 - fFillOpacity));
629ddde725dSArmin Le Grand                         }
630ddde725dSArmin Le Grand                         else
631ddde725dSArmin Le Grand                         {
632ddde725dSArmin Le Grand                             // append
633ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewFill);
634ddde725dSArmin Le Grand                         }
635ddde725dSArmin Le Grand                     }
636ddde725dSArmin Le Grand                 }
637ddde725dSArmin Le Grand             }
638ddde725dSArmin Le Grand         }
639ddde725dSArmin Le Grand 
640ddde725dSArmin Le Grand         void SvgStyleAttributes::add_stroke(
641ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
642ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
643ddde725dSArmin Le Grand             const basegfx::B2DRange& rGeoRange) const
644ddde725dSArmin Le Grand         {
645ddde725dSArmin Le Grand             const basegfx::BColor* pStroke = getStroke();
646ddde725dSArmin Le Grand             const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
647ddde725dSArmin Le Grand             const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
648ddde725dSArmin Le Grand 
649ddde725dSArmin Le Grand             if(pStroke || pStrokeGradient || pStrokePattern)
650ddde725dSArmin Le Grand             {
651ddde725dSArmin Le Grand                 drawinglayer::primitive2d::Primitive2DSequence aNewStroke;
652ddde725dSArmin Le Grand                 const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length));
653ddde725dSArmin Le Grand 
654ddde725dSArmin Le Grand                 if(basegfx::fTools::more(fStrokeOpacity, 0.0))
655ddde725dSArmin Le Grand                 {
656ddde725dSArmin Le Grand                     // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all
657ddde725dSArmin Le Grand                     const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
658ddde725dSArmin Le Grand 
659ddde725dSArmin Le Grand                     if(basegfx::fTools::more(fStrokeWidth, 0.0))
660ddde725dSArmin Le Grand                     {
661ddde725dSArmin Le Grand                         // get LineJoin and stroke array
662ddde725dSArmin Le Grand                         const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
663ddde725dSArmin Le Grand                         ::std::vector< double > aDashArray;
664ddde725dSArmin Le Grand 
665ddde725dSArmin Le Grand                         if(!getStrokeDasharray().empty())
666ddde725dSArmin Le Grand                         {
667ddde725dSArmin Le Grand                             aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length);
668ddde725dSArmin Le Grand                         }
669ddde725dSArmin Le Grand 
670ddde725dSArmin Le Grand                         // todo: Handle getStrokeDashOffset()
671ddde725dSArmin Le Grand                         // todo: Handle getStrokeLinecap()
672ddde725dSArmin Le Grand 
673ddde725dSArmin Le Grand                         // prepare line attribute
674ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive;
675ddde725dSArmin Le Grand                         const drawinglayer::attribute::LineAttribute aLineAttribute(
676ddde725dSArmin Le Grand                             pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
677ddde725dSArmin Le Grand                             fStrokeWidth,
678ddde725dSArmin Le Grand                             aB2DLineJoin);
679ddde725dSArmin Le Grand 
680ddde725dSArmin Le Grand                         if(aDashArray.empty())
681ddde725dSArmin Le Grand                         {
682ddde725dSArmin Le Grand                             aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
683ddde725dSArmin Le Grand                                 rPath,
684ddde725dSArmin Le Grand                                 aLineAttribute);
685ddde725dSArmin Le Grand                         }
686ddde725dSArmin Le Grand                         else
687ddde725dSArmin Le Grand                         {
688ddde725dSArmin Le Grand                             const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray);
689ddde725dSArmin Le Grand 
690ddde725dSArmin Le Grand                             aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
691ddde725dSArmin Le Grand                                 rPath,
692ddde725dSArmin Le Grand                                 aLineAttribute,
693ddde725dSArmin Le Grand                                 aDashArray);
694ddde725dSArmin Le Grand                         }
695ddde725dSArmin Le Grand 
696ddde725dSArmin Le Grand                         if(pStrokeGradient || pStrokePattern)
697ddde725dSArmin Le Grand                         {
698ddde725dSArmin Le Grand                             // put primitive into Primitive2DReference and Primitive2DSequence
699ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aNewLinePrimitive, 1);
700ddde725dSArmin Le Grand 
701ddde725dSArmin Le Grand                             // use neutral ViewInformation and create LineGeometryExtractor2D
702ddde725dSArmin Le Grand                             const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
703ddde725dSArmin Le Grand                             drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
704ddde725dSArmin Le Grand 
705ddde725dSArmin Le Grand                             // proccess
706ddde725dSArmin Le Grand                             aExtractor.process(aSeq);
707ddde725dSArmin Le Grand 
708ddde725dSArmin Le Grand                             // check for fill rsults
709ddde725dSArmin Le Grand                             const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills());
710ddde725dSArmin Le Grand 
711e2bf1e9dSArmin Le Grand                             if(!rLineFillVector.empty())
712ddde725dSArmin Le Grand                             {
713ddde725dSArmin Le Grand                                 const basegfx::B2DPolyPolygon aMergedArea(
714ddde725dSArmin Le Grand                                     basegfx::tools::mergeToSinglePolyPolygon(
715e2bf1e9dSArmin Le Grand                                         rLineFillVector));
716ddde725dSArmin Le Grand 
717ddde725dSArmin Le Grand                                 if(aMergedArea.count())
718ddde725dSArmin Le Grand                                 {
719ddde725dSArmin Le Grand                                     if(pStrokeGradient)
720ddde725dSArmin Le Grand                                     {
721ddde725dSArmin Le Grand                                         // create fill content with SVG gradient primitive. Use original GeoRange,
722ddde725dSArmin Le Grand                                         // e.g. from circle without LineWidth
723ddde725dSArmin Le Grand                                         add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange);
724ddde725dSArmin Le Grand                                     }
725ddde725dSArmin Le Grand                                     else // if(pStrokePattern)
726ddde725dSArmin Le Grand                                     {
727ddde725dSArmin Le Grand                                         // create fill content with SVG pattern primitive. Use GeoRange
728ddde725dSArmin Le Grand                                         // from the expanded data, e.g. circle with extended geo by half linewidth
729ddde725dSArmin Le Grand                                         add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange());
730ddde725dSArmin Le Grand                                     }
731ddde725dSArmin Le Grand                                 }
732ddde725dSArmin Le Grand                             }
733ddde725dSArmin Le Grand                         }
734ddde725dSArmin Le Grand                         else // if(pStroke)
735ddde725dSArmin Le Grand                         {
736ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aNewStroke, aNewLinePrimitive);
737ddde725dSArmin Le Grand                         }
738ddde725dSArmin Le Grand 
739ddde725dSArmin Le Grand                         if(aNewStroke.hasElements())
740ddde725dSArmin Le Grand                         {
741ddde725dSArmin Le Grand                             if(basegfx::fTools::less(fStrokeOpacity, 1.0))
742ddde725dSArmin Le Grand                             {
743ddde725dSArmin Le Grand                                 // embed in UnifiedTransparencePrimitive2D
744ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
745ddde725dSArmin Le Grand                                     rTarget,
746ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
747ddde725dSArmin Le Grand                                         aNewStroke,
748ddde725dSArmin Le Grand                                         1.0 - fStrokeOpacity));
749ddde725dSArmin Le Grand                             }
750ddde725dSArmin Le Grand                             else
751ddde725dSArmin Le Grand                             {
752ddde725dSArmin Le Grand                                 // append
753ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewStroke);
754ddde725dSArmin Le Grand                             }
755ddde725dSArmin Le Grand                         }
756ddde725dSArmin Le Grand                     }
757ddde725dSArmin Le Grand                 }
758ddde725dSArmin Le Grand             }
759ddde725dSArmin Le Grand         }
760ddde725dSArmin Le Grand 
761ddde725dSArmin Le Grand         double get_markerRotation(
762ddde725dSArmin Le Grand             const SvgMarkerNode& rMarker,
763ddde725dSArmin Le Grand             const basegfx::B2DPolygon& rPolygon,
764ddde725dSArmin Le Grand             const sal_uInt32 nIndex)
765ddde725dSArmin Le Grand         {
766ddde725dSArmin Le Grand             double fAngle(0.0);
767ddde725dSArmin Le Grand             const sal_uInt32 nPointCount(rPolygon.count());
768ddde725dSArmin Le Grand 
769ddde725dSArmin Le Grand             if(nPointCount)
770ddde725dSArmin Le Grand             {
771ddde725dSArmin Le Grand                 if(rMarker.getOrientAuto())
772ddde725dSArmin Le Grand                 {
773ddde725dSArmin Le Grand                     const bool bPrev(rPolygon.isClosed() || nIndex > 0);
774ddde725dSArmin Le Grand                     basegfx::B2DCubicBezier aSegment;
775ddde725dSArmin Le Grand                     basegfx::B2DVector aPrev;
776ddde725dSArmin Le Grand                     basegfx::B2DVector aNext;
777ddde725dSArmin Le Grand 
778ddde725dSArmin Le Grand                     if(bPrev)
779ddde725dSArmin Le Grand                     {
780ddde725dSArmin Le Grand                         rPolygon.getBezierSegment((nIndex - 1) % nPointCount, aSegment);
781ddde725dSArmin Le Grand                         aPrev = aSegment.getTangent(1.0);
782ddde725dSArmin Le Grand                     }
783ddde725dSArmin Le Grand 
784ddde725dSArmin Le Grand                     const bool bNext(rPolygon.isClosed() || nIndex + 1 < nPointCount);
785ddde725dSArmin Le Grand 
786ddde725dSArmin Le Grand                     if(bNext)
787ddde725dSArmin Le Grand                     {
788ddde725dSArmin Le Grand                         rPolygon.getBezierSegment(nIndex % nPointCount, aSegment);
789ddde725dSArmin Le Grand                         aNext = aSegment.getTangent(0.0);
790ddde725dSArmin Le Grand                     }
791ddde725dSArmin Le Grand 
792ddde725dSArmin Le Grand                     if(bPrev && bNext)
793ddde725dSArmin Le Grand                     {
794ddde725dSArmin Le Grand                         fAngle = atan2(aPrev.getY() + aNext.getY(), aPrev.getX() + aNext.getX());
795ddde725dSArmin Le Grand                     }
796ddde725dSArmin Le Grand                     else if(bPrev)
797ddde725dSArmin Le Grand                     {
798ddde725dSArmin Le Grand                         fAngle = atan2(aPrev.getY(), aPrev.getX());
799ddde725dSArmin Le Grand                     }
800ddde725dSArmin Le Grand                     else if(bNext)
801ddde725dSArmin Le Grand                     {
802ddde725dSArmin Le Grand                         fAngle = atan2(aNext.getY(), aNext.getX());
803ddde725dSArmin Le Grand                     }
804ddde725dSArmin Le Grand                 }
805ddde725dSArmin Le Grand                 else
806ddde725dSArmin Le Grand                 {
807ddde725dSArmin Le Grand                     fAngle = rMarker.getAngle();
808ddde725dSArmin Le Grand                 }
809ddde725dSArmin Le Grand             }
810ddde725dSArmin Le Grand 
811ddde725dSArmin Le Grand             return fAngle;
812ddde725dSArmin Le Grand         }
813ddde725dSArmin Le Grand 
814ddde725dSArmin Le Grand         bool SvgStyleAttributes::prepare_singleMarker(
815ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
816ddde725dSArmin Le Grand             basegfx::B2DHomMatrix& rMarkerTransform,
817ddde725dSArmin Le Grand             basegfx::B2DRange& rClipRange,
818ddde725dSArmin Le Grand             const SvgMarkerNode& rMarker) const
819ddde725dSArmin Le Grand         {
820ddde725dSArmin Le Grand             // reset return values
821ddde725dSArmin Le Grand             rMarkerTransform.identity();
822ddde725dSArmin Le Grand             rClipRange.reset();
823ddde725dSArmin Le Grand 
824ddde725dSArmin Le Grand             // get marker primitive representation
825ddde725dSArmin Le Grand             rMarkerPrimitives = rMarker.getMarkerPrimitives();
826ddde725dSArmin Le Grand 
827ddde725dSArmin Le Grand             if(rMarkerPrimitives.hasElements())
828ddde725dSArmin Le Grand             {
829ddde725dSArmin Le Grand                 basegfx::B2DRange aPrimitiveRange;
830ddde725dSArmin Le Grand 
831ddde725dSArmin Le Grand                 if(rMarker.getViewBox())
832ddde725dSArmin Le Grand                 {
833ddde725dSArmin Le Grand                     aPrimitiveRange = *rMarker.getViewBox();
834ddde725dSArmin Le Grand                 }
835ddde725dSArmin Le Grand                 else
836ddde725dSArmin Le Grand                 {
837ddde725dSArmin Le Grand                     aPrimitiveRange = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
838ddde725dSArmin Le Grand                         rMarkerPrimitives,
839ddde725dSArmin Le Grand                         drawinglayer::geometry::ViewInformation2D());
840ddde725dSArmin Le Grand                 }
841ddde725dSArmin Le Grand 
842ddde725dSArmin Le Grand                 if(aPrimitiveRange.getWidth() > 0.0 && aPrimitiveRange.getHeight() > 0.0)
843ddde725dSArmin Le Grand                 {
844ddde725dSArmin Le Grand                     double fTargetWidth(rMarker.getMarkerWidth().isSet() ? rMarker.getMarkerWidth().solve(mrOwner, xcoordinate) : 0.0);
845ddde725dSArmin Le Grand                     double fTargetHeight(rMarker.getMarkerHeight().isSet() ? rMarker.getMarkerHeight().solve(mrOwner, xcoordinate) : 0.0);
846ddde725dSArmin Le Grand 
847ddde725dSArmin Le Grand                     if(SvgMarkerNode::strokeWidth == rMarker.getMarkerUnits())
848ddde725dSArmin Le Grand                     {
849ddde725dSArmin Le Grand                         // relative to strokeWidth
850ddde725dSArmin Le Grand                         const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
851ddde725dSArmin Le Grand 
852ddde725dSArmin Le Grand                         fTargetWidth *= fStrokeWidth;
853ddde725dSArmin Le Grand                         fTargetHeight *= fStrokeWidth;
854ddde725dSArmin Le Grand                     }
855ddde725dSArmin Le Grand 
856ddde725dSArmin Le Grand                     if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
857ddde725dSArmin Le Grand                     {
858ddde725dSArmin Le Grand                         const basegfx::B2DRange aTargetRange(0.0, 0.0, fTargetWidth, fTargetHeight);
859ddde725dSArmin Le Grand 
860ddde725dSArmin Le Grand                         // subbstract refX, refY first, it's in marker local coordinates
861ddde725dSArmin Le Grand                         rMarkerTransform.translate(
862ddde725dSArmin Le Grand                             rMarker.getRefX().isSet() ? -rMarker.getRefX().solve(mrOwner, xcoordinate) : 0.0,
863ddde725dSArmin Le Grand                             rMarker.getRefY().isSet() ? -rMarker.getRefY().solve(mrOwner, ycoordinate) : 0.0);
864ddde725dSArmin Le Grand 
865ddde725dSArmin Le Grand                         // create mapping
866ddde725dSArmin Le Grand                         const SvgAspectRatio& rRatio = rMarker.getSvgAspectRatio();
867ddde725dSArmin Le Grand 
868ddde725dSArmin Le Grand                         if(rRatio.isSet())
869ddde725dSArmin Le Grand                         {
870ddde725dSArmin Le Grand                             // let mapping be created from SvgAspectRatio
871ddde725dSArmin Le Grand                             rMarkerTransform = rRatio.createMapping(aTargetRange, aPrimitiveRange) * rMarkerTransform;
872ddde725dSArmin Le Grand 
873ddde725dSArmin Le Grand                             if(rRatio.isMeetOrSlice())
874ddde725dSArmin Le Grand                             {
875ddde725dSArmin Le Grand                                 // need to clip
876ddde725dSArmin Le Grand                                 rClipRange = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
877ddde725dSArmin Le Grand                             }
878ddde725dSArmin Le Grand                         }
879ddde725dSArmin Le Grand                         else
880ddde725dSArmin Le Grand                         {
881ddde725dSArmin Le Grand                             // choose default mapping
882ddde725dSArmin Le Grand                             rMarkerTransform = rRatio.createLinearMapping(aTargetRange, aPrimitiveRange) * rMarkerTransform;
883ddde725dSArmin Le Grand                         }
884ddde725dSArmin Le Grand 
885ddde725dSArmin Le Grand                         return true;
886ddde725dSArmin Le Grand                     }
887ddde725dSArmin Le Grand                 }
888ddde725dSArmin Le Grand             }
889ddde725dSArmin Le Grand 
890ddde725dSArmin Le Grand             return false;
891ddde725dSArmin Le Grand         }
892ddde725dSArmin Le Grand 
893ddde725dSArmin Le Grand         void SvgStyleAttributes::add_singleMarker(
894ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
895ddde725dSArmin Le Grand             const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
896ddde725dSArmin Le Grand             const basegfx::B2DHomMatrix& rMarkerTransform,
897e2bf1e9dSArmin Le Grand             const basegfx::B2DRange& /*rClipRange*/,
898ddde725dSArmin Le Grand             const SvgMarkerNode& rMarker,
899ddde725dSArmin Le Grand             const basegfx::B2DPolygon& rCandidate,
900ddde725dSArmin Le Grand             const sal_uInt32 nIndex) const
901ddde725dSArmin Le Grand         {
902ddde725dSArmin Le Grand             const sal_uInt32 nPointCount(rCandidate.count());
903ddde725dSArmin Le Grand 
904ddde725dSArmin Le Grand             if(nPointCount)
905ddde725dSArmin Le Grand             {
906ddde725dSArmin Le Grand                 // get and apply rotation
907ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aCombinedTransform(rMarkerTransform);
908ddde725dSArmin Le Grand                 aCombinedTransform.rotate(get_markerRotation(rMarker, rCandidate, nIndex));
909ddde725dSArmin Le Grand 
910ddde725dSArmin Le Grand                 // get and apply target position
911ddde725dSArmin Le Grand                 const basegfx::B2DPoint aPoint(rCandidate.getB2DPoint(nIndex % nPointCount));
912ddde725dSArmin Le Grand                 aCombinedTransform.translate(aPoint.getX(), aPoint.getY());
913ddde725dSArmin Le Grand 
914ddde725dSArmin Le Grand                 // add marker
915ddde725dSArmin Le Grand                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
916ddde725dSArmin Le Grand                     rTarget,
917ddde725dSArmin Le Grand                     new drawinglayer::primitive2d::TransformPrimitive2D(
918ddde725dSArmin Le Grand                         aCombinedTransform,
919ddde725dSArmin Le Grand                         rMarkerPrimitives));
920ddde725dSArmin Le Grand             }
921ddde725dSArmin Le Grand         }
922ddde725dSArmin Le Grand 
923ddde725dSArmin Le Grand         void SvgStyleAttributes::add_markers(
924ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
925ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
926ddde725dSArmin Le Grand         {
927ddde725dSArmin Le Grand             // try to access linked markers
928ddde725dSArmin Le Grand             const SvgMarkerNode* pStart = accessMarkerStartXLink();
929ddde725dSArmin Le Grand             const SvgMarkerNode* pMid = accessMarkerMidXLink();
930ddde725dSArmin Le Grand             const SvgMarkerNode* pEnd = accessMarkerEndXLink();
931ddde725dSArmin Le Grand 
932ddde725dSArmin Le Grand             if(pStart || pMid || pEnd)
933ddde725dSArmin Le Grand             {
934ddde725dSArmin Le Grand                 const sal_uInt32 nCount(rPath.count());
935ddde725dSArmin Le Grand 
936ddde725dSArmin Le Grand                 for (sal_uInt32 a(0); a < nCount; a++)
937ddde725dSArmin Le Grand                 {
938ddde725dSArmin Le Grand                     const basegfx::B2DPolygon aCandidate(rPath.getB2DPolygon(a));
939ddde725dSArmin Le Grand                     const sal_uInt32 nPointCount(aCandidate.count());
940ddde725dSArmin Le Grand 
941ddde725dSArmin Le Grand                     if(nPointCount)
942ddde725dSArmin Le Grand                     {
943ddde725dSArmin Le Grand                         const sal_uInt32 nMarkerCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount);
944ddde725dSArmin Le Grand                         drawinglayer::primitive2d::Primitive2DSequence aMarkerPrimitives;
945ddde725dSArmin Le Grand                         basegfx::B2DHomMatrix aMarkerTransform;
946ddde725dSArmin Le Grand                         basegfx::B2DRange aClipRange;
947ddde725dSArmin Le Grand                         const SvgMarkerNode* pPrepared = 0;
948ddde725dSArmin Le Grand 
949ddde725dSArmin Le Grand                         if(pStart)
950ddde725dSArmin Le Grand                         {
951ddde725dSArmin Le Grand                             if(prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pStart))
952ddde725dSArmin Le Grand                             {
953ddde725dSArmin Le Grand                                 pPrepared = pStart;
954ddde725dSArmin Le Grand                                 add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, 0);
955ddde725dSArmin Le Grand                             }
956ddde725dSArmin Le Grand                         }
957ddde725dSArmin Le Grand 
958ddde725dSArmin Le Grand                         if(pMid && nMarkerCount > 2)
959ddde725dSArmin Le Grand                         {
960ddde725dSArmin Le Grand                             if(pMid == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pMid))
961ddde725dSArmin Le Grand                             {
962ddde725dSArmin Le Grand                                 pPrepared = pMid;
963ddde725dSArmin Le Grand 
964e2bf1e9dSArmin Le Grand                                 for(sal_uInt32 b(1); b < nMarkerCount - 1; b++)
965ddde725dSArmin Le Grand                                 {
966e2bf1e9dSArmin Le Grand                                     add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, b);
967ddde725dSArmin Le Grand                                 }
968ddde725dSArmin Le Grand                             }
969ddde725dSArmin Le Grand                         }
970ddde725dSArmin Le Grand 
971ddde725dSArmin Le Grand                         if(pEnd)
972ddde725dSArmin Le Grand                         {
973ddde725dSArmin Le Grand                             if(pEnd == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pEnd))
974ddde725dSArmin Le Grand                             {
975ddde725dSArmin Le Grand                                 pPrepared = pEnd;
976ddde725dSArmin Le Grand                                 add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, nMarkerCount - 1);
977ddde725dSArmin Le Grand                             }
978ddde725dSArmin Le Grand                         }
979ddde725dSArmin Le Grand                     }
980ddde725dSArmin Le Grand                 }
981ddde725dSArmin Le Grand             }
982ddde725dSArmin Le Grand         }
983ddde725dSArmin Le Grand 
984ddde725dSArmin Le Grand         void SvgStyleAttributes::add_path(
985ddde725dSArmin Le Grand             const basegfx::B2DPolyPolygon& rPath,
986ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
987ddde725dSArmin Le Grand         {
988ddde725dSArmin Le Grand             const bool bIsLine(1 == rPath.count()
989ddde725dSArmin Le Grand                 && !rPath.areControlPointsUsed()
990ddde725dSArmin Le Grand                 && 2 == rPath.getB2DPolygon(0).count());
991ddde725dSArmin Le Grand 
992ddde725dSArmin Le Grand             if(!rPath.count())
993ddde725dSArmin Le Grand             {
994ddde725dSArmin Le Grand                 return;
995ddde725dSArmin Le Grand             }
996ddde725dSArmin Le Grand 
997ddde725dSArmin Le Grand             const basegfx::B2DRange aGeoRange(rPath.getB2DRange());
998ddde725dSArmin Le Grand 
999ddde725dSArmin Le Grand             if(aGeoRange.isEmpty())
1000ddde725dSArmin Le Grand             {
1001ddde725dSArmin Le Grand                 return;
1002ddde725dSArmin Le Grand             }
1003ddde725dSArmin Le Grand 
1004ddde725dSArmin Le Grand             if(!bIsLine && // not for lines
1005ddde725dSArmin Le Grand                 (basegfx::fTools::equalZero(aGeoRange.getWidth())
1006ddde725dSArmin Le Grand                 || basegfx::fTools::equalZero(aGeoRange.getHeight())))
1007ddde725dSArmin Le Grand             {
1008ddde725dSArmin Le Grand                 return;
1009ddde725dSArmin Le Grand             }
1010ddde725dSArmin Le Grand 
1011ddde725dSArmin Le Grand             const double fOpacity(getOpacity().getNumber());
1012ddde725dSArmin Le Grand 
1013ddde725dSArmin Le Grand             if(basegfx::fTools::equalZero(fOpacity))
1014ddde725dSArmin Le Grand             {
1015ddde725dSArmin Le Grand                 return;
1016ddde725dSArmin Le Grand             }
1017ddde725dSArmin Le Grand 
1018ddde725dSArmin Le Grand             if(!bIsLine)
1019ddde725dSArmin Le Grand             {
1020ddde725dSArmin Le Grand                 basegfx::B2DPolyPolygon aPath(rPath);
1021ddde725dSArmin Le Grand                 const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType());
1022ddde725dSArmin Le Grand                 const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && mbClipRule);
1023ddde725dSArmin Le Grand                 const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && getFillRule());
1024ddde725dSArmin Le Grand 
1025ddde725dSArmin Le Grand                 if(bClipPathIsNonzero || bFillRuleIsNonzero)
1026ddde725dSArmin Le Grand                 {
1027ddde725dSArmin Le Grand                     // nonzero is wanted, solve geometrically (see description on basegfx)
1028ddde725dSArmin Le Grand                     aPath = basegfx::tools::createNonzeroConform(aPath);
1029ddde725dSArmin Le Grand                 }
1030ddde725dSArmin Le Grand 
1031ddde725dSArmin Le Grand                 add_fill(aPath, rTarget, aGeoRange);
1032ddde725dSArmin Le Grand             }
1033ddde725dSArmin Le Grand 
1034ddde725dSArmin Le Grand             add_stroke(rPath, rTarget, aGeoRange);
1035ddde725dSArmin Le Grand 
1036ddde725dSArmin Le Grand             // Svg supports markers for path, polygon, polyline and line
1037ddde725dSArmin Le Grand             if(SVGTokenPath == mrOwner.getType() ||         // path
1038ddde725dSArmin Le Grand                 SVGTokenPolygon == mrOwner.getType() ||     // polygon, polyline
1039ddde725dSArmin Le Grand                 SVGTokenLine == mrOwner.getType())          // line
1040ddde725dSArmin Le Grand             {
1041ddde725dSArmin Le Grand                 // try to add markers
1042ddde725dSArmin Le Grand                 add_markers(rPath, rTarget);
1043ddde725dSArmin Le Grand             }
1044ddde725dSArmin Le Grand         }
1045ddde725dSArmin Le Grand 
1046ddde725dSArmin Le Grand         void SvgStyleAttributes::add_postProcess(
1047ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
1048ddde725dSArmin Le Grand             const drawinglayer::primitive2d::Primitive2DSequence& rSource,
1049ddde725dSArmin Le Grand             const basegfx::B2DHomMatrix* pTransform) const
1050ddde725dSArmin Le Grand         {
1051ddde725dSArmin Le Grand             if(rSource.hasElements())
1052ddde725dSArmin Le Grand             {
1053ddde725dSArmin Le Grand                 const double fOpacity(getOpacity().getNumber());
1054ddde725dSArmin Le Grand 
1055ddde725dSArmin Le Grand                 if(basegfx::fTools::equalZero(fOpacity))
1056ddde725dSArmin Le Grand                 {
1057ddde725dSArmin Le Grand                     return;
1058ddde725dSArmin Le Grand                 }
1059ddde725dSArmin Le Grand 
1060ddde725dSArmin Le Grand                 drawinglayer::primitive2d::Primitive2DSequence aSource(rSource);
1061ddde725dSArmin Le Grand 
1062ddde725dSArmin Le Grand                 if(basegfx::fTools::less(fOpacity, 1.0))
1063ddde725dSArmin Le Grand                 {
1064ddde725dSArmin Le Grand                     // embed in UnifiedTransparencePrimitive2D
1065ddde725dSArmin Le Grand                     const drawinglayer::primitive2d::Primitive2DReference xRef(
1066ddde725dSArmin Le Grand                         new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
1067ddde725dSArmin Le Grand                             aSource,
1068ddde725dSArmin Le Grand                             1.0 - fOpacity));
1069ddde725dSArmin Le Grand 
1070ddde725dSArmin Le Grand                     aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
1071ddde725dSArmin Le Grand                 }
1072ddde725dSArmin Le Grand 
1073ddde725dSArmin Le Grand                 if(getClipPathXLink().getLength())
1074ddde725dSArmin Le Grand                 {
1075ddde725dSArmin Le Grand                     // try to access linked ClipPath
1076ddde725dSArmin Le Grand                     const SvgClipPathNode* mpClip = dynamic_cast< const SvgClipPathNode* >(mrOwner.getDocument().findSvgNodeById(getClipPathXLink()));
1077ddde725dSArmin Le Grand 
1078ddde725dSArmin Le Grand                     if(mpClip)
1079ddde725dSArmin Le Grand                     {
1080ddde725dSArmin Le Grand                         mpClip->apply(aSource);
1081ddde725dSArmin Le Grand                     }
1082ddde725dSArmin Le Grand                 }
1083ddde725dSArmin Le Grand 
1084ddde725dSArmin Le Grand                 if(aSource.hasElements()) // test again, applied clipPath may have lead to empty geometry
1085ddde725dSArmin Le Grand                 {
1086ddde725dSArmin Le Grand                     if(getMaskXLink().getLength())
1087ddde725dSArmin Le Grand                     {
1088ddde725dSArmin Le Grand                         // try to access linked Mask
1089ddde725dSArmin Le Grand                         const SvgMaskNode* mpMask = dynamic_cast< const SvgMaskNode* >(mrOwner.getDocument().findSvgNodeById(getMaskXLink()));
1090ddde725dSArmin Le Grand 
1091ddde725dSArmin Le Grand                         if(mpMask)
1092ddde725dSArmin Le Grand                         {
1093ddde725dSArmin Le Grand                             mpMask->apply(aSource);
1094ddde725dSArmin Le Grand                         }
1095ddde725dSArmin Le Grand                     }
1096ddde725dSArmin Le Grand 
1097ddde725dSArmin Le Grand                     if(aSource.hasElements()) // test again, applied mask may have lead to empty geometry
1098ddde725dSArmin Le Grand                     {
1099ddde725dSArmin Le Grand                         if(pTransform)
1100ddde725dSArmin Le Grand                         {
1101ddde725dSArmin Le Grand                             // create embedding group element with transformation
1102ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xRef(
1103ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
1104ddde725dSArmin Le Grand                                     *pTransform,
1105ddde725dSArmin Le Grand                                     aSource));
1106ddde725dSArmin Le Grand 
1107ddde725dSArmin Le Grand                             aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
1108ddde725dSArmin Le Grand                         }
1109ddde725dSArmin Le Grand 
1110ddde725dSArmin Le Grand                         // append to current target
1111ddde725dSArmin Le Grand                         drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSource);
1112ddde725dSArmin Le Grand                     }
1113ddde725dSArmin Le Grand                 }
1114ddde725dSArmin Le Grand             }
1115ddde725dSArmin Le Grand         }
1116ddde725dSArmin Le Grand 
1117ddde725dSArmin Le Grand         SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner)
1118ddde725dSArmin Le Grand         :   mrOwner(rOwner),
1119ddde725dSArmin Le Grand             mpCssStyleParent(0),
1120ddde725dSArmin Le Grand             maFill(),
1121ddde725dSArmin Le Grand             maStroke(),
1122ddde725dSArmin Le Grand             maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true),
1123ddde725dSArmin Le Grand             maStrokeWidth(),
1124ddde725dSArmin Le Grand             maStopOpacity(),
1125ddde725dSArmin Le Grand             mpSvgGradientNodeFill(0),
1126ddde725dSArmin Le Grand             mpSvgGradientNodeStroke(0),
1127ddde725dSArmin Le Grand             mpSvgPatternNodeFill(0),
1128ddde725dSArmin Le Grand             mpSvgPatternNodeStroke(0),
1129ddde725dSArmin Le Grand             maFillOpacity(),
1130ddde725dSArmin Le Grand             maStrokeDasharray(),
1131ddde725dSArmin Le Grand             maStrokeDashOffset(),
1132ddde725dSArmin Le Grand             maStrokeLinecap(StrokeLinecap_notset),
1133ddde725dSArmin Le Grand             maStrokeLinejoin(StrokeLinejoin_notset),
1134ddde725dSArmin Le Grand             maStrokeMiterLimit(),
1135ddde725dSArmin Le Grand             maStrokeOpacity(),
1136ddde725dSArmin Le Grand             maFontFamily(),
1137ddde725dSArmin Le Grand             maFontSize(),
1138ddde725dSArmin Le Grand             maFontStretch(FontStretch_notset),
1139ddde725dSArmin Le Grand             maFontStyle(FontStyle_notset),
1140ddde725dSArmin Le Grand             maFontVariant(FontVariant_notset),
1141ddde725dSArmin Le Grand             maFontWeight(FontWeight_notset),
1142ddde725dSArmin Le Grand             maTextAlign(TextAlign_notset),
1143ddde725dSArmin Le Grand             maTextDecoration(TextDecoration_notset),
1144ddde725dSArmin Le Grand             maTextAnchor(TextAnchor_notset),
1145ddde725dSArmin Le Grand             maColor(),
1146ddde725dSArmin Le Grand             maOpacity(1.0),
1147ddde725dSArmin Le Grand             maClipPathXLink(),
1148ddde725dSArmin Le Grand             maMaskXLink(),
1149ddde725dSArmin Le Grand             maMarkerStartXLink(),
1150ddde725dSArmin Le Grand             mpMarkerStartXLink(0),
1151ddde725dSArmin Le Grand             maMarkerMidXLink(),
1152ddde725dSArmin Le Grand             mpMarkerMidXLink(0),
1153ddde725dSArmin Le Grand             maMarkerEndXLink(),
1154ddde725dSArmin Le Grand             mpMarkerEndXLink(0),
1155ddde725dSArmin Le Grand             maFillRule(true),
1156ddde725dSArmin Le Grand             maFillRuleSet(false),
1157ddde725dSArmin Le Grand             mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()),
1158ddde725dSArmin Le Grand             mbClipRule(true)
1159ddde725dSArmin Le Grand         {
1160ddde725dSArmin Le Grand             if(!mbIsClipPathContent)
1161ddde725dSArmin Le Grand             {
1162ddde725dSArmin Le Grand                 const SvgStyleAttributes* pParentStyle = getParentStyle();
1163ddde725dSArmin Le Grand 
1164ddde725dSArmin Le Grand                 if(pParentStyle)
1165ddde725dSArmin Le Grand                 {
1166ddde725dSArmin Le Grand                     mbIsClipPathContent = pParentStyle->mbIsClipPathContent;
1167ddde725dSArmin Le Grand                 }
1168ddde725dSArmin Le Grand             }
1169ddde725dSArmin Le Grand         }
1170ddde725dSArmin Le Grand 
1171ddde725dSArmin Le Grand         SvgStyleAttributes::~SvgStyleAttributes()
1172ddde725dSArmin Le Grand         {
1173ddde725dSArmin Le Grand         }
1174ddde725dSArmin Le Grand 
1175e2bf1e9dSArmin Le Grand         void SvgStyleAttributes::parseStyleAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
1176ddde725dSArmin Le Grand         {
1177ddde725dSArmin Le Grand             switch(aSVGToken)
1178ddde725dSArmin Le Grand             {
1179ddde725dSArmin Le Grand                 case SVGTokenFill:
1180ddde725dSArmin Le Grand                 {
1181ddde725dSArmin Le Grand                     SvgPaint aSvgPaint;
1182ddde725dSArmin Le Grand                     rtl::OUString aURL;
1183ddde725dSArmin Le Grand 
1184ddde725dSArmin Le Grand                     if(readSvgPaint(aContent, aSvgPaint, aURL))
1185ddde725dSArmin Le Grand                     {
1186ddde725dSArmin Le Grand                         setFill(aSvgPaint);
1187ddde725dSArmin Le Grand                     }
1188ddde725dSArmin Le Grand                     else if(aURL.getLength())
1189ddde725dSArmin Le Grand                     {
1190ddde725dSArmin Le Grand                         const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
1191ddde725dSArmin Le Grand 
1192ddde725dSArmin Le Grand                         if(pNode)
1193ddde725dSArmin Le Grand                         {
1194ddde725dSArmin Le Grand                             if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient  == pNode->getType())
1195ddde725dSArmin Le Grand                             {
1196ddde725dSArmin Le Grand                                 setSvgGradientNodeFill(static_cast< const SvgGradientNode* >(pNode));
1197ddde725dSArmin Le Grand                             }
1198ddde725dSArmin Le Grand                             else if(SVGTokenPattern == pNode->getType())
1199ddde725dSArmin Le Grand                             {
1200ddde725dSArmin Le Grand                                 setSvgPatternNodeFill(static_cast< const SvgPatternNode* >(pNode));
1201ddde725dSArmin Le Grand                             }
1202ddde725dSArmin Le Grand                         }
1203ddde725dSArmin Le Grand                     }
1204ddde725dSArmin Le Grand                     break;
1205ddde725dSArmin Le Grand                 }
1206ddde725dSArmin Le Grand                 case SVGTokenFillOpacity:
1207ddde725dSArmin Le Grand                 {
1208ddde725dSArmin Le Grand                     SvgNumber aNum;
1209ddde725dSArmin Le Grand 
1210ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1211ddde725dSArmin Le Grand                     {
1212ddde725dSArmin Le Grand                         if(aNum.isPositive())
1213ddde725dSArmin Le Grand                         {
1214ddde725dSArmin Le Grand                             setFillOpacity(aNum);
1215ddde725dSArmin Le Grand                         }
1216ddde725dSArmin Le Grand                     }
1217ddde725dSArmin Le Grand                     break;
1218ddde725dSArmin Le Grand                 }
1219ddde725dSArmin Le Grand                 case SVGTokenFillRule:
1220ddde725dSArmin Le Grand                 {
1221ddde725dSArmin Le Grand                     if(aContent.getLength())
1222ddde725dSArmin Le Grand                     {
1223ddde725dSArmin Le Grand                         if(aContent.match(commonStrings::aStrNonzero))
1224ddde725dSArmin Le Grand                         {
1225ddde725dSArmin Le Grand                             maFillRule = true;
1226ddde725dSArmin Le Grand                             maFillRuleSet = true;
1227ddde725dSArmin Le Grand                         }
1228ddde725dSArmin Le Grand                         else if(aContent.match(commonStrings::aStrEvenOdd))
1229ddde725dSArmin Le Grand                         {
1230ddde725dSArmin Le Grand                             maFillRule = false;
1231ddde725dSArmin Le Grand                             maFillRuleSet = true;
1232ddde725dSArmin Le Grand                         }
1233ddde725dSArmin Le Grand                     }
1234ddde725dSArmin Le Grand                     break;
1235ddde725dSArmin Le Grand                 }
1236ddde725dSArmin Le Grand                 case SVGTokenStroke:
1237ddde725dSArmin Le Grand                 {
1238ddde725dSArmin Le Grand                     SvgPaint aSvgPaint;
1239ddde725dSArmin Le Grand                     rtl::OUString aURL;
1240ddde725dSArmin Le Grand 
1241ddde725dSArmin Le Grand                     if(readSvgPaint(aContent, aSvgPaint, aURL))
1242ddde725dSArmin Le Grand                     {
1243ddde725dSArmin Le Grand                         setStroke(aSvgPaint);
1244ddde725dSArmin Le Grand                     }
1245ddde725dSArmin Le Grand                     else if(aURL.getLength())
1246ddde725dSArmin Le Grand                     {
1247ddde725dSArmin Le Grand                         const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
1248ddde725dSArmin Le Grand 
1249ddde725dSArmin Le Grand                         if(pNode)
1250ddde725dSArmin Le Grand                         {
1251ddde725dSArmin Le Grand                             if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient  == pNode->getType())
1252ddde725dSArmin Le Grand                             {
1253ddde725dSArmin Le Grand                                 setSvgGradientNodeStroke(static_cast< const SvgGradientNode* >(pNode));
1254ddde725dSArmin Le Grand                             }
1255ddde725dSArmin Le Grand                             else if(SVGTokenPattern == pNode->getType())
1256ddde725dSArmin Le Grand                             {
1257ddde725dSArmin Le Grand                                 setSvgPatternNodeStroke(static_cast< const SvgPatternNode* >(pNode));
1258ddde725dSArmin Le Grand                             }
1259ddde725dSArmin Le Grand                         }
1260ddde725dSArmin Le Grand                     }
1261ddde725dSArmin Le Grand                     break;
1262ddde725dSArmin Le Grand                 }
1263ddde725dSArmin Le Grand                 case SVGTokenStrokeDasharray:
1264ddde725dSArmin Le Grand                 {
1265ddde725dSArmin Le Grand                     if(aContent.getLength())
1266ddde725dSArmin Le Grand                     {
1267ddde725dSArmin Le Grand                         SvgNumberVector aVector;
1268ddde725dSArmin Le Grand 
1269ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
1270ddde725dSArmin Le Grand                         {
1271ddde725dSArmin Le Grand                             setStrokeDasharray(aVector);
1272ddde725dSArmin Le Grand                         }
1273ddde725dSArmin Le Grand                     }
1274ddde725dSArmin Le Grand                     break;
1275ddde725dSArmin Le Grand                 }
1276ddde725dSArmin Le Grand                 case SVGTokenStrokeDashoffset:
1277ddde725dSArmin Le Grand                 {
1278ddde725dSArmin Le Grand                     SvgNumber aNum;
1279ddde725dSArmin Le Grand 
1280ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1281ddde725dSArmin Le Grand                     {
1282ddde725dSArmin Le Grand                         if(aNum.isPositive())
1283ddde725dSArmin Le Grand                         {
1284ddde725dSArmin Le Grand                             setStrokeDashOffset(aNum);
1285ddde725dSArmin Le Grand                         }
1286ddde725dSArmin Le Grand                     }
1287ddde725dSArmin Le Grand                     break;
1288ddde725dSArmin Le Grand                 }
1289ddde725dSArmin Le Grand                 case SVGTokenStrokeLinecap:
1290ddde725dSArmin Le Grand                 {
1291ddde725dSArmin Le Grand                     if(aContent.getLength())
1292ddde725dSArmin Le Grand                     {
1293ddde725dSArmin Le Grand                         static rtl::OUString aStrButt(rtl::OUString::createFromAscii("butt"));
1294ddde725dSArmin Le Grand                         static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
1295ddde725dSArmin Le Grand                         static rtl::OUString aStrSquare(rtl::OUString::createFromAscii("square"));
1296ddde725dSArmin Le Grand 
1297ddde725dSArmin Le Grand                         if(aContent.match(aStrButt))
1298ddde725dSArmin Le Grand                         {
1299ddde725dSArmin Le Grand                             setStrokeLinecap(StrokeLinecap_butt);
1300ddde725dSArmin Le Grand                         }
1301ddde725dSArmin Le Grand                         else if(aContent.match(aStrRound))
1302ddde725dSArmin Le Grand                         {
1303ddde725dSArmin Le Grand                             setStrokeLinecap(StrokeLinecap_round);
1304ddde725dSArmin Le Grand                         }
1305ddde725dSArmin Le Grand                         else if(aContent.match(aStrSquare))
1306ddde725dSArmin Le Grand                         {
1307ddde725dSArmin Le Grand                             setStrokeLinecap(StrokeLinecap_square);
1308ddde725dSArmin Le Grand                         }
1309ddde725dSArmin Le Grand                     }
1310ddde725dSArmin Le Grand                     break;
1311ddde725dSArmin Le Grand                 }
1312ddde725dSArmin Le Grand                 case SVGTokenStrokeLinejoin:
1313ddde725dSArmin Le Grand                 {
1314ddde725dSArmin Le Grand                     if(aContent.getLength())
1315ddde725dSArmin Le Grand                     {
1316ddde725dSArmin Le Grand                         static rtl::OUString aStrMiter(rtl::OUString::createFromAscii("miter"));
1317ddde725dSArmin Le Grand                         static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
1318ddde725dSArmin Le Grand                         static rtl::OUString aStrBevel(rtl::OUString::createFromAscii("bevel"));
1319ddde725dSArmin Le Grand 
1320ddde725dSArmin Le Grand                         if(aContent.match(aStrMiter))
1321ddde725dSArmin Le Grand                         {
1322ddde725dSArmin Le Grand                             setStrokeLinejoin(StrokeLinejoin_miter);
1323ddde725dSArmin Le Grand                         }
1324ddde725dSArmin Le Grand                         else if(aContent.match(aStrRound))
1325ddde725dSArmin Le Grand                         {
1326ddde725dSArmin Le Grand                             setStrokeLinejoin(StrokeLinejoin_round);
1327ddde725dSArmin Le Grand                         }
1328ddde725dSArmin Le Grand                         else if(aContent.match(aStrBevel))
1329ddde725dSArmin Le Grand                         {
1330ddde725dSArmin Le Grand                             setStrokeLinejoin(StrokeLinejoin_bevel);
1331ddde725dSArmin Le Grand                         }
1332ddde725dSArmin Le Grand                     }
1333ddde725dSArmin Le Grand                     break;
1334ddde725dSArmin Le Grand                 }
1335ddde725dSArmin Le Grand                 case SVGTokenStrokeMiterlimit:
1336ddde725dSArmin Le Grand                 {
1337ddde725dSArmin Le Grand                     SvgNumber aNum;
1338ddde725dSArmin Le Grand 
1339ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1340ddde725dSArmin Le Grand                     {
1341ddde725dSArmin Le Grand                         if(aNum.isPositive())
1342ddde725dSArmin Le Grand                         {
1343ddde725dSArmin Le Grand                             setStrokeMiterLimit(aNum);
1344ddde725dSArmin Le Grand                         }
1345ddde725dSArmin Le Grand                     }
1346ddde725dSArmin Le Grand                     break;
1347ddde725dSArmin Le Grand                 }
1348ddde725dSArmin Le Grand                 case SVGTokenStrokeOpacity:
1349ddde725dSArmin Le Grand                 {
1350ddde725dSArmin Le Grand                     SvgNumber aNum;
1351ddde725dSArmin Le Grand 
1352ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1353ddde725dSArmin Le Grand                     {
1354ddde725dSArmin Le Grand                         if(aNum.isPositive())
1355ddde725dSArmin Le Grand                         {
1356ddde725dSArmin Le Grand                             setStrokeOpacity(aNum);
1357ddde725dSArmin Le Grand                         }
1358ddde725dSArmin Le Grand                     }
1359ddde725dSArmin Le Grand                     break;
1360ddde725dSArmin Le Grand                 }
1361ddde725dSArmin Le Grand                 case SVGTokenStrokeWidth:
1362ddde725dSArmin Le Grand                 {
1363ddde725dSArmin Le Grand                     SvgNumber aNum;
1364ddde725dSArmin Le Grand 
1365ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1366ddde725dSArmin Le Grand                     {
1367ddde725dSArmin Le Grand                         if(aNum.isPositive())
1368ddde725dSArmin Le Grand                         {
1369ddde725dSArmin Le Grand                             setStrokeWidth(aNum);
1370ddde725dSArmin Le Grand                         }
1371ddde725dSArmin Le Grand                     }
1372ddde725dSArmin Le Grand                     break;
1373ddde725dSArmin Le Grand                 }
1374ddde725dSArmin Le Grand                 case SVGTokenStopColor:
1375ddde725dSArmin Le Grand                 {
1376ddde725dSArmin Le Grand                     SvgPaint aSvgPaint;
1377ddde725dSArmin Le Grand                     rtl::OUString aURL;
1378ddde725dSArmin Le Grand 
1379ddde725dSArmin Le Grand                     if(readSvgPaint(aContent, aSvgPaint, aURL))
1380ddde725dSArmin Le Grand                     {
1381ddde725dSArmin Le Grand                         setStopColor(aSvgPaint);
1382ddde725dSArmin Le Grand                     }
1383ddde725dSArmin Le Grand                     break;
1384ddde725dSArmin Le Grand                 }
1385ddde725dSArmin Le Grand                 case SVGTokenStopOpacity:
1386ddde725dSArmin Le Grand                 {
1387ddde725dSArmin Le Grand                     SvgNumber aNum;
1388ddde725dSArmin Le Grand 
1389ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1390ddde725dSArmin Le Grand                     {
1391ddde725dSArmin Le Grand                         if(aNum.isPositive())
1392ddde725dSArmin Le Grand                         {
1393ddde725dSArmin Le Grand                             setStopOpacity(aNum);
1394ddde725dSArmin Le Grand                         }
1395ddde725dSArmin Le Grand                     }
1396ddde725dSArmin Le Grand                     break;
1397ddde725dSArmin Le Grand                 }
1398ddde725dSArmin Le Grand                 case SVGTokenFont:
1399ddde725dSArmin Le Grand                 {
1400ddde725dSArmin Le Grand                     break;
1401ddde725dSArmin Le Grand                 }
1402ddde725dSArmin Le Grand                 case SVGTokenFontFamily:
1403ddde725dSArmin Le Grand                 {
1404ddde725dSArmin Le Grand                     SvgStringVector aSvgStringVector;
1405ddde725dSArmin Le Grand 
1406ddde725dSArmin Le Grand                     if(readSvgStringVector(aContent, aSvgStringVector))
1407ddde725dSArmin Le Grand                     {
1408ddde725dSArmin Le Grand                         setFontFamily(aSvgStringVector);
1409ddde725dSArmin Le Grand                     }
1410ddde725dSArmin Le Grand                     break;
1411ddde725dSArmin Le Grand                 }
1412ddde725dSArmin Le Grand                 case SVGTokenFontSize:
1413ddde725dSArmin Le Grand                 {
1414ddde725dSArmin Le Grand                     SvgNumber aNum;
1415ddde725dSArmin Le Grand 
1416ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1417ddde725dSArmin Le Grand                     {
1418ddde725dSArmin Le Grand                         setFontSize(aNum);
1419ddde725dSArmin Le Grand                     }
1420ddde725dSArmin Le Grand                     break;
1421ddde725dSArmin Le Grand                 }
1422ddde725dSArmin Le Grand                 case SVGTokenFontSizeAdjust:
1423ddde725dSArmin Le Grand                 {
1424ddde725dSArmin Le Grand                     break;
1425ddde725dSArmin Le Grand                 }
1426ddde725dSArmin Le Grand                 case SVGTokenFontStretch:
1427ddde725dSArmin Le Grand                 {
1428ddde725dSArmin Le Grand                     if(aContent.getLength())
1429ddde725dSArmin Le Grand                     {
1430ddde725dSArmin Le Grand                         static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1431ddde725dSArmin Le Grand                         static rtl::OUString aStrWider(rtl::OUString::createFromAscii("wider"));
1432ddde725dSArmin Le Grand                         static rtl::OUString aStrNarrower(rtl::OUString::createFromAscii("narrower"));
1433ddde725dSArmin Le Grand                         static rtl::OUString aStrUltra_condensed(rtl::OUString::createFromAscii("ultra-condensed"));
1434ddde725dSArmin Le Grand                         static rtl::OUString aStrExtra_condensed(rtl::OUString::createFromAscii("extra-condensed"));
1435ddde725dSArmin Le Grand                         static rtl::OUString aStrCondensed(rtl::OUString::createFromAscii("condensed"));
1436ddde725dSArmin Le Grand                         static rtl::OUString aStrSemi_condensed(rtl::OUString::createFromAscii("semi-condensed"));
1437ddde725dSArmin Le Grand                         static rtl::OUString aStrSemi_expanded(rtl::OUString::createFromAscii("semi-expanded"));
1438ddde725dSArmin Le Grand                         static rtl::OUString aStrExpanded(rtl::OUString::createFromAscii("expanded"));
1439ddde725dSArmin Le Grand                         static rtl::OUString aStrExtra_expanded(rtl::OUString::createFromAscii("extra-expanded"));
1440ddde725dSArmin Le Grand                         static rtl::OUString aStrUltra_expanded(rtl::OUString::createFromAscii("ultra-expanded"));
1441ddde725dSArmin Le Grand 
1442ddde725dSArmin Le Grand                         if(aContent.match(aStrNormal))
1443ddde725dSArmin Le Grand                         {
1444ddde725dSArmin Le Grand                             setFontStretch(FontStretch_normal);
1445ddde725dSArmin Le Grand                         }
1446ddde725dSArmin Le Grand                         else if(aContent.match(aStrWider))
1447ddde725dSArmin Le Grand                         {
1448ddde725dSArmin Le Grand                             setFontStretch(FontStretch_wider);
1449ddde725dSArmin Le Grand                         }
1450ddde725dSArmin Le Grand                         else if(aContent.match(aStrNarrower))
1451ddde725dSArmin Le Grand                         {
1452ddde725dSArmin Le Grand                             setFontStretch(FontStretch_narrower);
1453ddde725dSArmin Le Grand                         }
1454ddde725dSArmin Le Grand                         else if(aContent.match(aStrUltra_condensed))
1455ddde725dSArmin Le Grand                         {
1456ddde725dSArmin Le Grand                             setFontStretch(FontStretch_ultra_condensed);
1457ddde725dSArmin Le Grand                         }
1458ddde725dSArmin Le Grand                         else if(aContent.match(aStrExtra_condensed))
1459ddde725dSArmin Le Grand                         {
1460ddde725dSArmin Le Grand                             setFontStretch(FontStretch_extra_condensed);
1461ddde725dSArmin Le Grand                         }
1462ddde725dSArmin Le Grand                         else if(aContent.match(aStrCondensed))
1463ddde725dSArmin Le Grand                         {
1464ddde725dSArmin Le Grand                             setFontStretch(FontStretch_condensed);
1465ddde725dSArmin Le Grand                         }
1466ddde725dSArmin Le Grand                         else if(aContent.match(aStrSemi_condensed))
1467ddde725dSArmin Le Grand                         {
1468ddde725dSArmin Le Grand                             setFontStretch(FontStretch_semi_condensed);
1469ddde725dSArmin Le Grand                         }
1470ddde725dSArmin Le Grand                         else if(aContent.match(aStrSemi_expanded))
1471ddde725dSArmin Le Grand                         {
1472ddde725dSArmin Le Grand                             setFontStretch(FontStretch_semi_expanded);
1473ddde725dSArmin Le Grand                         }
1474ddde725dSArmin Le Grand                         else if(aContent.match(aStrExpanded))
1475ddde725dSArmin Le Grand                         {
1476ddde725dSArmin Le Grand                             setFontStretch(FontStretch_expanded);
1477ddde725dSArmin Le Grand                         }
1478ddde725dSArmin Le Grand                         else if(aContent.match(aStrExtra_expanded))
1479ddde725dSArmin Le Grand                         {
1480ddde725dSArmin Le Grand                             setFontStretch(FontStretch_extra_expanded);
1481ddde725dSArmin Le Grand                         }
1482ddde725dSArmin Le Grand                         else if(aContent.match(aStrUltra_expanded))
1483ddde725dSArmin Le Grand                         {
1484ddde725dSArmin Le Grand                             setFontStretch(FontStretch_ultra_expanded);
1485ddde725dSArmin Le Grand                         }
1486ddde725dSArmin Le Grand                     }
1487ddde725dSArmin Le Grand                     break;
1488ddde725dSArmin Le Grand                 }
1489ddde725dSArmin Le Grand                 case SVGTokenFontStyle:
1490ddde725dSArmin Le Grand                 {
1491ddde725dSArmin Le Grand                     if(aContent.getLength())
1492ddde725dSArmin Le Grand                     {
1493ddde725dSArmin Le Grand                         static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1494ddde725dSArmin Le Grand                         static rtl::OUString aStrItalic(rtl::OUString::createFromAscii("italic"));
1495ddde725dSArmin Le Grand                         static rtl::OUString aStrOblique(rtl::OUString::createFromAscii("oblique"));
1496ddde725dSArmin Le Grand 
1497ddde725dSArmin Le Grand                         if(aContent.match(aStrNormal))
1498ddde725dSArmin Le Grand                         {
1499ddde725dSArmin Le Grand                             setFontStyle(FontStyle_normal);
1500ddde725dSArmin Le Grand                         }
1501ddde725dSArmin Le Grand                         else if(aContent.match(aStrItalic))
1502ddde725dSArmin Le Grand                         {
1503ddde725dSArmin Le Grand                             setFontStyle(FontStyle_italic);
1504ddde725dSArmin Le Grand                         }
1505ddde725dSArmin Le Grand                         else if(aContent.match(aStrOblique))
1506ddde725dSArmin Le Grand                         {
1507ddde725dSArmin Le Grand                             setFontStyle(FontStyle_oblique);
1508ddde725dSArmin Le Grand                         }
1509ddde725dSArmin Le Grand                     }
1510ddde725dSArmin Le Grand                     break;
1511ddde725dSArmin Le Grand                 }
1512ddde725dSArmin Le Grand                 case SVGTokenFontVariant:
1513ddde725dSArmin Le Grand                 {
1514ddde725dSArmin Le Grand                     if(aContent.getLength())
1515ddde725dSArmin Le Grand                     {
1516ddde725dSArmin Le Grand                         static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1517ddde725dSArmin Le Grand                         static rtl::OUString aStrSmallCaps(rtl::OUString::createFromAscii("small-caps"));
1518ddde725dSArmin Le Grand 
1519ddde725dSArmin Le Grand                         if(aContent.match(aStrNormal))
1520ddde725dSArmin Le Grand                         {
1521ddde725dSArmin Le Grand                             setFontVariant(FontVariant_normal);
1522ddde725dSArmin Le Grand                         }
1523ddde725dSArmin Le Grand                         else if(aContent.match(aStrSmallCaps))
1524ddde725dSArmin Le Grand                         {
1525ddde725dSArmin Le Grand                             setFontVariant(FontVariant_small_caps);
1526ddde725dSArmin Le Grand                         }
1527ddde725dSArmin Le Grand                     }
1528ddde725dSArmin Le Grand                     break;
1529ddde725dSArmin Le Grand                 }
1530ddde725dSArmin Le Grand                 case SVGTokenFontWeight:
1531ddde725dSArmin Le Grand                 {
1532ddde725dSArmin Le Grand                     if(aContent.getLength())
1533ddde725dSArmin Le Grand                     {
1534ddde725dSArmin Le Grand                         static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1535ddde725dSArmin Le Grand                         static rtl::OUString aStrBold(rtl::OUString::createFromAscii("bold"));
1536ddde725dSArmin Le Grand                         static rtl::OUString aStrBolder(rtl::OUString::createFromAscii("bolder"));
1537ddde725dSArmin Le Grand                         static rtl::OUString aStrLighter(rtl::OUString::createFromAscii("lighter"));
1538ddde725dSArmin Le Grand                         static rtl::OUString aStr100(rtl::OUString::createFromAscii("100"));
1539ddde725dSArmin Le Grand                         static rtl::OUString aStr200(rtl::OUString::createFromAscii("200"));
1540ddde725dSArmin Le Grand                         static rtl::OUString aStr300(rtl::OUString::createFromAscii("300"));
1541ddde725dSArmin Le Grand                         static rtl::OUString aStr400(rtl::OUString::createFromAscii("400"));
1542ddde725dSArmin Le Grand                         static rtl::OUString aStr500(rtl::OUString::createFromAscii("500"));
1543ddde725dSArmin Le Grand                         static rtl::OUString aStr600(rtl::OUString::createFromAscii("600"));
1544ddde725dSArmin Le Grand                         static rtl::OUString aStr700(rtl::OUString::createFromAscii("700"));
1545ddde725dSArmin Le Grand                         static rtl::OUString aStr800(rtl::OUString::createFromAscii("800"));
1546ddde725dSArmin Le Grand                         static rtl::OUString aStr900(rtl::OUString::createFromAscii("900"));
1547ddde725dSArmin Le Grand 
1548ddde725dSArmin Le Grand                         if(aContent.match(aStr100))
1549ddde725dSArmin Le Grand                         {
1550ddde725dSArmin Le Grand                             setFontWeight(FontWeight_100);
1551ddde725dSArmin Le Grand                         }
1552ddde725dSArmin Le Grand                         else if(aContent.match(aStr200))
1553ddde725dSArmin Le Grand                         {
1554ddde725dSArmin Le Grand                             setFontWeight(FontWeight_200);
1555ddde725dSArmin Le Grand                         }
1556ddde725dSArmin Le Grand                         else if(aContent.match(aStr300))
1557ddde725dSArmin Le Grand                         {
1558ddde725dSArmin Le Grand                             setFontWeight(FontWeight_300);
1559ddde725dSArmin Le Grand                         }
1560ddde725dSArmin Le Grand                         else if(aContent.match(aStr400) || aContent.match(aStrNormal))
1561ddde725dSArmin Le Grand                         {
1562ddde725dSArmin Le Grand                             setFontWeight(FontWeight_400);
1563ddde725dSArmin Le Grand                         }
1564ddde725dSArmin Le Grand                         else if(aContent.match(aStr500))
1565ddde725dSArmin Le Grand                         {
1566ddde725dSArmin Le Grand                             setFontWeight(FontWeight_500);
1567ddde725dSArmin Le Grand                         }
1568ddde725dSArmin Le Grand                         else if(aContent.match(aStr600))
1569ddde725dSArmin Le Grand                         {
1570ddde725dSArmin Le Grand                             setFontWeight(FontWeight_600);
1571ddde725dSArmin Le Grand                         }
1572ddde725dSArmin Le Grand                         else if(aContent.match(aStr700) || aContent.match(aStrBold))
1573ddde725dSArmin Le Grand                         {
1574ddde725dSArmin Le Grand                             setFontWeight(FontWeight_700);
1575ddde725dSArmin Le Grand                         }
1576ddde725dSArmin Le Grand                         else if(aContent.match(aStr800))
1577ddde725dSArmin Le Grand                         {
1578ddde725dSArmin Le Grand                             setFontWeight(FontWeight_800);
1579ddde725dSArmin Le Grand                         }
1580ddde725dSArmin Le Grand                         else if(aContent.match(aStr900))
1581ddde725dSArmin Le Grand                         {
1582ddde725dSArmin Le Grand                             setFontWeight(FontWeight_900);
1583ddde725dSArmin Le Grand                         }
1584ddde725dSArmin Le Grand                         else if(aContent.match(aStrBolder))
1585ddde725dSArmin Le Grand                         {
1586ddde725dSArmin Le Grand                             setFontWeight(FontWeight_bolder);
1587ddde725dSArmin Le Grand                         }
1588ddde725dSArmin Le Grand                         else if(aContent.match(aStrLighter))
1589ddde725dSArmin Le Grand                         {
1590ddde725dSArmin Le Grand                             setFontWeight(FontWeight_lighter);
1591ddde725dSArmin Le Grand                         }
1592ddde725dSArmin Le Grand                     }
1593ddde725dSArmin Le Grand                     break;
1594ddde725dSArmin Le Grand                 }
1595ddde725dSArmin Le Grand                 case SVGTokenDirection:
1596ddde725dSArmin Le Grand                 {
1597ddde725dSArmin Le Grand                     break;
1598ddde725dSArmin Le Grand                 }
1599ddde725dSArmin Le Grand                 case SVGTokenLetterSpacing:
1600ddde725dSArmin Le Grand                 {
1601ddde725dSArmin Le Grand                     break;
1602ddde725dSArmin Le Grand                 }
1603ddde725dSArmin Le Grand                 case SVGTokenTextDecoration:
1604ddde725dSArmin Le Grand                 {
1605ddde725dSArmin Le Grand                     if(aContent.getLength())
1606ddde725dSArmin Le Grand                     {
1607ddde725dSArmin Le Grand                         static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
1608ddde725dSArmin Le Grand                         static rtl::OUString aStrUnderline(rtl::OUString::createFromAscii("underline"));
1609ddde725dSArmin Le Grand                         static rtl::OUString aStrOverline(rtl::OUString::createFromAscii("overline"));
1610ddde725dSArmin Le Grand                         static rtl::OUString aStrLineThrough(rtl::OUString::createFromAscii("line-through"));
1611ddde725dSArmin Le Grand                         static rtl::OUString aStrBlink(rtl::OUString::createFromAscii("blink"));
1612ddde725dSArmin Le Grand 
1613ddde725dSArmin Le Grand                         if(aContent.match(aStrNone))
1614ddde725dSArmin Le Grand                         {
1615ddde725dSArmin Le Grand                             setTextDecoration(TextDecoration_none);
1616ddde725dSArmin Le Grand                         }
1617ddde725dSArmin Le Grand                         else if(aContent.match(aStrUnderline))
1618ddde725dSArmin Le Grand                         {
1619ddde725dSArmin Le Grand                             setTextDecoration(TextDecoration_underline);
1620ddde725dSArmin Le Grand                         }
1621ddde725dSArmin Le Grand                         else if(aContent.match(aStrOverline))
1622ddde725dSArmin Le Grand                         {
1623ddde725dSArmin Le Grand                             setTextDecoration(TextDecoration_overline);
1624ddde725dSArmin Le Grand                         }
1625ddde725dSArmin Le Grand                         else if(aContent.match(aStrLineThrough))
1626ddde725dSArmin Le Grand                         {
1627ddde725dSArmin Le Grand                             setTextDecoration(TextDecoration_line_through);
1628ddde725dSArmin Le Grand                         }
1629ddde725dSArmin Le Grand                         else if(aContent.match(aStrBlink))
1630ddde725dSArmin Le Grand                         {
1631ddde725dSArmin Le Grand                             setTextDecoration(TextDecoration_blink);
1632ddde725dSArmin Le Grand                         }
1633ddde725dSArmin Le Grand                     }
1634ddde725dSArmin Le Grand                     break;
1635ddde725dSArmin Le Grand                 }
1636ddde725dSArmin Le Grand                 case SVGTokenUnicodeBidi:
1637ddde725dSArmin Le Grand                 {
1638ddde725dSArmin Le Grand                     break;
1639ddde725dSArmin Le Grand                 }
1640ddde725dSArmin Le Grand                 case SVGTokenWordSpacing:
1641ddde725dSArmin Le Grand                 {
1642ddde725dSArmin Le Grand                     break;
1643ddde725dSArmin Le Grand                 }
1644ddde725dSArmin Le Grand                 case SVGTokenTextAnchor:
1645ddde725dSArmin Le Grand                 {
1646ddde725dSArmin Le Grand                     if(aContent.getLength())
1647ddde725dSArmin Le Grand                     {
1648ddde725dSArmin Le Grand                         static rtl::OUString aStrStart(rtl::OUString::createFromAscii("start"));
1649ddde725dSArmin Le Grand                         static rtl::OUString aStrMiddle(rtl::OUString::createFromAscii("middle"));
1650ddde725dSArmin Le Grand                         static rtl::OUString aStrEnd(rtl::OUString::createFromAscii("end"));
1651ddde725dSArmin Le Grand 
1652ddde725dSArmin Le Grand                         if(aContent.match(aStrStart))
1653ddde725dSArmin Le Grand                         {
1654ddde725dSArmin Le Grand                             setTextAnchor(TextAnchor_start);
1655ddde725dSArmin Le Grand                         }
1656ddde725dSArmin Le Grand                         else if(aContent.match(aStrMiddle))
1657ddde725dSArmin Le Grand                         {
1658ddde725dSArmin Le Grand                             setTextAnchor(TextAnchor_middle);
1659ddde725dSArmin Le Grand                         }
1660ddde725dSArmin Le Grand                         else if(aContent.match(aStrEnd))
1661ddde725dSArmin Le Grand                         {
1662ddde725dSArmin Le Grand                             setTextAnchor(TextAnchor_end);
1663ddde725dSArmin Le Grand                         }
1664ddde725dSArmin Le Grand                     }
1665ddde725dSArmin Le Grand                     break;
1666ddde725dSArmin Le Grand                 }
1667ddde725dSArmin Le Grand                 case SVGTokenTextAlign:
1668ddde725dSArmin Le Grand                 {
1669ddde725dSArmin Le Grand                     if(aContent.getLength())
1670ddde725dSArmin Le Grand                     {
1671ddde725dSArmin Le Grand                         static rtl::OUString aStrLeft(rtl::OUString::createFromAscii("left"));
1672ddde725dSArmin Le Grand                         static rtl::OUString aStrRight(rtl::OUString::createFromAscii("right"));
1673ddde725dSArmin Le Grand                         static rtl::OUString aStrCenter(rtl::OUString::createFromAscii("center"));
1674ddde725dSArmin Le Grand                         static rtl::OUString aStrJustify(rtl::OUString::createFromAscii("justify"));
1675ddde725dSArmin Le Grand 
1676ddde725dSArmin Le Grand                         if(aContent.match(aStrLeft))
1677ddde725dSArmin Le Grand                         {
1678ddde725dSArmin Le Grand                             setTextAlign(TextAlign_left);
1679ddde725dSArmin Le Grand                         }
1680ddde725dSArmin Le Grand                         else if(aContent.match(aStrRight))
1681ddde725dSArmin Le Grand                         {
1682ddde725dSArmin Le Grand                             setTextAlign(TextAlign_right);
1683ddde725dSArmin Le Grand                         }
1684ddde725dSArmin Le Grand                         else if(aContent.match(aStrCenter))
1685ddde725dSArmin Le Grand                         {
1686ddde725dSArmin Le Grand                             setTextAlign(TextAlign_center);
1687ddde725dSArmin Le Grand                         }
1688ddde725dSArmin Le Grand                         else if(aContent.match(aStrJustify))
1689ddde725dSArmin Le Grand                         {
1690ddde725dSArmin Le Grand                             setTextAlign(TextAlign_justify);
1691ddde725dSArmin Le Grand                         }
1692ddde725dSArmin Le Grand                     }
1693ddde725dSArmin Le Grand                     break;
1694ddde725dSArmin Le Grand                 }
1695ddde725dSArmin Le Grand                 case SVGTokenColor:
1696ddde725dSArmin Le Grand                 {
1697ddde725dSArmin Le Grand                     SvgPaint aSvgPaint;
1698ddde725dSArmin Le Grand                     rtl::OUString aURL;
1699ddde725dSArmin Le Grand 
1700ddde725dSArmin Le Grand                     if(readSvgPaint(aContent, aSvgPaint, aURL))
1701ddde725dSArmin Le Grand                     {
1702ddde725dSArmin Le Grand                         setColor(aSvgPaint);
1703ddde725dSArmin Le Grand                     }
1704ddde725dSArmin Le Grand                     break;
1705ddde725dSArmin Le Grand                 }
1706ddde725dSArmin Le Grand                 case SVGTokenOpacity:
1707ddde725dSArmin Le Grand                 {
1708ddde725dSArmin Le Grand                     SvgNumber aNum;
1709ddde725dSArmin Le Grand 
1710ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
1711ddde725dSArmin Le Grand                     {
1712ddde725dSArmin Le Grand                         setOpacity(SvgNumber(basegfx::clamp(aNum.getNumber(), 0.0, 1.0), aNum.getUnit(), aNum.isSet()));
1713ddde725dSArmin Le Grand                     }
1714ddde725dSArmin Le Grand                     break;
1715ddde725dSArmin Le Grand                 }
1716ddde725dSArmin Le Grand                 case SVGTokenClipPathProperty:
1717ddde725dSArmin Le Grand                 {
1718ddde725dSArmin Le Grand                     readLocalUrl(aContent, maClipPathXLink);
1719ddde725dSArmin Le Grand                     break;
1720ddde725dSArmin Le Grand                 }
1721ddde725dSArmin Le Grand                 case SVGTokenMask:
1722ddde725dSArmin Le Grand                 {
1723ddde725dSArmin Le Grand                     readLocalUrl(aContent, maMaskXLink);
1724ddde725dSArmin Le Grand                     break;
1725ddde725dSArmin Le Grand                 }
1726ddde725dSArmin Le Grand                 case SVGTokenClipRule:
1727ddde725dSArmin Le Grand                 {
1728ddde725dSArmin Le Grand                     if(aContent.getLength())
1729ddde725dSArmin Le Grand                     {
1730ddde725dSArmin Le Grand                         if(aContent.match(commonStrings::aStrNonzero))
1731ddde725dSArmin Le Grand                         {
1732ddde725dSArmin Le Grand                             mbClipRule = true;
1733ddde725dSArmin Le Grand                         }
1734ddde725dSArmin Le Grand                         else if(aContent.match(commonStrings::aStrEvenOdd))
1735ddde725dSArmin Le Grand                         {
1736ddde725dSArmin Le Grand                             mbClipRule = false;
1737ddde725dSArmin Le Grand                         }
1738ddde725dSArmin Le Grand                     }
1739ddde725dSArmin Le Grand                     break;
1740ddde725dSArmin Le Grand                 }
1741ddde725dSArmin Le Grand                 case SVGTokenMarker:
1742ddde725dSArmin Le Grand                 {
1743ddde725dSArmin Le Grand                     readLocalUrl(aContent, maMarkerEndXLink);
1744ddde725dSArmin Le Grand                     maMarkerStartXLink = maMarkerMidXLink = maMarkerEndXLink;
1745ddde725dSArmin Le Grand                     break;
1746ddde725dSArmin Le Grand                 }
1747ddde725dSArmin Le Grand                 case SVGTokenMarkerStart:
1748ddde725dSArmin Le Grand                 {
1749ddde725dSArmin Le Grand                     readLocalUrl(aContent, maMarkerStartXLink);
1750ddde725dSArmin Le Grand                     break;
1751ddde725dSArmin Le Grand                 }
1752ddde725dSArmin Le Grand                 case SVGTokenMarkerMid:
1753ddde725dSArmin Le Grand                 {
1754ddde725dSArmin Le Grand                     readLocalUrl(aContent, maMarkerMidXLink);
1755ddde725dSArmin Le Grand                     break;
1756ddde725dSArmin Le Grand                 }
1757ddde725dSArmin Le Grand                 case SVGTokenMarkerEnd:
1758ddde725dSArmin Le Grand                 {
1759ddde725dSArmin Le Grand                     readLocalUrl(aContent, maMarkerEndXLink);
1760ddde725dSArmin Le Grand                     break;
1761ddde725dSArmin Le Grand                 }
1762e2bf1e9dSArmin Le Grand                 default:
1763e2bf1e9dSArmin Le Grand                 {
1764e2bf1e9dSArmin Le Grand                     break;
1765e2bf1e9dSArmin Le Grand                 }
1766ddde725dSArmin Le Grand             }
1767ddde725dSArmin Le Grand         }
1768ddde725dSArmin Le Grand 
1769ddde725dSArmin Le Grand         const basegfx::BColor* SvgStyleAttributes::getFill() const
1770ddde725dSArmin Le Grand         {
1771ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1772ddde725dSArmin Le Grand             {
1773ddde725dSArmin Le Grand                 static basegfx::BColor aBlack(0.0, 0.0, 0.0);
1774ddde725dSArmin Le Grand 
1775ddde725dSArmin Le Grand                 return &aBlack;
1776ddde725dSArmin Le Grand             }
1777ddde725dSArmin Le Grand             else if(maFill.isSet())
1778ddde725dSArmin Le Grand             {
1779ddde725dSArmin Le Grand                 if(maFill.isCurrent())
1780ddde725dSArmin Le Grand                 {
1781ddde725dSArmin Le Grand                     return getColor();
1782ddde725dSArmin Le Grand                 }
1783ddde725dSArmin Le Grand                 else if(maFill.isOn())
1784ddde725dSArmin Le Grand                 {
1785ddde725dSArmin Le Grand                     return &maFill.getBColor();
1786ddde725dSArmin Le Grand                 }
1787ddde725dSArmin Le Grand             }
1788ddde725dSArmin Le Grand             else
1789ddde725dSArmin Le Grand             {
1790ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1791ddde725dSArmin Le Grand 
1792ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1793ddde725dSArmin Le Grand                 {
1794ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getFill();
1795ddde725dSArmin Le Grand                 }
1796ddde725dSArmin Le Grand             }
1797ddde725dSArmin Le Grand 
1798ddde725dSArmin Le Grand             return 0;
1799ddde725dSArmin Le Grand         }
1800ddde725dSArmin Le Grand 
1801ddde725dSArmin Le Grand         const basegfx::BColor* SvgStyleAttributes::getStroke() const
1802ddde725dSArmin Le Grand         {
1803ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1804ddde725dSArmin Le Grand             {
1805ddde725dSArmin Le Grand                 return 0;
1806ddde725dSArmin Le Grand             }
1807ddde725dSArmin Le Grand             else if(maStroke.isSet())
1808ddde725dSArmin Le Grand             {
1809ddde725dSArmin Le Grand                 if(maStroke.isCurrent())
1810ddde725dSArmin Le Grand                 {
1811ddde725dSArmin Le Grand                     return getColor();
1812ddde725dSArmin Le Grand                 }
1813ddde725dSArmin Le Grand                 else if(maStroke.isOn())
1814ddde725dSArmin Le Grand                 {
1815ddde725dSArmin Le Grand                     return &maStroke.getBColor();
1816ddde725dSArmin Le Grand                 }
1817ddde725dSArmin Le Grand             }
1818ddde725dSArmin Le Grand             else
1819ddde725dSArmin Le Grand             {
1820ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1821ddde725dSArmin Le Grand 
1822ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1823ddde725dSArmin Le Grand                 {
1824ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getStroke();
1825ddde725dSArmin Le Grand                 }
1826ddde725dSArmin Le Grand             }
1827ddde725dSArmin Le Grand 
1828ddde725dSArmin Le Grand             return 0;
1829ddde725dSArmin Le Grand         }
1830ddde725dSArmin Le Grand 
1831ddde725dSArmin Le Grand         const basegfx::BColor& SvgStyleAttributes::getStopColor() const
1832ddde725dSArmin Le Grand         {
1833ddde725dSArmin Le Grand             if(maStopColor.isCurrent())
1834ddde725dSArmin Le Grand             {
1835ddde725dSArmin Le Grand                 return *getColor();
1836ddde725dSArmin Le Grand             }
1837ddde725dSArmin Le Grand             else
1838ddde725dSArmin Le Grand             {
1839ddde725dSArmin Le Grand                 return maStopColor.getBColor();
1840ddde725dSArmin Le Grand             }
1841ddde725dSArmin Le Grand         }
1842ddde725dSArmin Le Grand 
1843ddde725dSArmin Le Grand         const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const
1844ddde725dSArmin Le Grand         {
1845ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1846ddde725dSArmin Le Grand             {
1847ddde725dSArmin Le Grand                 return 0;
1848ddde725dSArmin Le Grand             }
1849ddde725dSArmin Le Grand             else if(mpSvgGradientNodeFill)
1850ddde725dSArmin Le Grand             {
1851ddde725dSArmin Le Grand                 return mpSvgGradientNodeFill;
1852ddde725dSArmin Le Grand             }
1853ddde725dSArmin Le Grand             else
1854ddde725dSArmin Le Grand             {
1855ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1856ddde725dSArmin Le Grand 
1857ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1858ddde725dSArmin Le Grand                 {
1859ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getSvgGradientNodeFill();
1860ddde725dSArmin Le Grand                 }
1861ddde725dSArmin Le Grand             }
1862ddde725dSArmin Le Grand 
1863ddde725dSArmin Le Grand             return 0;
1864ddde725dSArmin Le Grand         }
1865ddde725dSArmin Le Grand 
1866ddde725dSArmin Le Grand         const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const
1867ddde725dSArmin Le Grand         {
1868ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1869ddde725dSArmin Le Grand             {
1870ddde725dSArmin Le Grand                 return 0;
1871ddde725dSArmin Le Grand             }
1872ddde725dSArmin Le Grand             else if(mpSvgGradientNodeStroke)
1873ddde725dSArmin Le Grand             {
1874ddde725dSArmin Le Grand                 return mpSvgGradientNodeStroke;
1875ddde725dSArmin Le Grand             }
1876ddde725dSArmin Le Grand             else
1877ddde725dSArmin Le Grand             {
1878ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1879ddde725dSArmin Le Grand 
1880ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1881ddde725dSArmin Le Grand                 {
1882ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getSvgGradientNodeStroke();
1883ddde725dSArmin Le Grand                 }
1884ddde725dSArmin Le Grand             }
1885ddde725dSArmin Le Grand 
1886ddde725dSArmin Le Grand             return 0;
1887ddde725dSArmin Le Grand         }
1888ddde725dSArmin Le Grand 
1889ddde725dSArmin Le Grand         const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeFill() const
1890ddde725dSArmin Le Grand         {
1891ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1892ddde725dSArmin Le Grand             {
1893ddde725dSArmin Le Grand                 return 0;
1894ddde725dSArmin Le Grand             }
1895ddde725dSArmin Le Grand             else if(mpSvgPatternNodeFill)
1896ddde725dSArmin Le Grand             {
1897ddde725dSArmin Le Grand                 return mpSvgPatternNodeFill;
1898ddde725dSArmin Le Grand             }
1899ddde725dSArmin Le Grand             else
1900ddde725dSArmin Le Grand             {
1901ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1902ddde725dSArmin Le Grand 
1903ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1904ddde725dSArmin Le Grand                 {
1905ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getSvgPatternNodeFill();
1906ddde725dSArmin Le Grand                 }
1907ddde725dSArmin Le Grand             }
1908ddde725dSArmin Le Grand 
1909ddde725dSArmin Le Grand             return 0;
1910ddde725dSArmin Le Grand         }
1911ddde725dSArmin Le Grand 
1912ddde725dSArmin Le Grand         const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeStroke() const
1913ddde725dSArmin Le Grand         {
1914ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1915ddde725dSArmin Le Grand             {
1916ddde725dSArmin Le Grand                 return 0;
1917ddde725dSArmin Le Grand             }
1918ddde725dSArmin Le Grand             else if(mpSvgPatternNodeStroke)
1919ddde725dSArmin Le Grand             {
1920ddde725dSArmin Le Grand                 return mpSvgPatternNodeStroke;
1921ddde725dSArmin Le Grand             }
1922ddde725dSArmin Le Grand             else
1923ddde725dSArmin Le Grand             {
1924ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1925ddde725dSArmin Le Grand 
1926ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
1927ddde725dSArmin Le Grand                 {
1928ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getSvgPatternNodeStroke();
1929ddde725dSArmin Le Grand                 }
1930ddde725dSArmin Le Grand             }
1931ddde725dSArmin Le Grand 
1932ddde725dSArmin Le Grand             return 0;
1933ddde725dSArmin Le Grand         }
1934ddde725dSArmin Le Grand 
1935ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getStrokeWidth() const
1936ddde725dSArmin Le Grand         {
1937ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1938ddde725dSArmin Le Grand             {
1939ddde725dSArmin Le Grand                 return SvgNumber(0.0);
1940ddde725dSArmin Le Grand             }
1941ddde725dSArmin Le Grand             else if(maStrokeWidth.isSet())
1942ddde725dSArmin Le Grand             {
1943ddde725dSArmin Le Grand                 return maStrokeWidth;
1944ddde725dSArmin Le Grand             }
1945ddde725dSArmin Le Grand 
1946ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1947ddde725dSArmin Le Grand 
1948ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
1949ddde725dSArmin Le Grand             {
1950ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeWidth();
1951ddde725dSArmin Le Grand             }
1952ddde725dSArmin Le Grand 
1953ddde725dSArmin Le Grand             // default is 1
1954ddde725dSArmin Le Grand             return SvgNumber(1.0);
1955ddde725dSArmin Le Grand         }
1956ddde725dSArmin Le Grand 
1957ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getStopOpacity() const
1958ddde725dSArmin Le Grand         {
1959ddde725dSArmin Le Grand             if(maStopOpacity.isSet())
1960ddde725dSArmin Le Grand             {
1961ddde725dSArmin Le Grand                 return maStopOpacity;
1962ddde725dSArmin Le Grand             }
1963ddde725dSArmin Le Grand 
1964ddde725dSArmin Le Grand             // default is 1
1965ddde725dSArmin Le Grand             return SvgNumber(1.0);
1966ddde725dSArmin Le Grand         }
1967ddde725dSArmin Le Grand 
1968ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getFillOpacity() const
1969ddde725dSArmin Le Grand         {
1970ddde725dSArmin Le Grand             if(mbIsClipPathContent)
1971ddde725dSArmin Le Grand             {
1972ddde725dSArmin Le Grand                 return SvgNumber(1.0);
1973ddde725dSArmin Le Grand             }
1974ddde725dSArmin Le Grand             else if(maFillOpacity.isSet())
1975ddde725dSArmin Le Grand             {
1976ddde725dSArmin Le Grand                 return maFillOpacity;
1977ddde725dSArmin Le Grand             }
1978ddde725dSArmin Le Grand 
1979ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1980ddde725dSArmin Le Grand 
1981ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
1982ddde725dSArmin Le Grand             {
1983ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getFillOpacity();
1984ddde725dSArmin Le Grand             }
1985ddde725dSArmin Le Grand 
1986ddde725dSArmin Le Grand             // default is 1
1987ddde725dSArmin Le Grand             return SvgNumber(1.0);
1988ddde725dSArmin Le Grand         }
1989ddde725dSArmin Le Grand 
1990ddde725dSArmin Le Grand         bool SvgStyleAttributes::getFillRule() const
1991ddde725dSArmin Le Grand         {
1992ddde725dSArmin Le Grand             if(maFillRuleSet)
1993ddde725dSArmin Le Grand             {
1994ddde725dSArmin Le Grand                 return maFillRule;
1995ddde725dSArmin Le Grand             }
1996ddde725dSArmin Le Grand 
1997ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1998ddde725dSArmin Le Grand 
1999ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2000ddde725dSArmin Le Grand             {
2001ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getFillRule();
2002ddde725dSArmin Le Grand             }
2003ddde725dSArmin Le Grand 
2004ddde725dSArmin Le Grand             // default is NonZero
2005ddde725dSArmin Le Grand             return true;
2006ddde725dSArmin Le Grand         }
2007ddde725dSArmin Le Grand 
2008ddde725dSArmin Le Grand         void SvgStyleAttributes::setFillRule(const bool* pFillRule)
2009ddde725dSArmin Le Grand         {
2010ddde725dSArmin Le Grand             if(pFillRule)
2011ddde725dSArmin Le Grand             {
2012ddde725dSArmin Le Grand                 maFillRuleSet = true;
2013ddde725dSArmin Le Grand                 maFillRule = *pFillRule;
2014ddde725dSArmin Le Grand             }
2015ddde725dSArmin Le Grand             else
2016ddde725dSArmin Le Grand             {
2017ddde725dSArmin Le Grand                 maFillRuleSet = false;
2018ddde725dSArmin Le Grand             }
2019ddde725dSArmin Le Grand         }
2020ddde725dSArmin Le Grand 
2021ddde725dSArmin Le Grand         const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
2022ddde725dSArmin Le Grand         {
2023ddde725dSArmin Le Grand             if(!maStrokeDasharray.empty())
2024ddde725dSArmin Le Grand             {
2025ddde725dSArmin Le Grand                 return maStrokeDasharray;
2026ddde725dSArmin Le Grand             }
2027ddde725dSArmin Le Grand 
2028ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2029ddde725dSArmin Le Grand 
2030ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2031ddde725dSArmin Le Grand             {
2032ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeDasharray();
2033ddde725dSArmin Le Grand             }
2034ddde725dSArmin Le Grand 
2035ddde725dSArmin Le Grand             // default empty
2036ddde725dSArmin Le Grand             return maStrokeDasharray;
2037ddde725dSArmin Le Grand         }
2038ddde725dSArmin Le Grand 
2039ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getStrokeDashOffset() const
2040ddde725dSArmin Le Grand         {
2041ddde725dSArmin Le Grand             if(maStrokeDashOffset.isSet())
2042ddde725dSArmin Le Grand             {
2043ddde725dSArmin Le Grand                 return maStrokeDashOffset;
2044ddde725dSArmin Le Grand             }
2045ddde725dSArmin Le Grand 
2046ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2047ddde725dSArmin Le Grand 
2048ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2049ddde725dSArmin Le Grand             {
2050ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeDashOffset();
2051ddde725dSArmin Le Grand             }
2052ddde725dSArmin Le Grand 
2053ddde725dSArmin Le Grand             // default is 0
2054ddde725dSArmin Le Grand             return SvgNumber(0.0);
2055ddde725dSArmin Le Grand         }
2056ddde725dSArmin Le Grand 
2057e2bf1e9dSArmin Le Grand         StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const
2058ddde725dSArmin Le Grand         {
2059ddde725dSArmin Le Grand             if(maStrokeLinecap != StrokeLinecap_notset)
2060ddde725dSArmin Le Grand             {
2061ddde725dSArmin Le Grand                 return maStrokeLinecap;
2062ddde725dSArmin Le Grand             }
2063ddde725dSArmin Le Grand 
2064ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2065ddde725dSArmin Le Grand 
2066ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2067ddde725dSArmin Le Grand             {
2068ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeLinecap();
2069ddde725dSArmin Le Grand             }
2070ddde725dSArmin Le Grand 
2071ddde725dSArmin Le Grand             // default is StrokeLinecap_butt
2072ddde725dSArmin Le Grand             return StrokeLinecap_butt;
2073ddde725dSArmin Le Grand         }
2074ddde725dSArmin Le Grand 
2075e2bf1e9dSArmin Le Grand         StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const
2076ddde725dSArmin Le Grand         {
2077ddde725dSArmin Le Grand             if(maStrokeLinejoin != StrokeLinejoin_notset)
2078ddde725dSArmin Le Grand             {
2079ddde725dSArmin Le Grand                 return maStrokeLinejoin;
2080ddde725dSArmin Le Grand             }
2081ddde725dSArmin Le Grand 
2082ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2083ddde725dSArmin Le Grand 
2084ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2085ddde725dSArmin Le Grand             {
2086ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeLinejoin();
2087ddde725dSArmin Le Grand             }
2088ddde725dSArmin Le Grand 
2089ddde725dSArmin Le Grand             // default is StrokeLinejoin_butt
2090ddde725dSArmin Le Grand             return StrokeLinejoin_miter;
2091ddde725dSArmin Le Grand         }
2092ddde725dSArmin Le Grand 
2093ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const
2094ddde725dSArmin Le Grand         {
2095ddde725dSArmin Le Grand             if(maStrokeMiterLimit.isSet())
2096ddde725dSArmin Le Grand             {
2097ddde725dSArmin Le Grand                 return maStrokeMiterLimit;
2098ddde725dSArmin Le Grand             }
2099ddde725dSArmin Le Grand 
2100ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2101ddde725dSArmin Le Grand 
2102ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2103ddde725dSArmin Le Grand             {
2104ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeMiterLimit();
2105ddde725dSArmin Le Grand             }
2106ddde725dSArmin Le Grand 
2107ddde725dSArmin Le Grand             // default is 4
2108ddde725dSArmin Le Grand             return SvgNumber(4.0);
2109ddde725dSArmin Le Grand         }
2110ddde725dSArmin Le Grand 
2111ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getStrokeOpacity() const
2112ddde725dSArmin Le Grand         {
2113ddde725dSArmin Le Grand             if(maStrokeOpacity.isSet())
2114ddde725dSArmin Le Grand             {
2115ddde725dSArmin Le Grand                 return maStrokeOpacity;
2116ddde725dSArmin Le Grand             }
2117ddde725dSArmin Le Grand 
2118ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2119ddde725dSArmin Le Grand 
2120ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2121ddde725dSArmin Le Grand             {
2122ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getStrokeOpacity();
2123ddde725dSArmin Le Grand             }
2124ddde725dSArmin Le Grand 
2125ddde725dSArmin Le Grand             // default is 1
2126ddde725dSArmin Le Grand             return SvgNumber(1.0);
2127ddde725dSArmin Le Grand         }
2128ddde725dSArmin Le Grand 
2129ddde725dSArmin Le Grand         const SvgStringVector& SvgStyleAttributes::getFontFamily() const
2130ddde725dSArmin Le Grand         {
2131ddde725dSArmin Le Grand             if(!maFontFamily.empty())
2132ddde725dSArmin Le Grand             {
2133ddde725dSArmin Le Grand                 return maFontFamily;
2134ddde725dSArmin Le Grand             }
2135ddde725dSArmin Le Grand 
2136ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2137ddde725dSArmin Le Grand 
2138ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2139ddde725dSArmin Le Grand             {
2140ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getFontFamily();
2141ddde725dSArmin Le Grand             }
2142ddde725dSArmin Le Grand 
2143ddde725dSArmin Le Grand             // default is empty
2144ddde725dSArmin Le Grand             return maFontFamily;
2145ddde725dSArmin Le Grand         }
2146ddde725dSArmin Le Grand 
2147ddde725dSArmin Le Grand         const SvgNumber SvgStyleAttributes::getFontSize() const
2148ddde725dSArmin Le Grand         {
2149ddde725dSArmin Le Grand             if(maFontSize.isSet())
2150ddde725dSArmin Le Grand             {
2151ddde725dSArmin Le Grand                 return maFontSize;
2152ddde725dSArmin Le Grand             }
2153ddde725dSArmin Le Grand 
2154ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2155ddde725dSArmin Le Grand 
2156ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2157ddde725dSArmin Le Grand             {
2158ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getFontSize();
2159ddde725dSArmin Le Grand             }
2160ddde725dSArmin Le Grand 
2161ddde725dSArmin Le Grand             // default is 'medium'
2162ddde725dSArmin Le Grand             return SvgNumber(12.0);
2163ddde725dSArmin Le Grand         }
2164ddde725dSArmin Le Grand 
2165e2bf1e9dSArmin Le Grand         FontStretch SvgStyleAttributes::getFontStretch() const
2166ddde725dSArmin Le Grand         {
2167ddde725dSArmin Le Grand             if(maFontStretch != FontStretch_notset)
2168ddde725dSArmin Le Grand             {
2169ddde725dSArmin Le Grand                 if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch)
2170ddde725dSArmin Le Grand                 {
2171ddde725dSArmin Le Grand                     return maFontStretch;
2172ddde725dSArmin Le Grand                 }
2173ddde725dSArmin Le Grand             }
2174ddde725dSArmin Le Grand 
2175ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2176ddde725dSArmin Le Grand 
2177ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2178ddde725dSArmin Le Grand             {
2179ddde725dSArmin Le Grand                 FontStretch aInherited = pSvgStyleAttributes->getFontStretch();
2180ddde725dSArmin Le Grand 
2181ddde725dSArmin Le Grand                 if(FontStretch_wider == maFontStretch)
2182ddde725dSArmin Le Grand                 {
2183ddde725dSArmin Le Grand                     aInherited = getWider(aInherited);
2184ddde725dSArmin Le Grand                 }
2185ddde725dSArmin Le Grand                 else if(FontStretch_narrower == maFontStretch)
2186ddde725dSArmin Le Grand                 {
2187ddde725dSArmin Le Grand                     aInherited = getNarrower(aInherited);
2188ddde725dSArmin Le Grand                 }
2189ddde725dSArmin Le Grand 
2190ddde725dSArmin Le Grand                 return aInherited;
2191ddde725dSArmin Le Grand             }
2192ddde725dSArmin Le Grand 
2193ddde725dSArmin Le Grand             // default is FontStretch_normal
2194ddde725dSArmin Le Grand             return FontStretch_normal;
2195ddde725dSArmin Le Grand         }
2196ddde725dSArmin Le Grand 
2197e2bf1e9dSArmin Le Grand         FontStyle SvgStyleAttributes::getFontStyle() const
2198ddde725dSArmin Le Grand         {
2199ddde725dSArmin Le Grand             if(maFontStyle != FontStyle_notset)
2200ddde725dSArmin Le Grand             {
2201ddde725dSArmin Le Grand                 return maFontStyle;
2202ddde725dSArmin Le Grand             }
2203ddde725dSArmin Le Grand 
2204ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2205ddde725dSArmin Le Grand 
2206ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2207ddde725dSArmin Le Grand             {
2208ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getFontStyle();
2209ddde725dSArmin Le Grand             }
2210ddde725dSArmin Le Grand 
2211ddde725dSArmin Le Grand             // default is FontStyle_normal
2212ddde725dSArmin Le Grand             return FontStyle_normal;
2213ddde725dSArmin Le Grand         }
2214ddde725dSArmin Le Grand 
2215e2bf1e9dSArmin Le Grand         FontWeight SvgStyleAttributes::getFontWeight() const
2216ddde725dSArmin Le Grand         {
2217ddde725dSArmin Le Grand             if(maFontWeight != FontWeight_notset)
2218ddde725dSArmin Le Grand             {
2219ddde725dSArmin Le Grand                 if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight)
2220ddde725dSArmin Le Grand                 {
2221ddde725dSArmin Le Grand                     return maFontWeight;
2222ddde725dSArmin Le Grand                 }
2223ddde725dSArmin Le Grand             }
2224ddde725dSArmin Le Grand 
2225ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2226ddde725dSArmin Le Grand 
2227ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2228ddde725dSArmin Le Grand             {
2229ddde725dSArmin Le Grand                 FontWeight aInherited = pSvgStyleAttributes->getFontWeight();
2230ddde725dSArmin Le Grand 
2231ddde725dSArmin Le Grand                 if(FontWeight_bolder == maFontWeight)
2232ddde725dSArmin Le Grand                 {
2233ddde725dSArmin Le Grand                     aInherited = getBolder(aInherited);
2234ddde725dSArmin Le Grand                 }
2235ddde725dSArmin Le Grand                 else if(FontWeight_lighter == maFontWeight)
2236ddde725dSArmin Le Grand                 {
2237ddde725dSArmin Le Grand                     aInherited = getLighter(aInherited);
2238ddde725dSArmin Le Grand                 }
2239ddde725dSArmin Le Grand 
2240ddde725dSArmin Le Grand                 return aInherited;
2241ddde725dSArmin Le Grand             }
2242ddde725dSArmin Le Grand 
2243ddde725dSArmin Le Grand             // default is FontWeight_400 (FontWeight_normal)
2244ddde725dSArmin Le Grand             return FontWeight_400;
2245ddde725dSArmin Le Grand         }
2246ddde725dSArmin Le Grand 
2247e2bf1e9dSArmin Le Grand         TextAlign SvgStyleAttributes::getTextAlign() const
2248ddde725dSArmin Le Grand         {
2249ddde725dSArmin Le Grand             if(maTextAlign != TextAlign_notset)
2250ddde725dSArmin Le Grand             {
2251ddde725dSArmin Le Grand                 return maTextAlign;
2252ddde725dSArmin Le Grand             }
2253ddde725dSArmin Le Grand 
2254ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2255ddde725dSArmin Le Grand 
2256ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2257ddde725dSArmin Le Grand             {
2258ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getTextAlign();
2259ddde725dSArmin Le Grand             }
2260ddde725dSArmin Le Grand 
2261ddde725dSArmin Le Grand             // default is TextAlign_left
2262ddde725dSArmin Le Grand             return TextAlign_left;
2263ddde725dSArmin Le Grand         }
2264ddde725dSArmin Le Grand 
2265ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const
2266ddde725dSArmin Le Grand         {
2267ddde725dSArmin Le Grand             if(maTextDecoration != TextDecoration_notset)
2268ddde725dSArmin Le Grand             {
2269ddde725dSArmin Le Grand                 return this;
2270ddde725dSArmin Le Grand             }
2271ddde725dSArmin Le Grand 
2272ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2273ddde725dSArmin Le Grand 
2274ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2275ddde725dSArmin Le Grand             {
2276ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes();
2277ddde725dSArmin Le Grand             }
2278ddde725dSArmin Le Grand 
2279ddde725dSArmin Le Grand             // default is 0
2280ddde725dSArmin Le Grand             return 0;
2281ddde725dSArmin Le Grand         }
2282ddde725dSArmin Le Grand 
2283e2bf1e9dSArmin Le Grand         TextDecoration SvgStyleAttributes::getTextDecoration() const
2284ddde725dSArmin Le Grand         {
2285ddde725dSArmin Le Grand             const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes();
2286ddde725dSArmin Le Grand 
2287ddde725dSArmin Le Grand             if(pDefining)
2288ddde725dSArmin Le Grand             {
2289ddde725dSArmin Le Grand                 return pDefining->maTextDecoration;
2290ddde725dSArmin Le Grand             }
2291ddde725dSArmin Le Grand             else
2292ddde725dSArmin Le Grand             {
2293ddde725dSArmin Le Grand                 // default is TextDecoration_none
2294ddde725dSArmin Le Grand                 return TextDecoration_none;
2295ddde725dSArmin Le Grand             }
2296ddde725dSArmin Le Grand         }
2297ddde725dSArmin Le Grand 
2298e2bf1e9dSArmin Le Grand         TextAnchor SvgStyleAttributes::getTextAnchor() const
2299ddde725dSArmin Le Grand         {
2300ddde725dSArmin Le Grand             if(maTextAnchor != TextAnchor_notset)
2301ddde725dSArmin Le Grand             {
2302ddde725dSArmin Le Grand                 return maTextAnchor;
2303ddde725dSArmin Le Grand             }
2304ddde725dSArmin Le Grand 
2305ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2306ddde725dSArmin Le Grand 
2307ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2308ddde725dSArmin Le Grand             {
2309ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getTextAnchor();
2310ddde725dSArmin Le Grand             }
2311ddde725dSArmin Le Grand 
2312ddde725dSArmin Le Grand             // default is TextAnchor_start
2313ddde725dSArmin Le Grand             return TextAnchor_start;
2314ddde725dSArmin Le Grand         }
2315ddde725dSArmin Le Grand 
2316ddde725dSArmin Le Grand         const basegfx::BColor* SvgStyleAttributes::getColor() const
2317ddde725dSArmin Le Grand         {
2318ddde725dSArmin Le Grand             if(maColor.isSet())
2319ddde725dSArmin Le Grand             {
2320ddde725dSArmin Le Grand                 if(maColor.isCurrent())
2321ddde725dSArmin Le Grand                 {
2322ddde725dSArmin Le Grand                     OSL_ENSURE(false, "Svg error: current color uses current color (!)");
2323ddde725dSArmin Le Grand                     return 0;
2324ddde725dSArmin Le Grand                 }
2325ddde725dSArmin Le Grand                 else if(maColor.isOn())
2326ddde725dSArmin Le Grand                 {
2327ddde725dSArmin Le Grand                     return &maColor.getBColor();
2328ddde725dSArmin Le Grand                 }
2329ddde725dSArmin Le Grand             }
2330ddde725dSArmin Le Grand             else
2331ddde725dSArmin Le Grand             {
2332ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2333ddde725dSArmin Le Grand 
2334ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
2335ddde725dSArmin Le Grand                 {
2336ddde725dSArmin Le Grand                     return pSvgStyleAttributes->getColor();
2337ddde725dSArmin Le Grand                 }
2338ddde725dSArmin Le Grand             }
2339ddde725dSArmin Le Grand 
2340ddde725dSArmin Le Grand             return 0;
2341ddde725dSArmin Le Grand         }
2342ddde725dSArmin Le Grand 
2343ddde725dSArmin Le Grand         const rtl::OUString SvgStyleAttributes::getMarkerStartXLink() const
2344ddde725dSArmin Le Grand         {
2345ddde725dSArmin Le Grand             if(maMarkerStartXLink.getLength())
2346ddde725dSArmin Le Grand             {
2347ddde725dSArmin Le Grand                 return maMarkerStartXLink;
2348ddde725dSArmin Le Grand             }
2349ddde725dSArmin Le Grand 
2350ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2351ddde725dSArmin Le Grand 
2352ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2353ddde725dSArmin Le Grand             {
2354ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getMarkerStartXLink();
2355ddde725dSArmin Le Grand             }
2356ddde725dSArmin Le Grand 
2357ddde725dSArmin Le Grand             return rtl::OUString();
2358ddde725dSArmin Le Grand         }
2359ddde725dSArmin Le Grand 
2360ddde725dSArmin Le Grand         const SvgMarkerNode* SvgStyleAttributes::accessMarkerStartXLink() const
2361ddde725dSArmin Le Grand         {
2362ddde725dSArmin Le Grand             if(!mpMarkerStartXLink)
2363ddde725dSArmin Le Grand             {
2364ddde725dSArmin Le Grand                 const rtl::OUString aMarker(getMarkerStartXLink());
2365ddde725dSArmin Le Grand 
2366ddde725dSArmin Le Grand                 if(aMarker.getLength())
2367ddde725dSArmin Le Grand                 {
2368ddde725dSArmin Le Grand                     const_cast< SvgStyleAttributes* >(this)->mpMarkerStartXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerStartXLink()));
2369ddde725dSArmin Le Grand                 }
2370ddde725dSArmin Le Grand             }
2371ddde725dSArmin Le Grand 
2372ddde725dSArmin Le Grand             return mpMarkerStartXLink;
2373ddde725dSArmin Le Grand         }
2374ddde725dSArmin Le Grand 
2375ddde725dSArmin Le Grand         const rtl::OUString SvgStyleAttributes::getMarkerMidXLink() const
2376ddde725dSArmin Le Grand         {
2377ddde725dSArmin Le Grand             if(maMarkerMidXLink.getLength())
2378ddde725dSArmin Le Grand             {
2379ddde725dSArmin Le Grand                 return maMarkerMidXLink;
2380ddde725dSArmin Le Grand             }
2381ddde725dSArmin Le Grand 
2382ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2383ddde725dSArmin Le Grand 
2384ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2385ddde725dSArmin Le Grand             {
2386ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getMarkerMidXLink();
2387ddde725dSArmin Le Grand             }
2388ddde725dSArmin Le Grand 
2389ddde725dSArmin Le Grand             return rtl::OUString();
2390ddde725dSArmin Le Grand         }
2391ddde725dSArmin Le Grand 
2392ddde725dSArmin Le Grand         const SvgMarkerNode* SvgStyleAttributes::accessMarkerMidXLink() const
2393ddde725dSArmin Le Grand         {
2394ddde725dSArmin Le Grand             if(!mpMarkerMidXLink)
2395ddde725dSArmin Le Grand             {
2396ddde725dSArmin Le Grand                 const rtl::OUString aMarker(getMarkerMidXLink());
2397ddde725dSArmin Le Grand 
2398ddde725dSArmin Le Grand                 if(aMarker.getLength())
2399ddde725dSArmin Le Grand                 {
2400ddde725dSArmin Le Grand                     const_cast< SvgStyleAttributes* >(this)->mpMarkerMidXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerMidXLink()));
2401ddde725dSArmin Le Grand                 }
2402ddde725dSArmin Le Grand             }
2403ddde725dSArmin Le Grand 
2404ddde725dSArmin Le Grand             return mpMarkerMidXLink;
2405ddde725dSArmin Le Grand         }
2406ddde725dSArmin Le Grand 
2407ddde725dSArmin Le Grand         const rtl::OUString SvgStyleAttributes::getMarkerEndXLink() const
2408ddde725dSArmin Le Grand         {
2409ddde725dSArmin Le Grand             if(maMarkerEndXLink.getLength())
2410ddde725dSArmin Le Grand             {
2411ddde725dSArmin Le Grand                 return maMarkerEndXLink;
2412ddde725dSArmin Le Grand             }
2413ddde725dSArmin Le Grand 
2414ddde725dSArmin Le Grand             const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2415ddde725dSArmin Le Grand 
2416ddde725dSArmin Le Grand             if(pSvgStyleAttributes)
2417ddde725dSArmin Le Grand             {
2418ddde725dSArmin Le Grand                 return pSvgStyleAttributes->getMarkerEndXLink();
2419ddde725dSArmin Le Grand             }
2420ddde725dSArmin Le Grand 
2421ddde725dSArmin Le Grand             return rtl::OUString();
2422ddde725dSArmin Le Grand         }
2423ddde725dSArmin Le Grand 
2424ddde725dSArmin Le Grand         const SvgMarkerNode* SvgStyleAttributes::accessMarkerEndXLink() const
2425ddde725dSArmin Le Grand         {
2426ddde725dSArmin Le Grand             if(!mpMarkerEndXLink)
2427ddde725dSArmin Le Grand             {
2428ddde725dSArmin Le Grand                 const rtl::OUString aMarker(getMarkerEndXLink());
2429ddde725dSArmin Le Grand 
2430ddde725dSArmin Le Grand                 if(aMarker.getLength())
2431ddde725dSArmin Le Grand                 {
2432ddde725dSArmin Le Grand                     const_cast< SvgStyleAttributes* >(this)->mpMarkerEndXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerEndXLink()));
2433ddde725dSArmin Le Grand                 }
2434ddde725dSArmin Le Grand             }
2435ddde725dSArmin Le Grand 
2436ddde725dSArmin Le Grand             return mpMarkerEndXLink;
2437ddde725dSArmin Le Grand         }
2438ddde725dSArmin Le Grand 
2439ddde725dSArmin Le Grand     } // end of namespace svgreader
2440ddde725dSArmin Le Grand } // end of namespace svgio
2441ddde725dSArmin Le Grand 
2442ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
2443ddde725dSArmin Le Grand // eof
2444