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