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