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