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