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