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     {
SvgTextPositions()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 
parseTextPositionAttributes(const rtl::OUString &,SVGToken aSVGToken,const rtl::OUString & aContent)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:
localTextBreakupHelper(const drawinglayer::primitive2d::TextSimplePortionPrimitive2D & rSource,SvgTextPosition & rSvgTextPosition)179ddde725dSArmin Le Grand             localTextBreakupHelper(
180693be7f6SArmin Le Grand                 const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource,
181ddde725dSArmin Le Grand                 SvgTextPosition& rSvgTextPosition)
182693be7f6SArmin Le Grand             :   drawinglayer::primitive2d::TextBreakupHelper(rSource),
183ddde725dSArmin Le Grand                 mrSvgTextPosition(rSvgTextPosition)
184ddde725dSArmin Le Grand             {
185ddde725dSArmin Le Grand             }
186ddde725dSArmin Le Grand         };
187ddde725dSArmin Le Grand 
allowChange(sal_uInt32,basegfx::B2DHomMatrix & rNewTransform,sal_uInt32,sal_uInt32)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     {
SvgCharacterNode(SvgDocument & rDocument,SvgNode * pParent,const rtl::OUString & rText)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 
~SvgCharacterNode()222ddde725dSArmin Le Grand         SvgCharacterNode::~SvgCharacterNode()
223ddde725dSArmin Le Grand         {
224ddde725dSArmin Le Grand         }
225ddde725dSArmin Le Grand 
getSvgStyleAttributes() const226ddde725dSArmin 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 
createSimpleTextPrimitive(SvgTextPosition & rSvgTextPosition,const SvgStyleAttributes & rSvgStyleAttributes) const239ddde725dSArmin 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
251861dea5cSArmin Le Grand                 rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ?
252ddde725dSArmin Le Grand                     rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) :
253ddde725dSArmin Le Grand                     rSvgStyleAttributes.getFontFamily()[0];
254861dea5cSArmin Le Grand 
255861dea5cSArmin Le Grand                 // #122324# if the FontFamily name ends on ' embedded' it is probably a re-import
256861dea5cSArmin Le Grand                 // of a SVG export with fiont embedding. Remove this to make font matching work. This
257861dea5cSArmin Le Grand                 // is pretty safe since there should be no font family names ending on ' embedded'.
258861dea5cSArmin Le Grand                 // Remove again when FontEmbedding is implemented in SVG import
259861dea5cSArmin Le Grand                 if(aFontFamily.endsWithAsciiL(" embedded", 9))
260861dea5cSArmin Le Grand                 {
261861dea5cSArmin Le Grand                     aFontFamily = aFontFamily.copy(0, aFontFamily.getLength() - 9);
262861dea5cSArmin Le Grand                 }
263861dea5cSArmin Le Grand 
264ddde725dSArmin Le Grand                 const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
265ddde725dSArmin Le Grand                 bool bSymbol(false);
266ddde725dSArmin Le Grand                 bool bVertical(false);
267ddde725dSArmin Le Grand                 bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle());
268ddde725dSArmin Le Grand                 bool bMonospaced(false);
269ddde725dSArmin Le Grand                 bool bOutline(false);
270ddde725dSArmin Le Grand                 bool bRTL(false);
271ddde725dSArmin Le Grand                 bool bBiDiStrong(false);
272ddde725dSArmin Le Grand 
273ddde725dSArmin Le Grand                 const drawinglayer::attribute::FontAttribute aFontAttribute(
274ddde725dSArmin Le Grand                     aFontFamily,
275ddde725dSArmin Le Grand                     rtl::OUString(),
276ddde725dSArmin Le Grand                     nFontWeight,
277ddde725dSArmin Le Grand                     bSymbol,
278ddde725dSArmin Le Grand                     bVertical,
279ddde725dSArmin Le Grand                     bItalic,
280ddde725dSArmin Le Grand                     bMonospaced,
281ddde725dSArmin Le Grand                     bOutline,
282ddde725dSArmin Le Grand                     bRTL,
283ddde725dSArmin Le Grand                     bBiDiStrong);
284ddde725dSArmin Le Grand 
285ddde725dSArmin Le Grand                 // prepare FontSize
286ddde725dSArmin Le Grand                 double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length));
287ddde725dSArmin Le Grand                 double fFontHeight(fFontWidth);
288ddde725dSArmin Le Grand 
289ddde725dSArmin Le Grand                 // prepare locale
290ddde725dSArmin Le Grand                 ::com::sun::star::lang::Locale aLocale;
291ddde725dSArmin Le Grand 
292ddde725dSArmin Le Grand                 // prepare TextLayouterDevice
293ddde725dSArmin Le Grand                 drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
294ddde725dSArmin Le Grand                 aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale);
295ddde725dSArmin Le Grand 
296ddde725dSArmin Le Grand                 // prepare TextArray
297ddde725dSArmin Le Grand                 ::std::vector< double > aTextArray(rSvgTextPosition.getX());
298ddde725dSArmin Le Grand 
299ddde725dSArmin Le Grand                 if(!aTextArray.empty() && aTextArray.size() < nLength)
300ddde725dSArmin Le Grand                 {
301ddde725dSArmin Le Grand                     const sal_uInt32 nArray(aTextArray.size());
302ddde725dSArmin Le Grand 
303ddde725dSArmin Le Grand                     if(nArray < nLength)
304ddde725dSArmin Le Grand                     {
305ddde725dSArmin Le Grand                         double fStartX(0.0);
306ddde725dSArmin Le Grand 
307ddde725dSArmin Le Grand                         if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX())
308ddde725dSArmin Le Grand                         {
309ddde725dSArmin Le Grand                             fStartX = rSvgTextPosition.getParent()->getPosition().getX();
310ddde725dSArmin Le Grand                         }
311ddde725dSArmin Le Grand                         else
312ddde725dSArmin Le Grand                         {
313ddde725dSArmin Le Grand                             fStartX = aTextArray[nArray - 1];
314ddde725dSArmin Le Grand                         }
315ddde725dSArmin Le Grand 
316ddde725dSArmin Le Grand                         ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray));
317ddde725dSArmin Le Grand                         aTextArray.reserve(nLength);
318ddde725dSArmin Le Grand 
319ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < aExtendArray.size(); a++)
320ddde725dSArmin Le Grand                         {
321ddde725dSArmin Le Grand                             aTextArray.push_back(aExtendArray[a] + fStartX);
322ddde725dSArmin Le Grand                         }
323ddde725dSArmin Le Grand                     }
324ddde725dSArmin Le Grand                 }
325ddde725dSArmin Le Grand 
326ddde725dSArmin Le Grand                 // get current TextPosition and TextWidth in units
327ddde725dSArmin Le Grand                 basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition());
328ddde725dSArmin Le Grand                 double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength));
329ddde725dSArmin Le Grand 
330ddde725dSArmin Le Grand                 // check for user-given TextLength
331ddde725dSArmin Le Grand                 if(0.0 != rSvgTextPosition.getTextLength()
332ddde725dSArmin Le Grand                     && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength()))
333ddde725dSArmin Le Grand                 {
334ddde725dSArmin Le Grand                     const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth);
335ddde725dSArmin Le Grand 
336ddde725dSArmin Le Grand                     if(rSvgTextPosition.getLengthAdjust())
337ddde725dSArmin Le Grand                     {
338ddde725dSArmin Le Grand                         // spacing, need to create and expand TextArray
339ddde725dSArmin Le Grand                         if(aTextArray.empty())
340ddde725dSArmin Le Grand                         {
341ddde725dSArmin Le Grand                             aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength);
342ddde725dSArmin Le Grand                         }
343ddde725dSArmin Le Grand 
344ddde725dSArmin Le Grand                         for(sal_uInt32 a(0); a < aTextArray.size(); a++)
345ddde725dSArmin Le Grand                         {
346ddde725dSArmin Le Grand                             aTextArray[a] *= fFactor;
347ddde725dSArmin Le Grand                         }
348ddde725dSArmin Le Grand                     }
349ddde725dSArmin Le Grand                     else
350ddde725dSArmin Le Grand                     {
351ddde725dSArmin Le Grand                         // spacing and glyphs, just apply to FontWidth
352ddde725dSArmin Le Grand                         fFontWidth *= fFactor;
353ddde725dSArmin Le Grand                     }
354ddde725dSArmin Le Grand 
355ddde725dSArmin Le Grand                     fTextWidth = rSvgTextPosition.getTextLength();
356ddde725dSArmin Le Grand                 }
357ddde725dSArmin Le Grand 
358ddde725dSArmin Le Grand                 // get TextAlign
359ddde725dSArmin Le Grand                 TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign());
360ddde725dSArmin Le Grand 
361ddde725dSArmin Le Grand                 // map TextAnchor to TextAlign, there seems not to be a difference
362ddde725dSArmin Le Grand                 if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor())
363ddde725dSArmin Le Grand                 {
364ddde725dSArmin Le Grand                     switch(rSvgStyleAttributes.getTextAnchor())
365ddde725dSArmin Le Grand                     {
366ddde725dSArmin Le Grand                         case TextAnchor_start:
367ddde725dSArmin Le Grand                         {
368ddde725dSArmin Le Grand                             aTextAlign = TextAlign_left;
369ddde725dSArmin Le Grand                             break;
370ddde725dSArmin Le Grand                         }
371ddde725dSArmin Le Grand                         case TextAnchor_middle:
372ddde725dSArmin Le Grand                         {
373ddde725dSArmin Le Grand                             aTextAlign = TextAlign_center;
374ddde725dSArmin Le Grand                             break;
375ddde725dSArmin Le Grand                         }
376ddde725dSArmin Le Grand                         case TextAnchor_end:
377ddde725dSArmin Le Grand                         {
378ddde725dSArmin Le Grand                             aTextAlign = TextAlign_right;
379ddde725dSArmin Le Grand                             break;
380ddde725dSArmin Le Grand                         }
381e2bf1e9dSArmin Le Grand                         default:
382e2bf1e9dSArmin Le Grand                         {
383e2bf1e9dSArmin Le Grand                             break;
384e2bf1e9dSArmin Le Grand                         }
385ddde725dSArmin Le Grand                     }
386ddde725dSArmin Le Grand                 }
387ddde725dSArmin Le Grand 
388ddde725dSArmin Le Grand                 // apply TextAlign
389ddde725dSArmin Le Grand                 switch(aTextAlign)
390ddde725dSArmin Le Grand                 {
391ddde725dSArmin Le Grand                     case TextAlign_right:
392ddde725dSArmin Le Grand                     {
393ddde725dSArmin Le Grand                         aPosition.setX(aPosition.getX() - fTextWidth);
394ddde725dSArmin Le Grand                         break;
395ddde725dSArmin Le Grand                     }
396ddde725dSArmin Le Grand                     case TextAlign_center:
397ddde725dSArmin Le Grand                     {
398ddde725dSArmin Le Grand                         aPosition.setX(aPosition.getX() - (fTextWidth * 0.5));
399ddde725dSArmin Le Grand                         break;
400ddde725dSArmin Le Grand                     }
401ddde725dSArmin Le Grand                     case TextAlign_notset:
402ddde725dSArmin Le Grand                     case TextAlign_left:
403ddde725dSArmin Le Grand                     case TextAlign_justify:
404ddde725dSArmin Le Grand                     {
405ddde725dSArmin Le Grand                         // TextAlign_notset, TextAlign_left: nothing to do
406ddde725dSArmin Le Grand                         // TextAlign_justify is not clear currently; handle as TextAlign_left
407ddde725dSArmin Le Grand                         break;
408ddde725dSArmin Le Grand                     }
409ddde725dSArmin Le Grand                 }
410ddde725dSArmin Le Grand 
411*86d02030SArmin Le Grand                 // get BaselineShift
412*86d02030SArmin Le Grand                 const BaselineShift aBaselineShift(rSvgStyleAttributes.getBaselineShift());
413*86d02030SArmin Le Grand 
414*86d02030SArmin Le Grand                 // apply BaselineShift
415*86d02030SArmin Le Grand                 switch(aBaselineShift)
416*86d02030SArmin Le Grand                 {
417*86d02030SArmin Le Grand                     case BaselineShift_Sub:
418*86d02030SArmin Le Grand                     {
419*86d02030SArmin Le Grand                         aPosition.setY(aPosition.getY() + aTextLayouterDevice.getUnderlineOffset());
420*86d02030SArmin Le Grand                         break;
421*86d02030SArmin Le Grand                     }
422*86d02030SArmin Le Grand                     case BaselineShift_Super:
423*86d02030SArmin Le Grand                     {
424*86d02030SArmin Le Grand                         aPosition.setY(aPosition.getY() + aTextLayouterDevice.getOverlineOffset());
425*86d02030SArmin Le Grand                         break;
426*86d02030SArmin Le Grand                     }
427*86d02030SArmin Le Grand                     case BaselineShift_Percentage:
428*86d02030SArmin Le Grand                     case BaselineShift_Length:
429*86d02030SArmin Le Grand                     {
430*86d02030SArmin Le Grand                         const SvgNumber aNumber(rSvgStyleAttributes.getBaselineShiftNumber());
431*86d02030SArmin Le Grand                         const double mfBaselineShift(aNumber.solve(*this, length));
432*86d02030SArmin Le Grand 
433*86d02030SArmin Le Grand                         aPosition.setY(aPosition.getY() + mfBaselineShift);
434*86d02030SArmin Le Grand                         break;
435*86d02030SArmin Le Grand                     }
436*86d02030SArmin Le Grand                     default: // BaselineShift_Baseline
437*86d02030SArmin Le Grand                     {
438*86d02030SArmin Le Grand                         // nothing to do
439*86d02030SArmin Le Grand                         break;
440*86d02030SArmin Le Grand                     }
441*86d02030SArmin Le Grand                 }
442*86d02030SArmin Le Grand 
443ddde725dSArmin Le Grand                 // get fill color
444ddde725dSArmin Le Grand                 const basegfx::BColor aFill(rSvgStyleAttributes.getFill()
445ddde725dSArmin Le Grand                     ? *rSvgStyleAttributes.getFill()
446ddde725dSArmin Le Grand                     : basegfx::BColor(0.0, 0.0, 0.0));
447ddde725dSArmin Le Grand 
448ddde725dSArmin Le Grand                 // prepare TextTransformation
449ddde725dSArmin Le Grand                 basegfx::B2DHomMatrix aTextTransform;
450ddde725dSArmin Le Grand 
451ddde725dSArmin Le Grand                 aTextTransform.scale(fFontWidth, fFontHeight);
452ddde725dSArmin Le Grand                 aTextTransform.translate(aPosition.getX(), aPosition.getY());
453ddde725dSArmin Le Grand 
454ddde725dSArmin Le Grand                 // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed
455ddde725dSArmin Le Grand                 const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration());
456ddde725dSArmin Le Grand 
457ddde725dSArmin Le Grand                 if(TextDecoration_underline == aDeco
458ddde725dSArmin Le Grand                     || TextDecoration_overline == aDeco
459ddde725dSArmin Le Grand                     || TextDecoration_line_through == aDeco)
460ddde725dSArmin Le Grand                 {
461ddde725dSArmin Le Grand                     // get the fill for decroation as described by SVG. We cannot
462ddde725dSArmin Le Grand                     // have different stroke colors/definitions for those, though
463ddde725dSArmin Le Grand                     const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes();
464ddde725dSArmin Le Grand                     const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill);
465ddde725dSArmin Le Grand 
466ddde725dSArmin Le Grand                     // create decorated text primitive
467ddde725dSArmin Le Grand                     pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
468ddde725dSArmin Le Grand                         aTextTransform,
469ddde725dSArmin Le Grand                         getText(),
470ddde725dSArmin Le Grand                         nIndex,
471ddde725dSArmin Le Grand                         nLength,
472ddde725dSArmin Le Grand                         aTextArray,
473ddde725dSArmin Le Grand                         aFontAttribute,
474ddde725dSArmin Le Grand                         aLocale,
475ddde725dSArmin Le Grand                         aFill,
476ddde725dSArmin Le Grand 
477ddde725dSArmin Le Grand                         // extra props for decorated
478ddde725dSArmin Le Grand                         aDecoColor,
479ddde725dSArmin Le Grand                         aDecoColor,
480ddde725dSArmin Le Grand                         TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
481ddde725dSArmin Le Grand                         TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
482ddde725dSArmin Le Grand                         false,
483ddde725dSArmin Le Grand                         TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE,
484ddde725dSArmin Le Grand                         false,
485ddde725dSArmin Le Grand                         drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE,
486ddde725dSArmin Le Grand                         true,
487ddde725dSArmin Le Grand                         false,
488ddde725dSArmin Le Grand                         drawinglayer::primitive2d::TEXT_RELIEF_NONE,
489ddde725dSArmin Le Grand                         false);
490ddde725dSArmin Le Grand                 }
491ddde725dSArmin Le Grand                 else
492ddde725dSArmin Le Grand                 {
493ddde725dSArmin Le Grand                     // create text primitive
494ddde725dSArmin Le Grand                     pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
495ddde725dSArmin Le Grand                         aTextTransform,
496ddde725dSArmin Le Grand                         getText(),
497ddde725dSArmin Le Grand                         nIndex,
498ddde725dSArmin Le Grand                         nLength,
499ddde725dSArmin Le Grand                         aTextArray,
500ddde725dSArmin Le Grand                         aFontAttribute,
501ddde725dSArmin Le Grand                         aLocale,
502ddde725dSArmin Le Grand                         aFill);
503ddde725dSArmin Le Grand                 }
504ddde725dSArmin Le Grand 
505ddde725dSArmin Le Grand                 // advance current TextPosition
506ddde725dSArmin Le Grand                 rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0));
507ddde725dSArmin Le Grand             }
508ddde725dSArmin Le Grand 
509ddde725dSArmin Le Grand             return pRetval;
510ddde725dSArmin Le Grand         }
511ddde725dSArmin Le Grand 
decomposeTextWithStyle(drawinglayer::primitive2d::Primitive2DSequence & rTarget,SvgTextPosition & rSvgTextPosition,const SvgStyleAttributes & rSvgStyleAttributes) const512ddde725dSArmin Le Grand         void SvgCharacterNode::decomposeTextWithStyle(
513ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence& rTarget,
514ddde725dSArmin Le Grand             SvgTextPosition& rSvgTextPosition,
515ddde725dSArmin Le Grand             const SvgStyleAttributes& rSvgStyleAttributes) const
516ddde725dSArmin Le Grand         {
517ddde725dSArmin Le Grand             const drawinglayer::primitive2d::Primitive2DReference xRef(
518ddde725dSArmin Le Grand                 createSimpleTextPrimitive(
519ddde725dSArmin Le Grand                     rSvgTextPosition,
520ddde725dSArmin Le Grand                     rSvgStyleAttributes));
521ddde725dSArmin Le Grand 
522ddde725dSArmin Le Grand             if(xRef.is())
523ddde725dSArmin Le Grand             {
524ddde725dSArmin Le Grand                 if(!rSvgTextPosition.isRotated())
525ddde725dSArmin Le Grand                 {
526ddde725dSArmin Le Grand                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
527ddde725dSArmin Le Grand                 }
528ddde725dSArmin Le Grand                 else
529ddde725dSArmin Le Grand                 {
530ddde725dSArmin Le Grand                     // need to apply rotations to each character as given
531693be7f6SArmin Le Grand                     const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate =
532693be7f6SArmin Le Grand                         dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get());
533ddde725dSArmin Le Grand 
534693be7f6SArmin Le Grand                     if(pCandidate)
535ddde725dSArmin Le Grand                     {
536693be7f6SArmin Le Grand                         const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition);
537693be7f6SArmin Le Grand                         const drawinglayer::primitive2d::Primitive2DSequence aResult(
538693be7f6SArmin Le Grand                             alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character));
539693be7f6SArmin Le Grand 
540693be7f6SArmin Le Grand                         if(aResult.hasElements())
541693be7f6SArmin Le Grand                         {
542693be7f6SArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult);
543693be7f6SArmin Le Grand                         }
544ddde725dSArmin Le Grand 
545693be7f6SArmin Le Grand                         // also consume for the implied single space
546693be7f6SArmin Le Grand                         rSvgTextPosition.consumeRotation();
547693be7f6SArmin Le Grand                     }
548693be7f6SArmin Le Grand                     else
549693be7f6SArmin Le Grand                     {
550693be7f6SArmin Le Grand                         OSL_ENSURE(false, "Used primitive is not a text primitive (!)");
551693be7f6SArmin Le Grand                     }
552ddde725dSArmin Le Grand                 }
553ddde725dSArmin Le Grand             }
554ddde725dSArmin Le Grand         }
555ddde725dSArmin Le Grand 
whiteSpaceHandling()556ddde725dSArmin Le Grand         void SvgCharacterNode::whiteSpaceHandling()
557ddde725dSArmin Le Grand         {
558ddde725dSArmin Le Grand             if(XmlSpace_default == getXmlSpace())
559ddde725dSArmin Le Grand             {
560ddde725dSArmin Le Grand                 maText = whiteSpaceHandlingDefault(maText);
561ddde725dSArmin Le Grand             }
562ddde725dSArmin Le Grand             else
563ddde725dSArmin Le Grand             {
564ddde725dSArmin Le Grand                 maText = whiteSpaceHandlingPreserve(maText);
565ddde725dSArmin Le Grand             }
566ddde725dSArmin Le Grand         }
567ddde725dSArmin Le Grand 
addGap()568ddde725dSArmin Le Grand         void SvgCharacterNode::addGap()
569ddde725dSArmin Le Grand         {
570ddde725dSArmin Le Grand             maText += rtl::OUString(sal_Unicode(' '));
571ddde725dSArmin Le Grand         }
572ddde725dSArmin Le Grand 
concatenate(const rtl::OUString & rText)573ddde725dSArmin Le Grand         void SvgCharacterNode::concatenate(const rtl::OUString& rText)
574ddde725dSArmin Le Grand         {
575ddde725dSArmin Le Grand             maText += rText;
576ddde725dSArmin Le Grand         }
577ddde725dSArmin Le Grand 
decomposeText(drawinglayer::primitive2d::Primitive2DSequence & rTarget,SvgTextPosition & rSvgTextPosition) const578ddde725dSArmin Le Grand         void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const
579ddde725dSArmin Le Grand         {
580ddde725dSArmin Le Grand             if(getText().getLength())
581ddde725dSArmin Le Grand             {
582ddde725dSArmin Le Grand                 const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes();
583ddde725dSArmin Le Grand 
584ddde725dSArmin Le Grand                 if(pSvgStyleAttributes)
585ddde725dSArmin Le Grand                 {
586ddde725dSArmin Le Grand                     decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes);
587ddde725dSArmin Le Grand                 }
588ddde725dSArmin Le Grand             }
589ddde725dSArmin Le Grand         }
590ddde725dSArmin Le Grand 
591ddde725dSArmin Le Grand     } // end of namespace svgreader
592ddde725dSArmin Le Grand } // end of namespace svgio
593ddde725dSArmin Le Grand 
594ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
595ddde725dSArmin Le Grand 
596ddde725dSArmin Le Grand namespace svgio
597ddde725dSArmin Le Grand {
598ddde725dSArmin Le Grand     namespace svgreader
599ddde725dSArmin Le Grand     {
SvgTextPosition(SvgTextPosition * pParent,const InfoProvider & rInfoProvider,const SvgTextPositions & rSvgTextPositions)600ddde725dSArmin Le Grand         SvgTextPosition::SvgTextPosition(
601ddde725dSArmin Le Grand             SvgTextPosition* pParent,
602ddde725dSArmin Le Grand             const InfoProvider& rInfoProvider,
603ddde725dSArmin Le Grand             const SvgTextPositions& rSvgTextPositions)
604ddde725dSArmin Le Grand         :   mpParent(pParent),
605ddde725dSArmin Le Grand             maX(), // computed below
606ddde725dSArmin Le Grand             maY(), // computed below
607ddde725dSArmin Le Grand             maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)),
608ddde725dSArmin Le Grand             mfTextLength(0.0),
609ddde725dSArmin Le Grand             maPosition(), // computed below
610ddde725dSArmin Le Grand             mnRotationIndex(0),
611ddde725dSArmin Le Grand             mbLengthAdjust(rSvgTextPositions.getLengthAdjust()),
612ddde725dSArmin Le Grand             mbAbsoluteX(false),
613ddde725dSArmin Le Grand             mbAbsoluteY(false)
614ddde725dSArmin Le Grand         {
615ddde725dSArmin Le Grand             // get TextLength if provided
616ddde725dSArmin Le Grand             if(rSvgTextPositions.getTextLength().isSet())
617ddde725dSArmin Le Grand             {
618ddde725dSArmin Le Grand                 mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length);
619ddde725dSArmin Le Grand             }
620ddde725dSArmin Le Grand 
621ddde725dSArmin Le Grand             // SVG does not really define in which units a �rotate� for Text/TSpan is given,
622ddde725dSArmin Le Grand             // but it seems to be degrees. Convert here to radians
623ddde725dSArmin Le Grand             if(!maRotate.empty())
624ddde725dSArmin Le Grand             {
625ddde725dSArmin Le Grand                 const double fFactor(F_PI / 180.0);
626ddde725dSArmin Le Grand 
627ddde725dSArmin Le Grand                 for(sal_uInt32 a(0); a < maRotate.size(); a++)
628ddde725dSArmin Le Grand                 {
629ddde725dSArmin Le Grand                     maRotate[a] *= fFactor;
630ddde725dSArmin Le Grand                 }
631ddde725dSArmin Le Grand             }
632ddde725dSArmin Le Grand 
633ddde725dSArmin Le Grand             // get text positions X
634ddde725dSArmin Le Grand             const sal_uInt32 nSizeX(rSvgTextPositions.getX().size());
635ddde725dSArmin Le Grand 
636ddde725dSArmin Le Grand             if(nSizeX)
637ddde725dSArmin Le Grand             {
638ddde725dSArmin Le Grand                 // we have absolute positions, get first one as current text position X
639ddde725dSArmin Le Grand                 maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate));
640ddde725dSArmin Le Grand                 mbAbsoluteX = true;
641ddde725dSArmin Le Grand 
642ddde725dSArmin Le Grand                 if(nSizeX > 1)
643ddde725dSArmin Le Grand                 {
644ddde725dSArmin Le Grand                     // fill deltas to maX
645ddde725dSArmin Le Grand                     maX.reserve(nSizeX);
646ddde725dSArmin Le Grand 
647ddde725dSArmin Le Grand                     for(sal_uInt32 a(1); a < nSizeX; a++)
648ddde725dSArmin Le Grand                     {
649ddde725dSArmin Le Grand                         maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX());
650ddde725dSArmin Le Grand                     }
651ddde725dSArmin Le Grand                 }
652ddde725dSArmin Le Grand             }
653ddde725dSArmin Le Grand             else
654ddde725dSArmin Le Grand             {
655ddde725dSArmin Le Grand                 // no absolute position, get from parent
656ddde725dSArmin Le Grand                 if(pParent)
657ddde725dSArmin Le Grand                 {
658ddde725dSArmin Le Grand                     maPosition.setX(pParent->getPosition().getX());
659ddde725dSArmin Le Grand                 }
660ddde725dSArmin Le Grand 
661ddde725dSArmin Le Grand                 const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size());
662ddde725dSArmin Le Grand 
663ddde725dSArmin Le Grand                 if(nSizeDx)
664ddde725dSArmin Le Grand                 {
665ddde725dSArmin Le Grand                     // relative positions given, translate position derived from parent
666ddde725dSArmin Le Grand                     maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate));
667ddde725dSArmin Le Grand 
668ddde725dSArmin Le Grand                     if(nSizeDx > 1)
669ddde725dSArmin Le Grand                     {
670ddde725dSArmin Le Grand                         // fill deltas to maX
671ddde725dSArmin Le Grand                         maX.reserve(nSizeDx);
672ddde725dSArmin Le Grand 
673ddde725dSArmin Le Grand                         for(sal_uInt32 a(1); a < nSizeDx; a++)
674ddde725dSArmin Le Grand                         {
675ddde725dSArmin Le Grand                             maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate));
676ddde725dSArmin Le Grand                         }
677ddde725dSArmin Le Grand                     }
678ddde725dSArmin Le Grand                 }
679ddde725dSArmin Le Grand             }
680ddde725dSArmin Le Grand 
681ddde725dSArmin Le Grand             // get text positions Y
682ddde725dSArmin Le Grand             const sal_uInt32 nSizeY(rSvgTextPositions.getY().size());
683ddde725dSArmin Le Grand 
684ddde725dSArmin Le Grand             if(nSizeY)
685ddde725dSArmin Le Grand             {
686ddde725dSArmin Le Grand                 // we have absolute positions, get first one as current text position Y
687ddde725dSArmin Le Grand                 maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate));
688ddde725dSArmin Le Grand                 mbAbsoluteX = true;
689ddde725dSArmin Le Grand 
690ddde725dSArmin Le Grand                 if(nSizeY > 1)
691ddde725dSArmin Le Grand                 {
692ddde725dSArmin Le Grand                     // fill deltas to maY
693ddde725dSArmin Le Grand                     maY.reserve(nSizeY);
694ddde725dSArmin Le Grand 
695ddde725dSArmin Le Grand                     for(sal_uInt32 a(1); a < nSizeY; a++)
696ddde725dSArmin Le Grand                     {
697ddde725dSArmin Le Grand                         maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY());
698ddde725dSArmin Le Grand                     }
699ddde725dSArmin Le Grand                 }
700ddde725dSArmin Le Grand             }
701ddde725dSArmin Le Grand             else
702ddde725dSArmin Le Grand             {
703ddde725dSArmin Le Grand                 // no absolute position, get from parent
704ddde725dSArmin Le Grand                 if(pParent)
705ddde725dSArmin Le Grand                 {
706ddde725dSArmin Le Grand                     maPosition.setY(pParent->getPosition().getY());
707ddde725dSArmin Le Grand                 }
708ddde725dSArmin Le Grand 
709ddde725dSArmin Le Grand                 const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size());
710ddde725dSArmin Le Grand 
711ddde725dSArmin Le Grand                 if(nSizeDy)
712ddde725dSArmin Le Grand                 {
713ddde725dSArmin Le Grand                     // relative positions given, translate position derived from parent
714ddde725dSArmin Le Grand                     maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate));
715ddde725dSArmin Le Grand 
716ddde725dSArmin Le Grand                     if(nSizeDy > 1)
717ddde725dSArmin Le Grand                     {
718ddde725dSArmin Le Grand                         // fill deltas to maY
719ddde725dSArmin Le Grand                         maY.reserve(nSizeDy);
720ddde725dSArmin Le Grand 
721ddde725dSArmin Le Grand                         for(sal_uInt32 a(1); a < nSizeDy; a++)
722ddde725dSArmin Le Grand                         {
723ddde725dSArmin Le Grand                             maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate));
724ddde725dSArmin Le Grand                         }
725ddde725dSArmin Le Grand                     }
726ddde725dSArmin Le Grand                 }
727ddde725dSArmin Le Grand             }
728ddde725dSArmin Le Grand         }
729ddde725dSArmin Le Grand 
isRotated() const730ddde725dSArmin Le Grand         bool SvgTextPosition::isRotated() const
731ddde725dSArmin Le Grand         {
732ddde725dSArmin Le Grand             if(maRotate.empty())
733ddde725dSArmin Le Grand             {
734ddde725dSArmin Le Grand                 if(getParent())
735ddde725dSArmin Le Grand                 {
736ddde725dSArmin Le Grand                     return getParent()->isRotated();
737ddde725dSArmin Le Grand                 }
738ddde725dSArmin Le Grand                 else
739ddde725dSArmin Le Grand                 {
740ddde725dSArmin Le Grand                     return false;
741ddde725dSArmin Le Grand                 }
742ddde725dSArmin Le Grand             }
743ddde725dSArmin Le Grand             else
744ddde725dSArmin Le Grand             {
745ddde725dSArmin Le Grand                 return true;
746ddde725dSArmin Le Grand             }
747ddde725dSArmin Le Grand         }
748ddde725dSArmin Le Grand 
consumeRotation()749ddde725dSArmin Le Grand         double SvgTextPosition::consumeRotation()
750ddde725dSArmin Le Grand         {
751ddde725dSArmin Le Grand             double fRetval(0.0);
752ddde725dSArmin Le Grand 
753ddde725dSArmin Le Grand             if(maRotate.empty())
754ddde725dSArmin Le Grand             {
755ddde725dSArmin Le Grand                 if(getParent())
756ddde725dSArmin Le Grand                 {
757ddde725dSArmin Le Grand                     fRetval = mpParent->consumeRotation();
758ddde725dSArmin Le Grand                 }
759ddde725dSArmin Le Grand                 else
760ddde725dSArmin Le Grand                 {
761ddde725dSArmin Le Grand                     fRetval = 0.0;
762ddde725dSArmin Le Grand                 }
763ddde725dSArmin Le Grand             }
764ddde725dSArmin Le Grand             else
765ddde725dSArmin Le Grand             {
766ddde725dSArmin Le Grand                 const sal_uInt32 nSize(maRotate.size());
767ddde725dSArmin Le Grand 
768ddde725dSArmin Le Grand                 if(mnRotationIndex < nSize)
769ddde725dSArmin Le Grand                 {
770ddde725dSArmin Le Grand                     fRetval = maRotate[mnRotationIndex++];
771ddde725dSArmin Le Grand                 }
772ddde725dSArmin Le Grand                 else
773ddde725dSArmin Le Grand                 {
774ddde725dSArmin Le Grand                     fRetval = maRotate[nSize - 1];
775ddde725dSArmin Le Grand                 }
776ddde725dSArmin Le Grand             }
777ddde725dSArmin Le Grand 
778ddde725dSArmin Le Grand             return fRetval;
779ddde725dSArmin Le Grand         }
780ddde725dSArmin Le Grand 
781ddde725dSArmin Le Grand     } // end of namespace svgreader
782ddde725dSArmin Le Grand } // end of namespace svgio
783ddde725dSArmin Le Grand 
784ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
785ddde725dSArmin Le Grand // eof
786