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