xref: /AOO41X/main/svgio/source/svgreader/svgcharacternode.cxx (revision 693be7f615b07ee08c4eb2232b246abfb35b35b4)
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/svgcharacternode.hxx>
26ddde725dSArmin Le Grand #include <svgio/svgreader/svgstyleattributes.hxx>
27ddde725dSArmin Le Grand #include <drawinglayer/attribute/fontattribute.hxx>
28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textprimitive2d.hxx>
29ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
30ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textbreakuphelper.hxx>
31ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
32ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
33ddde725dSArmin Le Grand 
34ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
35ddde725dSArmin Le Grand 
36ddde725dSArmin Le Grand namespace svgio
37ddde725dSArmin Le Grand {
38ddde725dSArmin Le Grand     namespace svgreader
39ddde725dSArmin Le Grand     {
40ddde725dSArmin Le Grand         SvgTextPositions::SvgTextPositions()
41ddde725dSArmin Le Grand         :   maX(),
42ddde725dSArmin Le Grand             maY(),
43ddde725dSArmin Le Grand             maDx(),
44ddde725dSArmin Le Grand             maDy(),
45ddde725dSArmin Le Grand             maRotate(),
46ddde725dSArmin Le Grand             maTextLength(),
47ddde725dSArmin Le Grand             mbLengthAdjust(true)
48ddde725dSArmin Le Grand         {
49ddde725dSArmin Le Grand         }
50ddde725dSArmin Le Grand 
51e2bf1e9dSArmin Le Grand         void SvgTextPositions::parseTextPositionAttributes(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
52ddde725dSArmin Le Grand         {
53ddde725dSArmin Le Grand             // parse own
54ddde725dSArmin Le Grand             switch(aSVGToken)
55ddde725dSArmin Le Grand             {
56ddde725dSArmin Le Grand                 case SVGTokenX:
57ddde725dSArmin Le Grand                 {
58ddde725dSArmin Le Grand                     if(aContent.getLength())
59ddde725dSArmin Le Grand                     {
60ddde725dSArmin Le Grand                         SvgNumberVector aVector;
61ddde725dSArmin Le Grand 
62ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
63ddde725dSArmin Le Grand                         {
64ddde725dSArmin Le Grand                             setX(aVector);
65ddde725dSArmin Le Grand                         }
66ddde725dSArmin Le Grand                     }
67ddde725dSArmin Le Grand                     break;
68ddde725dSArmin Le Grand                 }
69ddde725dSArmin Le Grand                 case SVGTokenY:
70ddde725dSArmin Le Grand                 {
71ddde725dSArmin Le Grand                     if(aContent.getLength())
72ddde725dSArmin Le Grand                     {
73ddde725dSArmin Le Grand                         SvgNumberVector aVector;
74ddde725dSArmin Le Grand 
75ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
76ddde725dSArmin Le Grand                         {
77ddde725dSArmin Le Grand                             setY(aVector);
78ddde725dSArmin Le Grand                         }
79ddde725dSArmin Le Grand                     }
80ddde725dSArmin Le Grand                     break;
81ddde725dSArmin Le Grand                 }
82ddde725dSArmin Le Grand                 case SVGTokenDx:
83ddde725dSArmin Le Grand                 {
84ddde725dSArmin Le Grand                     if(aContent.getLength())
85ddde725dSArmin Le Grand                     {
86ddde725dSArmin Le Grand                         SvgNumberVector aVector;
87ddde725dSArmin Le Grand 
88ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
89ddde725dSArmin Le Grand                         {
90ddde725dSArmin Le Grand                             setDx(aVector);
91ddde725dSArmin Le Grand                         }
92ddde725dSArmin Le Grand                     }
93ddde725dSArmin Le Grand                     break;
94ddde725dSArmin Le Grand                 }
95ddde725dSArmin Le Grand                 case SVGTokenDy:
96ddde725dSArmin Le Grand                 {
97ddde725dSArmin Le Grand                     if(aContent.getLength())
98ddde725dSArmin Le Grand                     {
99ddde725dSArmin Le Grand                         SvgNumberVector aVector;
100ddde725dSArmin Le Grand 
101ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
102ddde725dSArmin Le Grand                         {
103ddde725dSArmin Le Grand                             setDy(aVector);
104ddde725dSArmin Le Grand                         }
105ddde725dSArmin Le Grand                     }
106ddde725dSArmin Le Grand                     break;
107ddde725dSArmin Le Grand                 }
108ddde725dSArmin Le Grand                 case SVGTokenRotate:
109ddde725dSArmin Le Grand                 {
110ddde725dSArmin Le Grand                     if(aContent.getLength())
111ddde725dSArmin Le Grand                     {
112ddde725dSArmin Le Grand                         SvgNumberVector aVector;
113ddde725dSArmin Le Grand 
114ddde725dSArmin Le Grand                         if(readSvgNumberVector(aContent, aVector))
115ddde725dSArmin Le Grand                         {
116ddde725dSArmin Le Grand                             setRotate(aVector);
117ddde725dSArmin Le Grand                         }
118ddde725dSArmin Le Grand                     }
119ddde725dSArmin Le Grand                     break;
120ddde725dSArmin Le Grand                 }
121ddde725dSArmin Le Grand                 case SVGTokenTextLength:
122ddde725dSArmin Le Grand                 {
123ddde725dSArmin Le Grand                     SvgNumber aNum;
124ddde725dSArmin Le Grand 
125ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
126ddde725dSArmin Le Grand                     {
127ddde725dSArmin Le Grand                         if(aNum.isPositive())
128ddde725dSArmin Le Grand                         {
129ddde725dSArmin Le Grand                             setTextLength(aNum);
130ddde725dSArmin Le Grand                         }
131ddde725dSArmin Le Grand                     }
132ddde725dSArmin Le Grand                     break;
133ddde725dSArmin Le Grand                 }
134ddde725dSArmin Le Grand                 case SVGTokenLengthAdjust:
135ddde725dSArmin Le Grand                 {
136ddde725dSArmin Le Grand                     if(aContent.getLength())
137ddde725dSArmin Le Grand                     {
138ddde725dSArmin Le Grand                         static rtl::OUString aStrSpacing(rtl::OUString::createFromAscii("spacing"));
139ddde725dSArmin Le Grand                         static rtl::OUString aStrSpacingAndGlyphs(rtl::OUString::createFromAscii("spacingAndGlyphs"));
140ddde725dSArmin Le Grand 
141ddde725dSArmin Le Grand                         if(aContent.match(aStrSpacing))
142ddde725dSArmin Le Grand                         {
143ddde725dSArmin Le Grand                             setLengthAdjust(true);
144ddde725dSArmin Le Grand                         }
145ddde725dSArmin Le Grand                         else if(aContent.match(aStrSpacingAndGlyphs))
146ddde725dSArmin Le Grand                         {
147ddde725dSArmin Le Grand                             setLengthAdjust(false);
148ddde725dSArmin Le Grand                         }
149ddde725dSArmin Le Grand                     }
150ddde725dSArmin Le Grand                     break;
151ddde725dSArmin Le Grand                 }
152e2bf1e9dSArmin Le Grand                 default:
153e2bf1e9dSArmin Le Grand                 {
154e2bf1e9dSArmin Le Grand                     break;
155e2bf1e9dSArmin Le Grand                 }
156ddde725dSArmin Le Grand             }
157ddde725dSArmin Le Grand         }
158ddde725dSArmin Le Grand 
159ddde725dSArmin Le Grand     } // end of namespace svgreader
160ddde725dSArmin Le Grand } // end of namespace svgio
161ddde725dSArmin Le Grand 
162ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
163ddde725dSArmin Le Grand 
164ddde725dSArmin Le Grand namespace svgio
165ddde725dSArmin Le Grand {
166ddde725dSArmin Le Grand     namespace svgreader
167ddde725dSArmin Le Grand     {
168ddde725dSArmin Le Grand         class localTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper
169ddde725dSArmin Le Grand         {
170ddde725dSArmin Le Grand         private:
171ddde725dSArmin Le Grand             SvgTextPosition&                    mrSvgTextPosition;
172ddde725dSArmin Le Grand 
173ddde725dSArmin Le Grand         protected:
174ddde725dSArmin Le Grand             /// allow user callback to allow changes to the new TextTransformation. Default
175ddde725dSArmin Le Grand             /// does nothing.
176ddde725dSArmin Le Grand             virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength);
177ddde725dSArmin Le Grand 
178ddde725dSArmin Le Grand         public:
179ddde725dSArmin Le Grand             localTextBreakupHelper(
180*693be7f6SArmin Le Grand                 const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource,
181ddde725dSArmin Le Grand                 SvgTextPosition& rSvgTextPosition)
182*693be7f6SArmin Le Grand             :   drawinglayer::primitive2d::TextBreakupHelper(rSource),
183ddde725dSArmin Le Grand                 mrSvgTextPosition(rSvgTextPosition)
184ddde725dSArmin Le Grand             {
185ddde725dSArmin Le Grand             }
186ddde725dSArmin Le Grand         };
187ddde725dSArmin Le Grand 
188e2bf1e9dSArmin Le Grand         bool localTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
189ddde725dSArmin Le Grand         {
190ddde725dSArmin Le Grand             const double fRotation(mrSvgTextPosition.consumeRotation());
191ddde725dSArmin Le Grand 
192ddde725dSArmin Le Grand             if(0.0 != fRotation)
193ddde725dSArmin Le Grand             {
194ddde725dSArmin Le Grand                 const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0));
195ddde725dSArmin Le Grand 
196ddde725dSArmin Le Grand                 rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY());
197ddde725dSArmin Le Grand                 rNewTransform.rotate(fRotation);
198ddde725dSArmin Le Grand                 rNewTransform.translate(aBasePoint.getX(), aBasePoint.getY());
199ddde725dSArmin Le Grand             }
200ddde725dSArmin Le Grand 
201ddde725dSArmin Le Grand             return true;
202ddde725dSArmin Le Grand         }
203ddde725dSArmin Le Grand 
204ddde725dSArmin Le Grand     } // end of namespace svgreader
205ddde725dSArmin Le Grand } // end of namespace svgio
206ddde725dSArmin Le Grand 
207ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
208ddde725dSArmin Le Grand 
209ddde725dSArmin Le Grand namespace svgio
210ddde725dSArmin Le Grand {
211ddde725dSArmin Le Grand     namespace svgreader
212ddde725dSArmin Le Grand     {
213ddde725dSArmin Le Grand         SvgCharacterNode::SvgCharacterNode(
214ddde725dSArmin Le Grand             SvgDocument& rDocument,
215ddde725dSArmin Le Grand             SvgNode* pParent,
216ddde725dSArmin Le Grand             const rtl::OUString& rText)
217ddde725dSArmin Le Grand         :   SvgNode(SVGTokenCharacter, rDocument, pParent),
218ddde725dSArmin Le Grand             maText(rText)
219ddde725dSArmin Le Grand         {
220ddde725dSArmin Le Grand         }
221ddde725dSArmin Le Grand 
222ddde725dSArmin Le Grand         SvgCharacterNode::~SvgCharacterNode()
223ddde725dSArmin Le Grand         {
224ddde725dSArmin Le Grand         }
225ddde725dSArmin Le Grand 
226ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgCharacterNode::getSvgStyleAttributes() const
227ddde725dSArmin Le Grand         {
228ddde725dSArmin Le Grand             // no own style, use parent's
229ddde725dSArmin Le Grand             if(getParent())
230ddde725dSArmin Le Grand             {
231ddde725dSArmin Le Grand                 return getParent()->getSvgStyleAttributes();
232ddde725dSArmin Le Grand             }
233ddde725dSArmin Le Grand             else
234ddde725dSArmin Le Grand             {
235ddde725dSArmin Le Grand                 return 0;
236ddde725dSArmin Le Grand             }
237ddde725dSArmin Le Grand         }
238ddde725dSArmin Le Grand 
239ddde725dSArmin Le Grand         drawinglayer::primitive2d::TextSimplePortionPrimitive2D* SvgCharacterNode::createSimpleTextPrimitive(
240ddde725dSArmin Le Grand             SvgTextPosition& rSvgTextPosition,
241ddde725dSArmin Le Grand             const SvgStyleAttributes& rSvgStyleAttributes) const
242ddde725dSArmin Le Grand         {
243ddde725dSArmin Le Grand             // prepare retval, index and length
244ddde725dSArmin Le Grand             drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pRetval = 0;
245ddde725dSArmin Le Grand             sal_uInt32 nIndex(0);
246ddde725dSArmin Le Grand             sal_uInt32 nLength(getText().getLength());
247ddde725dSArmin Le Grand 
248ddde725dSArmin Le Grand             if(nLength)
249ddde725dSArmin Le Grand             {
250ddde725dSArmin Le Grand                 // prepare FontAttribute
251ddde725dSArmin Le Grand                 const rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ?
252ddde725dSArmin Le Grand                     rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) :
253ddde725dSArmin Le Grand                     rSvgStyleAttributes.getFontFamily()[0];
254ddde725dSArmin Le Grand                 const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
255ddde725dSArmin Le Grand                 bool bSymbol(false);
256ddde725dSArmin Le Grand                 bool bVertical(false);
257ddde725dSArmin Le Grand                 bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle());
258ddde725dSArmin Le Grand                 bool bMonospaced(false);
259ddde725dSArmin Le Grand                 bool bOutline(false);
260ddde725dSArmin Le Grand                 bool bRTL(false);
261ddde725dSArmin Le Grand                 bool bBiDiStrong(false);
262ddde725dSArmin Le Grand 
263ddde725dSArmin Le Grand                 const drawinglayer::attribute::FontAttribute aFontAttribute(
264ddde725dSArmin Le Grand                     aFontFamily,
265ddde725dSArmin Le Grand                     rtl::OUString(),
266ddde725dSArmin Le Grand                     nFontWeight,
267ddde725dSArmin Le Grand                     bSymbol,
268ddde725dSArmin Le Grand                     bVertical,
269ddde725dSArmin Le Grand                     bItalic,
270ddde725dSArmin Le Grand                     bMonospaced,
271ddde725dSArmin Le Grand                     bOutline,
272ddde725dSArmin Le Grand                     bRTL,
273ddde725dSArmin Le Grand                     bBiDiStrong);
274ddde725dSArmin Le Grand 
275ddde725dSArmin Le Grand                 // prepare FontSize
276ddde725dSArmin Le Grand                 double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length));
277ddde725dSArmin Le Grand                 double fFontHeight(fFontWidth);
278ddde725dSArmin Le Grand 
279ddde725dSArmin Le Grand                 // prepare locale
280ddde725dSArmin Le Grand                 ::com::sun::star::lang::Locale aLocale;
281ddde725dSArmin Le Grand 
282ddde725dSArmin Le Grand                 // prepare TextLayouterDevice
283ddde725dSArmin Le Grand                 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
284ddde725dSArmin Le Grand                 aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale);
285ddde725dSArmin Le Grand 
286ddde725dSArmin Le Grand                 // prepare TextArray
287ddde725dSArmin Le Grand                 ::std::vector< double > aTextArray(rSvgTextPosition.getX());
288ddde725dSArmin Le Grand 
289ddde725dSArmin Le Grand                 if(!aTextArray.empty() && aTextArray.size() < nLength)
290ddde725dSArmin Le Grand                 {
291ddde725dSArmin Le Grand                     const sal_uInt32 nArray(aTextArray.size());
292ddde725dSArmin Le Grand 
293ddde725dSArmin Le Grand                     if(nArray < nLength)
294ddde725dSArmin Le Grand                     {
295ddde725dSArmin Le Grand                         double fStartX(0.0);
296ddde725dSArmin Le Grand 
297ddde725dSArmin Le Grand                         if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX())
298ddde725dSArmin Le Grand                         {
299ddde725dSArmin Le Grand                             fStartX = rSvgTextPosition.getParent()->getPosition().getX();
300ddde725dSArmin Le Grand                         }
301ddde725dSArmin Le Grand                         else
302ddde725dSArmin Le Grand                         {
303ddde725dSArmin Le Grand                             fStartX = aTextArray[nArray - 1];
304ddde725dSArmin Le Grand                         }
305ddde725dSArmin Le Grand 
306ddde725dSArmin Le Grand                         ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray));
307ddde725dSArmin Le Grand                         aTextArray.reserve(nLength);
308ddde725dSArmin Le Grand 
309ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < aExtendArray.size(); a++)
310ddde725dSArmin Le Grand                         {
311ddde725dSArmin Le Grand                             aTextArray.push_back(aExtendArray[a] + fStartX);
312ddde725dSArmin Le Grand                         }
313ddde725dSArmin Le Grand                     }
314ddde725dSArmin Le Grand                 }
315ddde725dSArmin Le Grand 
316ddde725dSArmin Le Grand                 // get current TextPosition and TextWidth in units
317ddde725dSArmin Le Grand                 basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition());
318ddde725dSArmin Le Grand                 double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength));
319ddde725dSArmin Le Grand 
320ddde725dSArmin Le Grand                 // check for user-given TextLength
321ddde725dSArmin Le Grand                 if(0.0 != rSvgTextPosition.getTextLength()
322ddde725dSArmin Le Grand                     && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength()))
323ddde725dSArmin Le Grand                 {
324ddde725dSArmin Le Grand                     const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth);
325ddde725dSArmin Le Grand 
326ddde725dSArmin Le Grand                     if(rSvgTextPosition.getLengthAdjust())
327ddde725dSArmin Le Grand                     {
328ddde725dSArmin Le Grand                         // spacing, need to create and expand TextArray
329ddde725dSArmin Le Grand                         if(aTextArray.empty())
330ddde725dSArmin Le Grand                         {
331ddde725dSArmin Le Grand                             aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength);
332ddde725dSArmin Le Grand                         }
333ddde725dSArmin Le Grand 
334ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < aTextArray.size(); a++)
335ddde725dSArmin Le Grand                         {
336ddde725dSArmin Le Grand                             aTextArray[a] *= fFactor;
337ddde725dSArmin Le Grand                         }
338ddde725dSArmin Le Grand                     }
339ddde725dSArmin Le Grand                     else
340ddde725dSArmin Le Grand                     {
341ddde725dSArmin Le Grand                         // spacing and glyphs, just apply to FontWidth
342ddde725dSArmin Le Grand                         fFontWidth *= fFactor;
343ddde725dSArmin Le Grand                     }
344ddde725dSArmin Le Grand 
345ddde725dSArmin Le Grand                     fTextWidth = rSvgTextPosition.getTextLength();
346ddde725dSArmin Le Grand                 }
347ddde725dSArmin Le Grand 
348ddde725dSArmin Le Grand                 // get TextAlign
349ddde725dSArmin Le Grand                 TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign());
350ddde725dSArmin Le Grand 
351ddde725dSArmin Le Grand                 // map TextAnchor to TextAlign, there seems not to be a difference
352ddde725dSArmin Le Grand                 if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor())
353ddde725dSArmin Le Grand                 {
354ddde725dSArmin Le Grand                     switch(rSvgStyleAttributes.getTextAnchor())
355ddde725dSArmin Le Grand                     {
356ddde725dSArmin Le Grand                         case TextAnchor_start:
357ddde725dSArmin Le Grand                         {
358ddde725dSArmin Le Grand                             aTextAlign = TextAlign_left;
359ddde725dSArmin Le Grand                             break;
360ddde725dSArmin Le Grand                         }
361ddde725dSArmin Le Grand                         case TextAnchor_middle:
362ddde725dSArmin Le Grand                         {
363ddde725dSArmin Le Grand                             aTextAlign = TextAlign_center;
364ddde725dSArmin Le Grand                             break;
365ddde725dSArmin Le Grand                         }
366ddde725dSArmin Le Grand                         case TextAnchor_end:
367ddde725dSArmin Le Grand                         {
368ddde725dSArmin Le Grand                             aTextAlign = TextAlign_right;
369ddde725dSArmin Le Grand                             break;
370ddde725dSArmin Le Grand                         }
371e2bf1e9dSArmin Le Grand                         default:
372e2bf1e9dSArmin Le Grand                         {
373e2bf1e9dSArmin Le Grand                             break;
374e2bf1e9dSArmin Le Grand                         }
375ddde725dSArmin Le Grand                     }
376ddde725dSArmin Le Grand                 }
377ddde725dSArmin Le Grand 
378ddde725dSArmin Le Grand                 // apply TextAlign
379ddde725dSArmin Le Grand                 switch(aTextAlign)
380ddde725dSArmin Le Grand                 {
381ddde725dSArmin Le Grand                     case TextAlign_right:
382ddde725dSArmin Le Grand                     {
383ddde725dSArmin Le Grand                         aPosition.setX(aPosition.getX() - fTextWidth);
384ddde725dSArmin Le Grand                         break;
385ddde725dSArmin Le Grand                     }
386ddde725dSArmin Le Grand                     case TextAlign_center:
387ddde725dSArmin Le Grand                     {
388ddde725dSArmin Le Grand                         aPosition.setX(aPosition.getX() - (fTextWidth * 0.5));
389ddde725dSArmin Le Grand                         break;
390ddde725dSArmin Le Grand                     }
391ddde725dSArmin Le Grand                     case TextAlign_notset:
392ddde725dSArmin Le Grand                     case TextAlign_left:
393ddde725dSArmin Le Grand                     case TextAlign_justify:
394ddde725dSArmin Le Grand                     {
395ddde725dSArmin Le Grand                         // TextAlign_notset, TextAlign_left: nothing to do
396ddde725dSArmin Le Grand                         // TextAlign_justify is not clear currently; handle as TextAlign_left
397ddde725dSArmin Le Grand                         break;
398ddde725dSArmin Le Grand                     }
399ddde725dSArmin Le Grand                 }
400ddde725dSArmin Le Grand 
401ddde725dSArmin Le Grand                 // get fill color
402ddde725dSArmin Le Grand                 const basegfx::BColor aFill(rSvgStyleAttributes.getFill()
403ddde725dSArmin Le Grand                     ? *rSvgStyleAttributes.getFill()
404ddde725dSArmin Le Grand                     : basegfx::BColor(0.0, 0.0, 0.0));
405ddde725dSArmin Le Grand 
406ddde725dSArmin Le Grand                 // prepare TextTransformation
407ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aTextTransform;
408ddde725dSArmin Le Grand 
409ddde725dSArmin Le Grand                 aTextTransform.scale(fFontWidth, fFontHeight);
410ddde725dSArmin Le Grand                 aTextTransform.translate(aPosition.getX(), aPosition.getY());
411ddde725dSArmin Le Grand 
412ddde725dSArmin Le Grand                 // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed
413ddde725dSArmin Le Grand                 const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration());
414ddde725dSArmin Le Grand 
415ddde725dSArmin Le Grand                 if(TextDecoration_underline == aDeco
416ddde725dSArmin Le Grand                     || TextDecoration_overline == aDeco
417ddde725dSArmin Le Grand                     || TextDecoration_line_through == aDeco)
418ddde725dSArmin Le Grand                 {
419ddde725dSArmin Le Grand                     // get the fill for decroation as described by SVG. We cannot
420ddde725dSArmin Le Grand                     // have different stroke colors/definitions for those, though
421ddde725dSArmin Le Grand                     const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes();
422ddde725dSArmin Le Grand                     const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill);
423ddde725dSArmin Le Grand 
424ddde725dSArmin Le Grand                     // create decorated text primitive
425ddde725dSArmin Le Grand                     pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
426ddde725dSArmin Le Grand                         aTextTransform,
427ddde725dSArmin Le Grand                         getText(),
428ddde725dSArmin Le Grand                         nIndex,
429ddde725dSArmin Le Grand                         nLength,
430ddde725dSArmin Le Grand                         aTextArray,
431ddde725dSArmin Le Grand                         aFontAttribute,
432ddde725dSArmin Le Grand                         aLocale,
433ddde725dSArmin Le Grand                         aFill,
434ddde725dSArmin Le Grand 
435ddde725dSArmin Le Grand                         // extra props for decorated
436ddde725dSArmin Le Grand                         aDecoColor,
437ddde725dSArmin Le Grand                         aDecoColor,
438ddde725dSArmin Le Grand                         TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
439ddde725dSArmin Le Grand                         TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
440ddde725dSArmin Le Grand                         false,
441ddde725dSArmin Le Grand                         TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE,
442ddde725dSArmin Le Grand                         false,
443ddde725dSArmin Le Grand                         drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE,
444ddde725dSArmin Le Grand                         true,
445ddde725dSArmin Le Grand                         false,
446ddde725dSArmin Le Grand                         drawinglayer::primitive2d::TEXT_RELIEF_NONE,
447ddde725dSArmin Le Grand                         false);
448ddde725dSArmin Le Grand                 }
449ddde725dSArmin Le Grand                 else
450ddde725dSArmin Le Grand                 {
451ddde725dSArmin Le Grand                     // create text primitive
452ddde725dSArmin Le Grand                     pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
453ddde725dSArmin Le Grand                         aTextTransform,
454ddde725dSArmin Le Grand                         getText(),
455ddde725dSArmin Le Grand                         nIndex,
456ddde725dSArmin Le Grand                         nLength,
457ddde725dSArmin Le Grand                         aTextArray,
458ddde725dSArmin Le Grand                         aFontAttribute,
459ddde725dSArmin Le Grand                         aLocale,
460ddde725dSArmin Le Grand                         aFill);
461ddde725dSArmin Le Grand                 }
462ddde725dSArmin Le Grand 
463ddde725dSArmin Le Grand                 // advance current TextPosition
464ddde725dSArmin Le Grand                 rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0));
465ddde725dSArmin Le Grand             }
466ddde725dSArmin Le Grand 
467ddde725dSArmin Le Grand             return pRetval;
468ddde725dSArmin Le Grand         }
469ddde725dSArmin Le Grand 
470ddde725dSArmin Le Grand         void SvgCharacterNode::decomposeTextWithStyle(
471ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
472ddde725dSArmin Le Grand             SvgTextPosition& rSvgTextPosition,
473ddde725dSArmin Le Grand             const SvgStyleAttributes& rSvgStyleAttributes) const
474ddde725dSArmin Le Grand         {
475ddde725dSArmin Le Grand             const drawinglayer::primitive2d::Primitive2DReference xRef(
476ddde725dSArmin Le Grand                 createSimpleTextPrimitive(
477ddde725dSArmin Le Grand                     rSvgTextPosition,
478ddde725dSArmin Le Grand                     rSvgStyleAttributes));
479ddde725dSArmin Le Grand 
480ddde725dSArmin Le Grand             if(xRef.is())
481ddde725dSArmin Le Grand             {
482ddde725dSArmin Le Grand                 if(!rSvgTextPosition.isRotated())
483ddde725dSArmin Le Grand                 {
484ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
485ddde725dSArmin Le Grand                 }
486ddde725dSArmin Le Grand                 else
487ddde725dSArmin Le Grand                 {
488ddde725dSArmin Le Grand                     // need to apply rotations to each character as given
489*693be7f6SArmin Le Grand                     const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate =
490*693be7f6SArmin Le Grand                         dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get());
491*693be7f6SArmin Le Grand 
492*693be7f6SArmin Le Grand                     if(pCandidate)
493*693be7f6SArmin Le Grand                     {
494*693be7f6SArmin Le Grand                         const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition);
495ddde725dSArmin Le Grand                         const drawinglayer::primitive2d::Primitive2DSequence aResult(
496ddde725dSArmin Le Grand                             alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character));
497ddde725dSArmin Le Grand 
498ddde725dSArmin Le Grand                         if(aResult.hasElements())
499ddde725dSArmin Le Grand                         {
500ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult);
501ddde725dSArmin Le Grand                         }
502ddde725dSArmin Le Grand 
503ddde725dSArmin Le Grand                         // also consume for the implied single space
504ddde725dSArmin Le Grand                         rSvgTextPosition.consumeRotation();
505ddde725dSArmin Le Grand                     }
506*693be7f6SArmin Le Grand                     else
507*693be7f6SArmin Le Grand                     {
508*693be7f6SArmin Le Grand                         OSL_ENSURE(false, "Used primitive is not a text primitive (!)");
509*693be7f6SArmin Le Grand                     }
510*693be7f6SArmin Le Grand                 }
511ddde725dSArmin Le Grand             }
512ddde725dSArmin Le Grand         }
513ddde725dSArmin Le Grand 
514ddde725dSArmin Le Grand         void SvgCharacterNode::whiteSpaceHandling()
515ddde725dSArmin Le Grand         {
516ddde725dSArmin Le Grand             if(XmlSpace_default == getXmlSpace())
517ddde725dSArmin Le Grand             {
518ddde725dSArmin Le Grand                 maText = whiteSpaceHandlingDefault(maText);
519ddde725dSArmin Le Grand             }
520ddde725dSArmin Le Grand             else
521ddde725dSArmin Le Grand             {
522ddde725dSArmin Le Grand                 maText = whiteSpaceHandlingPreserve(maText);
523ddde725dSArmin Le Grand             }
524ddde725dSArmin Le Grand         }
525ddde725dSArmin Le Grand 
526ddde725dSArmin Le Grand         void SvgCharacterNode::addGap()
527ddde725dSArmin Le Grand         {
528ddde725dSArmin Le Grand             maText += rtl::OUString(sal_Unicode(' '));
529ddde725dSArmin Le Grand         }
530ddde725dSArmin Le Grand 
531ddde725dSArmin Le Grand         void SvgCharacterNode::concatenate(const rtl::OUString& rText)
532ddde725dSArmin Le Grand         {
533ddde725dSArmin Le Grand             maText += rText;
534ddde725dSArmin Le Grand         }
535ddde725dSArmin Le Grand 
536ddde725dSArmin Le Grand         void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const
537ddde725dSArmin Le Grand         {
538ddde725dSArmin Le Grand             if(getText().getLength())
539ddde725dSArmin Le Grand             {
540ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes();
541ddde725dSArmin Le Grand 
542ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
543ddde725dSArmin Le Grand                 {
544ddde725dSArmin Le Grand                     decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes);
545ddde725dSArmin Le Grand                 }
546ddde725dSArmin Le Grand             }
547ddde725dSArmin Le Grand         }
548ddde725dSArmin Le Grand 
549ddde725dSArmin Le Grand     } // end of namespace svgreader
550ddde725dSArmin Le Grand } // end of namespace svgio
551ddde725dSArmin Le Grand 
552ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
553ddde725dSArmin Le Grand 
554ddde725dSArmin Le Grand namespace svgio
555ddde725dSArmin Le Grand {
556ddde725dSArmin Le Grand     namespace svgreader
557ddde725dSArmin Le Grand     {
558ddde725dSArmin Le Grand         SvgTextPosition::SvgTextPosition(
559ddde725dSArmin Le Grand             SvgTextPosition* pParent,
560ddde725dSArmin Le Grand             const InfoProvider& rInfoProvider,
561ddde725dSArmin Le Grand             const SvgTextPositions& rSvgTextPositions)
562ddde725dSArmin Le Grand         :   mpParent(pParent),
563ddde725dSArmin Le Grand             maX(), // computed below
564ddde725dSArmin Le Grand             maY(), // computed below
565ddde725dSArmin Le Grand             maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)),
566ddde725dSArmin Le Grand             mfTextLength(0.0),
567ddde725dSArmin Le Grand             maPosition(), // computed below
568ddde725dSArmin Le Grand             mnRotationIndex(0),
569ddde725dSArmin Le Grand             mbLengthAdjust(rSvgTextPositions.getLengthAdjust()),
570ddde725dSArmin Le Grand             mbAbsoluteX(false),
571ddde725dSArmin Le Grand             mbAbsoluteY(false)
572ddde725dSArmin Le Grand         {
573ddde725dSArmin Le Grand             // get TextLength if provided
574ddde725dSArmin Le Grand             if(rSvgTextPositions.getTextLength().isSet())
575ddde725dSArmin Le Grand             {
576ddde725dSArmin Le Grand                 mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length);
577ddde725dSArmin Le Grand             }
578ddde725dSArmin Le Grand 
579ddde725dSArmin Le Grand             // SVG does not really define in which units a �rotate� for Text/TSpan is given,
580ddde725dSArmin Le Grand             // but it seems to be degrees. Convert here to radians
581ddde725dSArmin Le Grand             if(!maRotate.empty())
582ddde725dSArmin Le Grand             {
583ddde725dSArmin Le Grand                 const double fFactor(F_PI / 180.0);
584ddde725dSArmin Le Grand 
585ddde725dSArmin Le Grand                 for(sal_uInt32 a(0); a < maRotate.size(); a++)
586ddde725dSArmin Le Grand                 {
587ddde725dSArmin Le Grand                     maRotate[a] *= fFactor;
588ddde725dSArmin Le Grand                 }
589ddde725dSArmin Le Grand             }
590ddde725dSArmin Le Grand 
591ddde725dSArmin Le Grand             // get text positions X
592ddde725dSArmin Le Grand             const sal_uInt32 nSizeX(rSvgTextPositions.getX().size());
593ddde725dSArmin Le Grand 
594ddde725dSArmin Le Grand             if(nSizeX)
595ddde725dSArmin Le Grand             {
596ddde725dSArmin Le Grand                 // we have absolute positions, get first one as current text position X
597ddde725dSArmin Le Grand                 maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate));
598ddde725dSArmin Le Grand                 mbAbsoluteX = true;
599ddde725dSArmin Le Grand 
600ddde725dSArmin Le Grand                 if(nSizeX > 1)
601ddde725dSArmin Le Grand                 {
602ddde725dSArmin Le Grand                     // fill deltas to maX
603ddde725dSArmin Le Grand                     maX.reserve(nSizeX);
604ddde725dSArmin Le Grand 
605ddde725dSArmin Le Grand                     for(sal_uInt32 a(1); a < nSizeX; a++)
606ddde725dSArmin Le Grand                     {
607ddde725dSArmin Le Grand                         maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX());
608ddde725dSArmin Le Grand                     }
609ddde725dSArmin Le Grand                 }
610ddde725dSArmin Le Grand             }
611ddde725dSArmin Le Grand             else
612ddde725dSArmin Le Grand             {
613ddde725dSArmin Le Grand                 // no absolute position, get from parent
614ddde725dSArmin Le Grand                 if(pParent)
615ddde725dSArmin Le Grand                 {
616ddde725dSArmin Le Grand                     maPosition.setX(pParent->getPosition().getX());
617ddde725dSArmin Le Grand                 }
618ddde725dSArmin Le Grand 
619ddde725dSArmin Le Grand                 const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size());
620ddde725dSArmin Le Grand 
621ddde725dSArmin Le Grand                 if(nSizeDx)
622ddde725dSArmin Le Grand                 {
623ddde725dSArmin Le Grand                     // relative positions given, translate position derived from parent
624ddde725dSArmin Le Grand                     maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate));
625ddde725dSArmin Le Grand 
626ddde725dSArmin Le Grand                     if(nSizeDx > 1)
627ddde725dSArmin Le Grand                     {
628ddde725dSArmin Le Grand                         // fill deltas to maX
629ddde725dSArmin Le Grand                         maX.reserve(nSizeDx);
630ddde725dSArmin Le Grand 
631ddde725dSArmin Le Grand                         for(sal_uInt32 a(1); a < nSizeDx; a++)
632ddde725dSArmin Le Grand                         {
633ddde725dSArmin Le Grand                             maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate));
634ddde725dSArmin Le Grand                         }
635ddde725dSArmin Le Grand                     }
636ddde725dSArmin Le Grand                 }
637ddde725dSArmin Le Grand             }
638ddde725dSArmin Le Grand 
639ddde725dSArmin Le Grand             // get text positions Y
640ddde725dSArmin Le Grand             const sal_uInt32 nSizeY(rSvgTextPositions.getY().size());
641ddde725dSArmin Le Grand 
642ddde725dSArmin Le Grand             if(nSizeY)
643ddde725dSArmin Le Grand             {
644ddde725dSArmin Le Grand                 // we have absolute positions, get first one as current text position Y
645ddde725dSArmin Le Grand                 maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate));
646ddde725dSArmin Le Grand                 mbAbsoluteX = true;
647ddde725dSArmin Le Grand 
648ddde725dSArmin Le Grand                 if(nSizeY > 1)
649ddde725dSArmin Le Grand                 {
650ddde725dSArmin Le Grand                     // fill deltas to maY
651ddde725dSArmin Le Grand                     maY.reserve(nSizeY);
652ddde725dSArmin Le Grand 
653ddde725dSArmin Le Grand                     for(sal_uInt32 a(1); a < nSizeY; a++)
654ddde725dSArmin Le Grand                     {
655ddde725dSArmin Le Grand                         maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY());
656ddde725dSArmin Le Grand                     }
657ddde725dSArmin Le Grand                 }
658ddde725dSArmin Le Grand             }
659ddde725dSArmin Le Grand             else
660ddde725dSArmin Le Grand             {
661ddde725dSArmin Le Grand                 // no absolute position, get from parent
662ddde725dSArmin Le Grand                 if(pParent)
663ddde725dSArmin Le Grand                 {
664ddde725dSArmin Le Grand                     maPosition.setY(pParent->getPosition().getY());
665ddde725dSArmin Le Grand                 }
666ddde725dSArmin Le Grand 
667ddde725dSArmin Le Grand                 const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size());
668ddde725dSArmin Le Grand 
669ddde725dSArmin Le Grand                 if(nSizeDy)
670ddde725dSArmin Le Grand                 {
671ddde725dSArmin Le Grand                     // relative positions given, translate position derived from parent
672ddde725dSArmin Le Grand                     maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate));
673ddde725dSArmin Le Grand 
674ddde725dSArmin Le Grand                     if(nSizeDy > 1)
675ddde725dSArmin Le Grand                     {
676ddde725dSArmin Le Grand                         // fill deltas to maY
677ddde725dSArmin Le Grand                         maY.reserve(nSizeDy);
678ddde725dSArmin Le Grand 
679ddde725dSArmin Le Grand                         for(sal_uInt32 a(1); a < nSizeDy; a++)
680ddde725dSArmin Le Grand                         {
681ddde725dSArmin Le Grand                             maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate));
682ddde725dSArmin Le Grand                         }
683ddde725dSArmin Le Grand                     }
684ddde725dSArmin Le Grand                 }
685ddde725dSArmin Le Grand             }
686ddde725dSArmin Le Grand         }
687ddde725dSArmin Le Grand 
688ddde725dSArmin Le Grand         bool SvgTextPosition::isRotated() const
689ddde725dSArmin Le Grand         {
690ddde725dSArmin Le Grand             if(maRotate.empty())
691ddde725dSArmin Le Grand             {
692ddde725dSArmin Le Grand                 if(getParent())
693ddde725dSArmin Le Grand                 {
694ddde725dSArmin Le Grand                     return getParent()->isRotated();
695ddde725dSArmin Le Grand                 }
696ddde725dSArmin Le Grand                 else
697ddde725dSArmin Le Grand                 {
698ddde725dSArmin Le Grand                     return false;
699ddde725dSArmin Le Grand                 }
700ddde725dSArmin Le Grand             }
701ddde725dSArmin Le Grand             else
702ddde725dSArmin Le Grand             {
703ddde725dSArmin Le Grand                 return true;
704ddde725dSArmin Le Grand             }
705ddde725dSArmin Le Grand         }
706ddde725dSArmin Le Grand 
707ddde725dSArmin Le Grand         double SvgTextPosition::consumeRotation()
708ddde725dSArmin Le Grand         {
709ddde725dSArmin Le Grand             double fRetval(0.0);
710ddde725dSArmin Le Grand 
711ddde725dSArmin Le Grand             if(maRotate.empty())
712ddde725dSArmin Le Grand             {
713ddde725dSArmin Le Grand                 if(getParent())
714ddde725dSArmin Le Grand                 {
715ddde725dSArmin Le Grand                     fRetval = mpParent->consumeRotation();
716ddde725dSArmin Le Grand                 }
717ddde725dSArmin Le Grand                 else
718ddde725dSArmin Le Grand                 {
719ddde725dSArmin Le Grand                     fRetval = 0.0;
720ddde725dSArmin Le Grand                 }
721ddde725dSArmin Le Grand             }
722ddde725dSArmin Le Grand             else
723ddde725dSArmin Le Grand             {
724ddde725dSArmin Le Grand                 const sal_uInt32 nSize(maRotate.size());
725ddde725dSArmin Le Grand 
726ddde725dSArmin Le Grand                 if(mnRotationIndex < nSize)
727ddde725dSArmin Le Grand                 {
728ddde725dSArmin Le Grand                     fRetval = maRotate[mnRotationIndex++];
729ddde725dSArmin Le Grand                 }
730ddde725dSArmin Le Grand                 else
731ddde725dSArmin Le Grand                 {
732ddde725dSArmin Le Grand                     fRetval = maRotate[nSize - 1];
733ddde725dSArmin Le Grand                 }
734ddde725dSArmin Le Grand             }
735ddde725dSArmin Le Grand 
736ddde725dSArmin Le Grand             return fRetval;
737ddde725dSArmin Le Grand         }
738ddde725dSArmin Le Grand 
739ddde725dSArmin Le Grand     } // end of namespace svgreader
740ddde725dSArmin Le Grand } // end of namespace svgio
741ddde725dSArmin Le Grand 
742ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
743ddde725dSArmin Le Grand // eof
744