| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svgio.hxx" |
| |
| #include <svgio/svgreader/svgcharacternode.hxx> |
| #include <svgio/svgreader/svgstyleattributes.hxx> |
| #include <drawinglayer/attribute/fontattribute.hxx> |
| #include <drawinglayer/primitive2d/textprimitive2d.hxx> |
| #include <drawinglayer/primitive2d/textlayoutdevice.hxx> |
| #include <drawinglayer/primitive2d/textbreakuphelper.hxx> |
| #include <drawinglayer/primitive2d/groupprimitive2d.hxx> |
| #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace svgio |
| { |
| namespace svgreader |
| { |
| SvgTextPositions::SvgTextPositions() |
| : maX(), |
| maY(), |
| maDx(), |
| maDy(), |
| maRotate(), |
| maTextLength(), |
| mbLengthAdjust(true) |
| { |
| } |
| |
| void SvgTextPositions::parseTextPositionAttributes(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) |
| { |
| // parse own |
| switch(aSVGToken) |
| { |
| case SVGTokenX: |
| { |
| if(aContent.getLength()) |
| { |
| SvgNumberVector aVector; |
| |
| if(readSvgNumberVector(aContent, aVector)) |
| { |
| setX(aVector); |
| } |
| } |
| break; |
| } |
| case SVGTokenY: |
| { |
| if(aContent.getLength()) |
| { |
| SvgNumberVector aVector; |
| |
| if(readSvgNumberVector(aContent, aVector)) |
| { |
| setY(aVector); |
| } |
| } |
| break; |
| } |
| case SVGTokenDx: |
| { |
| if(aContent.getLength()) |
| { |
| SvgNumberVector aVector; |
| |
| if(readSvgNumberVector(aContent, aVector)) |
| { |
| setDx(aVector); |
| } |
| } |
| break; |
| } |
| case SVGTokenDy: |
| { |
| if(aContent.getLength()) |
| { |
| SvgNumberVector aVector; |
| |
| if(readSvgNumberVector(aContent, aVector)) |
| { |
| setDy(aVector); |
| } |
| } |
| break; |
| } |
| case SVGTokenRotate: |
| { |
| if(aContent.getLength()) |
| { |
| SvgNumberVector aVector; |
| |
| if(readSvgNumberVector(aContent, aVector)) |
| { |
| setRotate(aVector); |
| } |
| } |
| break; |
| } |
| case SVGTokenTextLength: |
| { |
| SvgNumber aNum; |
| |
| if(readSingleNumber(aContent, aNum)) |
| { |
| if(aNum.isPositive()) |
| { |
| setTextLength(aNum); |
| } |
| } |
| break; |
| } |
| case SVGTokenLengthAdjust: |
| { |
| if(aContent.getLength()) |
| { |
| static rtl::OUString aStrSpacing(rtl::OUString::createFromAscii("spacing")); |
| static rtl::OUString aStrSpacingAndGlyphs(rtl::OUString::createFromAscii("spacingAndGlyphs")); |
| |
| if(aContent.match(aStrSpacing)) |
| { |
| setLengthAdjust(true); |
| } |
| else if(aContent.match(aStrSpacingAndGlyphs)) |
| { |
| setLengthAdjust(false); |
| } |
| } |
| break; |
| } |
| default: |
| { |
| break; |
| } |
| } |
| } |
| |
| } // end of namespace svgreader |
| } // end of namespace svgio |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace svgio |
| { |
| namespace svgreader |
| { |
| class localTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper |
| { |
| private: |
| SvgTextPosition& mrSvgTextPosition; |
| |
| protected: |
| /// allow user callback to allow changes to the new TextTransformation. Default |
| /// does nothing. |
| virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength); |
| |
| public: |
| localTextBreakupHelper( |
| const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource, |
| SvgTextPosition& rSvgTextPosition) |
| : drawinglayer::primitive2d::TextBreakupHelper(rSource), |
| mrSvgTextPosition(rSvgTextPosition) |
| { |
| } |
| }; |
| |
| bool localTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/) |
| { |
| const double fRotation(mrSvgTextPosition.consumeRotation()); |
| |
| if(0.0 != fRotation) |
| { |
| const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0)); |
| |
| rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY()); |
| rNewTransform.rotate(fRotation); |
| rNewTransform.translate(aBasePoint.getX(), aBasePoint.getY()); |
| } |
| |
| return true; |
| } |
| |
| } // end of namespace svgreader |
| } // end of namespace svgio |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace svgio |
| { |
| namespace svgreader |
| { |
| SvgCharacterNode::SvgCharacterNode( |
| SvgDocument& rDocument, |
| SvgNode* pParent, |
| const rtl::OUString& rText) |
| : SvgNode(SVGTokenCharacter, rDocument, pParent), |
| maText(rText) |
| { |
| } |
| |
| SvgCharacterNode::~SvgCharacterNode() |
| { |
| } |
| |
| const SvgStyleAttributes* SvgCharacterNode::getSvgStyleAttributes() const |
| { |
| // no own style, use parent's |
| if(getParent()) |
| { |
| return getParent()->getSvgStyleAttributes(); |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| drawinglayer::primitive2d::TextSimplePortionPrimitive2D* SvgCharacterNode::createSimpleTextPrimitive( |
| SvgTextPosition& rSvgTextPosition, |
| const SvgStyleAttributes& rSvgStyleAttributes) const |
| { |
| // prepare retval, index and length |
| drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pRetval = 0; |
| sal_uInt32 nIndex(0); |
| sal_uInt32 nLength(getText().getLength()); |
| |
| if(nLength) |
| { |
| // prepare FontAttribute |
| rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ? |
| rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) : |
| rSvgStyleAttributes.getFontFamily()[0]; |
| |
| // #122324# if the FontFamily name ends on ' embedded' it is probably a re-import |
| // of a SVG export with fiont embedding. Remove this to make font matching work. This |
| // is pretty safe since there should be no font family names ending on ' embedded'. |
| // Remove again when FontEmbedding is implemented in SVG import |
| if(aFontFamily.endsWithAsciiL(" embedded", 9)) |
| { |
| aFontFamily = aFontFamily.copy(0, aFontFamily.getLength() - 9); |
| } |
| |
| const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight())); |
| bool bSymbol(false); |
| bool bVertical(false); |
| bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle()); |
| bool bMonospaced(false); |
| bool bOutline(false); |
| bool bRTL(false); |
| bool bBiDiStrong(false); |
| |
| const drawinglayer::attribute::FontAttribute aFontAttribute( |
| aFontFamily, |
| rtl::OUString(), |
| nFontWeight, |
| bSymbol, |
| bVertical, |
| bItalic, |
| bMonospaced, |
| bOutline, |
| bRTL, |
| bBiDiStrong); |
| |
| // prepare FontSize |
| double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length)); |
| double fFontHeight(fFontWidth); |
| |
| // prepare locale |
| ::com::sun::star::lang::Locale aLocale; |
| |
| // prepare TextLayouterDevice |
| drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; |
| aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale); |
| |
| // prepare TextArray |
| ::std::vector< double > aTextArray(rSvgTextPosition.getX()); |
| |
| if(!aTextArray.empty() && aTextArray.size() < nLength) |
| { |
| const sal_uInt32 nArray(aTextArray.size()); |
| |
| if(nArray < nLength) |
| { |
| double fStartX(0.0); |
| |
| if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX()) |
| { |
| fStartX = rSvgTextPosition.getParent()->getPosition().getX(); |
| } |
| else |
| { |
| fStartX = aTextArray[nArray - 1]; |
| } |
| |
| ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray)); |
| aTextArray.reserve(nLength); |
| |
| for(sal_uInt32 a(0); a < aExtendArray.size(); a++) |
| { |
| aTextArray.push_back(aExtendArray[a] + fStartX); |
| } |
| } |
| } |
| |
| // get current TextPosition and TextWidth in units |
| basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition()); |
| double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength)); |
| |
| // check for user-given TextLength |
| if(0.0 != rSvgTextPosition.getTextLength() |
| && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength())) |
| { |
| const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth); |
| |
| if(rSvgTextPosition.getLengthAdjust()) |
| { |
| // spacing, need to create and expand TextArray |
| if(aTextArray.empty()) |
| { |
| aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength); |
| } |
| |
| for(sal_uInt32 a(0); a < aTextArray.size(); a++) |
| { |
| aTextArray[a] *= fFactor; |
| } |
| } |
| else |
| { |
| // spacing and glyphs, just apply to FontWidth |
| fFontWidth *= fFactor; |
| } |
| |
| fTextWidth = rSvgTextPosition.getTextLength(); |
| } |
| |
| // get TextAlign |
| TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign()); |
| |
| // map TextAnchor to TextAlign, there seems not to be a difference |
| if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor()) |
| { |
| switch(rSvgStyleAttributes.getTextAnchor()) |
| { |
| case TextAnchor_start: |
| { |
| aTextAlign = TextAlign_left; |
| break; |
| } |
| case TextAnchor_middle: |
| { |
| aTextAlign = TextAlign_center; |
| break; |
| } |
| case TextAnchor_end: |
| { |
| aTextAlign = TextAlign_right; |
| break; |
| } |
| default: |
| { |
| break; |
| } |
| } |
| } |
| |
| // apply TextAlign |
| switch(aTextAlign) |
| { |
| case TextAlign_right: |
| { |
| aPosition.setX(aPosition.getX() - fTextWidth); |
| break; |
| } |
| case TextAlign_center: |
| { |
| aPosition.setX(aPosition.getX() - (fTextWidth * 0.5)); |
| break; |
| } |
| case TextAlign_notset: |
| case TextAlign_left: |
| case TextAlign_justify: |
| { |
| // TextAlign_notset, TextAlign_left: nothing to do |
| // TextAlign_justify is not clear currently; handle as TextAlign_left |
| break; |
| } |
| } |
| |
| // get BaselineShift |
| const BaselineShift aBaselineShift(rSvgStyleAttributes.getBaselineShift()); |
| |
| // apply BaselineShift |
| switch(aBaselineShift) |
| { |
| case BaselineShift_Sub: |
| { |
| aPosition.setY(aPosition.getY() + aTextLayouterDevice.getUnderlineOffset()); |
| break; |
| } |
| case BaselineShift_Super: |
| { |
| aPosition.setY(aPosition.getY() + aTextLayouterDevice.getOverlineOffset()); |
| break; |
| } |
| case BaselineShift_Percentage: |
| case BaselineShift_Length: |
| { |
| const SvgNumber aNumber(rSvgStyleAttributes.getBaselineShiftNumber()); |
| const double mfBaselineShift(aNumber.solve(*this, length)); |
| |
| aPosition.setY(aPosition.getY() + mfBaselineShift); |
| break; |
| } |
| default: // BaselineShift_Baseline |
| { |
| // nothing to do |
| break; |
| } |
| } |
| |
| // get fill color |
| const basegfx::BColor aFill(rSvgStyleAttributes.getFill() |
| ? *rSvgStyleAttributes.getFill() |
| : basegfx::BColor(0.0, 0.0, 0.0)); |
| |
| // prepare TextTransformation |
| basegfx::B2DHomMatrix aTextTransform; |
| |
| aTextTransform.scale(fFontWidth, fFontHeight); |
| aTextTransform.translate(aPosition.getX(), aPosition.getY()); |
| |
| // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed |
| const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration()); |
| |
| if(TextDecoration_underline == aDeco |
| || TextDecoration_overline == aDeco |
| || TextDecoration_line_through == aDeco) |
| { |
| // get the fill for decroation as described by SVG. We cannot |
| // have different stroke colors/definitions for those, though |
| const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes(); |
| const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill); |
| |
| // create decorated text primitive |
| pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D( |
| aTextTransform, |
| getText(), |
| nIndex, |
| nLength, |
| aTextArray, |
| aFontAttribute, |
| aLocale, |
| aFill, |
| |
| // extra props for decorated |
| aDecoColor, |
| aDecoColor, |
| TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, |
| TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, |
| false, |
| TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE, |
| false, |
| drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE, |
| true, |
| false, |
| drawinglayer::primitive2d::TEXT_RELIEF_NONE, |
| false); |
| } |
| else |
| { |
| // create text primitive |
| pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( |
| aTextTransform, |
| getText(), |
| nIndex, |
| nLength, |
| aTextArray, |
| aFontAttribute, |
| aLocale, |
| aFill); |
| } |
| |
| // advance current TextPosition |
| rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0)); |
| } |
| |
| return pRetval; |
| } |
| |
| void SvgCharacterNode::decomposeTextWithStyle( |
| drawinglayer::primitive2d::Primitive2DSequence& rTarget, |
| SvgTextPosition& rSvgTextPosition, |
| const SvgStyleAttributes& rSvgStyleAttributes) const |
| { |
| const drawinglayer::primitive2d::Primitive2DReference xRef( |
| createSimpleTextPrimitive( |
| rSvgTextPosition, |
| rSvgStyleAttributes)); |
| |
| if(xRef.is()) |
| { |
| if(!rSvgTextPosition.isRotated()) |
| { |
| drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); |
| } |
| else |
| { |
| // need to apply rotations to each character as given |
| const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = |
| dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get()); |
| |
| if(pCandidate) |
| { |
| const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition); |
| const drawinglayer::primitive2d::Primitive2DSequence aResult( |
| alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character)); |
| |
| if(aResult.hasElements()) |
| { |
| drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult); |
| } |
| |
| // also consume for the implied single space |
| rSvgTextPosition.consumeRotation(); |
| } |
| else |
| { |
| OSL_ENSURE(false, "Used primitive is not a text primitive (!)"); |
| } |
| } |
| } |
| } |
| |
| void SvgCharacterNode::whiteSpaceHandling() |
| { |
| if(XmlSpace_default == getXmlSpace()) |
| { |
| maText = whiteSpaceHandlingDefault(maText); |
| } |
| else |
| { |
| maText = whiteSpaceHandlingPreserve(maText); |
| } |
| } |
| |
| void SvgCharacterNode::addGap() |
| { |
| maText += rtl::OUString(sal_Unicode(' ')); |
| } |
| |
| void SvgCharacterNode::concatenate(const rtl::OUString& rText) |
| { |
| maText += rText; |
| } |
| |
| void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const |
| { |
| if(getText().getLength()) |
| { |
| const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes(); |
| |
| if(pSvgStyleAttributes) |
| { |
| decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes); |
| } |
| } |
| } |
| |
| } // end of namespace svgreader |
| } // end of namespace svgio |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace svgio |
| { |
| namespace svgreader |
| { |
| SvgTextPosition::SvgTextPosition( |
| SvgTextPosition* pParent, |
| const InfoProvider& rInfoProvider, |
| const SvgTextPositions& rSvgTextPositions) |
| : mpParent(pParent), |
| maX(), // computed below |
| maY(), // computed below |
| maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)), |
| mfTextLength(0.0), |
| maPosition(), // computed below |
| mnRotationIndex(0), |
| mbLengthAdjust(rSvgTextPositions.getLengthAdjust()), |
| mbAbsoluteX(false), |
| mbAbsoluteY(false) |
| { |
| // get TextLength if provided |
| if(rSvgTextPositions.getTextLength().isSet()) |
| { |
| mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length); |
| } |
| |
| // SVG does not really define in which units a rotate for Text/TSpan is given, |
| // but it seems to be degrees. Convert here to radians |
| if(!maRotate.empty()) |
| { |
| const double fFactor(F_PI / 180.0); |
| |
| for(sal_uInt32 a(0); a < maRotate.size(); a++) |
| { |
| maRotate[a] *= fFactor; |
| } |
| } |
| |
| // get text positions X |
| const sal_uInt32 nSizeX(rSvgTextPositions.getX().size()); |
| |
| if(nSizeX) |
| { |
| // we have absolute positions, get first one as current text position X |
| maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate)); |
| mbAbsoluteX = true; |
| |
| if(nSizeX > 1) |
| { |
| // fill deltas to maX |
| maX.reserve(nSizeX); |
| |
| for(sal_uInt32 a(1); a < nSizeX; a++) |
| { |
| maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX()); |
| } |
| } |
| } |
| else |
| { |
| // no absolute position, get from parent |
| if(pParent) |
| { |
| maPosition.setX(pParent->getPosition().getX()); |
| } |
| |
| const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size()); |
| |
| if(nSizeDx) |
| { |
| // relative positions given, translate position derived from parent |
| maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate)); |
| |
| if(nSizeDx > 1) |
| { |
| // fill deltas to maX |
| maX.reserve(nSizeDx); |
| |
| for(sal_uInt32 a(1); a < nSizeDx; a++) |
| { |
| maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate)); |
| } |
| } |
| } |
| } |
| |
| // get text positions Y |
| const sal_uInt32 nSizeY(rSvgTextPositions.getY().size()); |
| |
| if(nSizeY) |
| { |
| // we have absolute positions, get first one as current text position Y |
| maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate)); |
| mbAbsoluteX = true; |
| |
| if(nSizeY > 1) |
| { |
| // fill deltas to maY |
| maY.reserve(nSizeY); |
| |
| for(sal_uInt32 a(1); a < nSizeY; a++) |
| { |
| maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY()); |
| } |
| } |
| } |
| else |
| { |
| // no absolute position, get from parent |
| if(pParent) |
| { |
| maPosition.setY(pParent->getPosition().getY()); |
| } |
| |
| const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size()); |
| |
| if(nSizeDy) |
| { |
| // relative positions given, translate position derived from parent |
| maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate)); |
| |
| if(nSizeDy > 1) |
| { |
| // fill deltas to maY |
| maY.reserve(nSizeDy); |
| |
| for(sal_uInt32 a(1); a < nSizeDy; a++) |
| { |
| maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate)); |
| } |
| } |
| } |
| } |
| } |
| |
| bool SvgTextPosition::isRotated() const |
| { |
| if(maRotate.empty()) |
| { |
| if(getParent()) |
| { |
| return getParent()->isRotated(); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| else |
| { |
| return true; |
| } |
| } |
| |
| double SvgTextPosition::consumeRotation() |
| { |
| double fRetval(0.0); |
| |
| if(maRotate.empty()) |
| { |
| if(getParent()) |
| { |
| fRetval = mpParent->consumeRotation(); |
| } |
| else |
| { |
| fRetval = 0.0; |
| } |
| } |
| else |
| { |
| const sal_uInt32 nSize(maRotate.size()); |
| |
| if(mnRotationIndex < nSize) |
| { |
| fRetval = maRotate[mnRotationIndex++]; |
| } |
| else |
| { |
| fRetval = maRotate[nSize - 1]; |
| } |
| } |
| |
| return fRetval; |
| } |
| |
| } // end of namespace svgreader |
| } // end of namespace svgio |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // eof |