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( 180693be7f6SArmin Le Grand const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource, 181ddde725dSArmin Le Grand SvgTextPosition& rSvgTextPosition) 182693be7f6SArmin 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 251*861dea5cSArmin Le Grand rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ? 252ddde725dSArmin Le Grand rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) : 253ddde725dSArmin Le Grand rSvgStyleAttributes.getFontFamily()[0]; 254*861dea5cSArmin Le Grand 255*861dea5cSArmin Le Grand // #122324# if the FontFamily name ends on ' embedded' it is probably a re-import 256*861dea5cSArmin Le Grand // of a SVG export with fiont embedding. Remove this to make font matching work. This 257*861dea5cSArmin Le Grand // is pretty safe since there should be no font family names ending on ' embedded'. 258*861dea5cSArmin Le Grand // Remove again when FontEmbedding is implemented in SVG import 259*861dea5cSArmin Le Grand if(aFontFamily.endsWithAsciiL(" embedded", 9)) 260*861dea5cSArmin Le Grand { 261*861dea5cSArmin Le Grand aFontFamily = aFontFamily.copy(0, aFontFamily.getLength() - 9); 262*861dea5cSArmin Le Grand } 263*861dea5cSArmin Le Grand 264ddde725dSArmin Le Grand const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight())); 265ddde725dSArmin Le Grand bool bSymbol(false); 266ddde725dSArmin Le Grand bool bVertical(false); 267ddde725dSArmin Le Grand bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle()); 268ddde725dSArmin Le Grand bool bMonospaced(false); 269ddde725dSArmin Le Grand bool bOutline(false); 270ddde725dSArmin Le Grand bool bRTL(false); 271ddde725dSArmin Le Grand bool bBiDiStrong(false); 272ddde725dSArmin Le Grand 273ddde725dSArmin Le Grand const drawinglayer::attribute::FontAttribute aFontAttribute( 274ddde725dSArmin Le Grand aFontFamily, 275ddde725dSArmin Le Grand rtl::OUString(), 276ddde725dSArmin Le Grand nFontWeight, 277ddde725dSArmin Le Grand bSymbol, 278ddde725dSArmin Le Grand bVertical, 279ddde725dSArmin Le Grand bItalic, 280ddde725dSArmin Le Grand bMonospaced, 281ddde725dSArmin Le Grand bOutline, 282ddde725dSArmin Le Grand bRTL, 283ddde725dSArmin Le Grand bBiDiStrong); 284ddde725dSArmin Le Grand 285ddde725dSArmin Le Grand // prepare FontSize 286ddde725dSArmin Le Grand double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length)); 287ddde725dSArmin Le Grand double fFontHeight(fFontWidth); 288ddde725dSArmin Le Grand 289ddde725dSArmin Le Grand // prepare locale 290ddde725dSArmin Le Grand ::com::sun::star::lang::Locale aLocale; 291ddde725dSArmin Le Grand 292ddde725dSArmin Le Grand // prepare TextLayouterDevice 293ddde725dSArmin Le Grand drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; 294ddde725dSArmin Le Grand aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale); 295ddde725dSArmin Le Grand 296ddde725dSArmin Le Grand // prepare TextArray 297ddde725dSArmin Le Grand ::std::vector< double > aTextArray(rSvgTextPosition.getX()); 298ddde725dSArmin Le Grand 299ddde725dSArmin Le Grand if(!aTextArray.empty() && aTextArray.size() < nLength) 300ddde725dSArmin Le Grand { 301ddde725dSArmin Le Grand const sal_uInt32 nArray(aTextArray.size()); 302ddde725dSArmin Le Grand 303ddde725dSArmin Le Grand if(nArray < nLength) 304ddde725dSArmin Le Grand { 305ddde725dSArmin Le Grand double fStartX(0.0); 306ddde725dSArmin Le Grand 307ddde725dSArmin Le Grand if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX()) 308ddde725dSArmin Le Grand { 309ddde725dSArmin Le Grand fStartX = rSvgTextPosition.getParent()->getPosition().getX(); 310ddde725dSArmin Le Grand } 311ddde725dSArmin Le Grand else 312ddde725dSArmin Le Grand { 313ddde725dSArmin Le Grand fStartX = aTextArray[nArray - 1]; 314ddde725dSArmin Le Grand } 315ddde725dSArmin Le Grand 316ddde725dSArmin Le Grand ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray)); 317ddde725dSArmin Le Grand aTextArray.reserve(nLength); 318ddde725dSArmin Le Grand 319ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < aExtendArray.size(); a++) 320ddde725dSArmin Le Grand { 321ddde725dSArmin Le Grand aTextArray.push_back(aExtendArray[a] + fStartX); 322ddde725dSArmin Le Grand } 323ddde725dSArmin Le Grand } 324ddde725dSArmin Le Grand } 325ddde725dSArmin Le Grand 326ddde725dSArmin Le Grand // get current TextPosition and TextWidth in units 327ddde725dSArmin Le Grand basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition()); 328ddde725dSArmin Le Grand double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength)); 329ddde725dSArmin Le Grand 330ddde725dSArmin Le Grand // check for user-given TextLength 331ddde725dSArmin Le Grand if(0.0 != rSvgTextPosition.getTextLength() 332ddde725dSArmin Le Grand && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength())) 333ddde725dSArmin Le Grand { 334ddde725dSArmin Le Grand const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth); 335ddde725dSArmin Le Grand 336ddde725dSArmin Le Grand if(rSvgTextPosition.getLengthAdjust()) 337ddde725dSArmin Le Grand { 338ddde725dSArmin Le Grand // spacing, need to create and expand TextArray 339ddde725dSArmin Le Grand if(aTextArray.empty()) 340ddde725dSArmin Le Grand { 341ddde725dSArmin Le Grand aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength); 342ddde725dSArmin Le Grand } 343ddde725dSArmin Le Grand 344ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < aTextArray.size(); a++) 345ddde725dSArmin Le Grand { 346ddde725dSArmin Le Grand aTextArray[a] *= fFactor; 347ddde725dSArmin Le Grand } 348ddde725dSArmin Le Grand } 349ddde725dSArmin Le Grand else 350ddde725dSArmin Le Grand { 351ddde725dSArmin Le Grand // spacing and glyphs, just apply to FontWidth 352ddde725dSArmin Le Grand fFontWidth *= fFactor; 353ddde725dSArmin Le Grand } 354ddde725dSArmin Le Grand 355ddde725dSArmin Le Grand fTextWidth = rSvgTextPosition.getTextLength(); 356ddde725dSArmin Le Grand } 357ddde725dSArmin Le Grand 358ddde725dSArmin Le Grand // get TextAlign 359ddde725dSArmin Le Grand TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign()); 360ddde725dSArmin Le Grand 361ddde725dSArmin Le Grand // map TextAnchor to TextAlign, there seems not to be a difference 362ddde725dSArmin Le Grand if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor()) 363ddde725dSArmin Le Grand { 364ddde725dSArmin Le Grand switch(rSvgStyleAttributes.getTextAnchor()) 365ddde725dSArmin Le Grand { 366ddde725dSArmin Le Grand case TextAnchor_start: 367ddde725dSArmin Le Grand { 368ddde725dSArmin Le Grand aTextAlign = TextAlign_left; 369ddde725dSArmin Le Grand break; 370ddde725dSArmin Le Grand } 371ddde725dSArmin Le Grand case TextAnchor_middle: 372ddde725dSArmin Le Grand { 373ddde725dSArmin Le Grand aTextAlign = TextAlign_center; 374ddde725dSArmin Le Grand break; 375ddde725dSArmin Le Grand } 376ddde725dSArmin Le Grand case TextAnchor_end: 377ddde725dSArmin Le Grand { 378ddde725dSArmin Le Grand aTextAlign = TextAlign_right; 379ddde725dSArmin Le Grand break; 380ddde725dSArmin Le Grand } 381e2bf1e9dSArmin Le Grand default: 382e2bf1e9dSArmin Le Grand { 383e2bf1e9dSArmin Le Grand break; 384e2bf1e9dSArmin Le Grand } 385ddde725dSArmin Le Grand } 386ddde725dSArmin Le Grand } 387ddde725dSArmin Le Grand 388ddde725dSArmin Le Grand // apply TextAlign 389ddde725dSArmin Le Grand switch(aTextAlign) 390ddde725dSArmin Le Grand { 391ddde725dSArmin Le Grand case TextAlign_right: 392ddde725dSArmin Le Grand { 393ddde725dSArmin Le Grand aPosition.setX(aPosition.getX() - fTextWidth); 394ddde725dSArmin Le Grand break; 395ddde725dSArmin Le Grand } 396ddde725dSArmin Le Grand case TextAlign_center: 397ddde725dSArmin Le Grand { 398ddde725dSArmin Le Grand aPosition.setX(aPosition.getX() - (fTextWidth * 0.5)); 399ddde725dSArmin Le Grand break; 400ddde725dSArmin Le Grand } 401ddde725dSArmin Le Grand case TextAlign_notset: 402ddde725dSArmin Le Grand case TextAlign_left: 403ddde725dSArmin Le Grand case TextAlign_justify: 404ddde725dSArmin Le Grand { 405ddde725dSArmin Le Grand // TextAlign_notset, TextAlign_left: nothing to do 406ddde725dSArmin Le Grand // TextAlign_justify is not clear currently; handle as TextAlign_left 407ddde725dSArmin Le Grand break; 408ddde725dSArmin Le Grand } 409ddde725dSArmin Le Grand } 410ddde725dSArmin Le Grand 411ddde725dSArmin Le Grand // get fill color 412ddde725dSArmin Le Grand const basegfx::BColor aFill(rSvgStyleAttributes.getFill() 413ddde725dSArmin Le Grand ? *rSvgStyleAttributes.getFill() 414ddde725dSArmin Le Grand : basegfx::BColor(0.0, 0.0, 0.0)); 415ddde725dSArmin Le Grand 416ddde725dSArmin Le Grand // prepare TextTransformation 417ddde725dSArmin Le Grand basegfx::B2DHomMatrix aTextTransform; 418ddde725dSArmin Le Grand 419ddde725dSArmin Le Grand aTextTransform.scale(fFontWidth, fFontHeight); 420ddde725dSArmin Le Grand aTextTransform.translate(aPosition.getX(), aPosition.getY()); 421ddde725dSArmin Le Grand 422ddde725dSArmin Le Grand // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed 423ddde725dSArmin Le Grand const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration()); 424ddde725dSArmin Le Grand 425ddde725dSArmin Le Grand if(TextDecoration_underline == aDeco 426ddde725dSArmin Le Grand || TextDecoration_overline == aDeco 427ddde725dSArmin Le Grand || TextDecoration_line_through == aDeco) 428ddde725dSArmin Le Grand { 429ddde725dSArmin Le Grand // get the fill for decroation as described by SVG. We cannot 430ddde725dSArmin Le Grand // have different stroke colors/definitions for those, though 431ddde725dSArmin Le Grand const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes(); 432ddde725dSArmin Le Grand const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill); 433ddde725dSArmin Le Grand 434ddde725dSArmin Le Grand // create decorated text primitive 435ddde725dSArmin Le Grand pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D( 436ddde725dSArmin Le Grand aTextTransform, 437ddde725dSArmin Le Grand getText(), 438ddde725dSArmin Le Grand nIndex, 439ddde725dSArmin Le Grand nLength, 440ddde725dSArmin Le Grand aTextArray, 441ddde725dSArmin Le Grand aFontAttribute, 442ddde725dSArmin Le Grand aLocale, 443ddde725dSArmin Le Grand aFill, 444ddde725dSArmin Le Grand 445ddde725dSArmin Le Grand // extra props for decorated 446ddde725dSArmin Le Grand aDecoColor, 447ddde725dSArmin Le Grand aDecoColor, 448ddde725dSArmin Le Grand TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, 449ddde725dSArmin Le Grand TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, 450ddde725dSArmin Le Grand false, 451ddde725dSArmin Le Grand TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE, 452ddde725dSArmin Le Grand false, 453ddde725dSArmin Le Grand drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE, 454ddde725dSArmin Le Grand true, 455ddde725dSArmin Le Grand false, 456ddde725dSArmin Le Grand drawinglayer::primitive2d::TEXT_RELIEF_NONE, 457ddde725dSArmin Le Grand false); 458ddde725dSArmin Le Grand } 459ddde725dSArmin Le Grand else 460ddde725dSArmin Le Grand { 461ddde725dSArmin Le Grand // create text primitive 462ddde725dSArmin Le Grand pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( 463ddde725dSArmin Le Grand aTextTransform, 464ddde725dSArmin Le Grand getText(), 465ddde725dSArmin Le Grand nIndex, 466ddde725dSArmin Le Grand nLength, 467ddde725dSArmin Le Grand aTextArray, 468ddde725dSArmin Le Grand aFontAttribute, 469ddde725dSArmin Le Grand aLocale, 470ddde725dSArmin Le Grand aFill); 471ddde725dSArmin Le Grand } 472ddde725dSArmin Le Grand 473ddde725dSArmin Le Grand // advance current TextPosition 474ddde725dSArmin Le Grand rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0)); 475ddde725dSArmin Le Grand } 476ddde725dSArmin Le Grand 477ddde725dSArmin Le Grand return pRetval; 478ddde725dSArmin Le Grand } 479ddde725dSArmin Le Grand 480ddde725dSArmin Le Grand void SvgCharacterNode::decomposeTextWithStyle( 481ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence& rTarget, 482ddde725dSArmin Le Grand SvgTextPosition& rSvgTextPosition, 483ddde725dSArmin Le Grand const SvgStyleAttributes& rSvgStyleAttributes) const 484ddde725dSArmin Le Grand { 485ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 486ddde725dSArmin Le Grand createSimpleTextPrimitive( 487ddde725dSArmin Le Grand rSvgTextPosition, 488ddde725dSArmin Le Grand rSvgStyleAttributes)); 489ddde725dSArmin Le Grand 490ddde725dSArmin Le Grand if(xRef.is()) 491ddde725dSArmin Le Grand { 492ddde725dSArmin Le Grand if(!rSvgTextPosition.isRotated()) 493ddde725dSArmin Le Grand { 494ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); 495ddde725dSArmin Le Grand } 496ddde725dSArmin Le Grand else 497ddde725dSArmin Le Grand { 498ddde725dSArmin Le Grand // need to apply rotations to each character as given 499693be7f6SArmin Le Grand const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = 500693be7f6SArmin Le Grand dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get()); 501693be7f6SArmin Le Grand 502693be7f6SArmin Le Grand if(pCandidate) 503693be7f6SArmin Le Grand { 504693be7f6SArmin Le Grand const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition); 505ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DSequence aResult( 506ddde725dSArmin Le Grand alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character)); 507ddde725dSArmin Le Grand 508ddde725dSArmin Le Grand if(aResult.hasElements()) 509ddde725dSArmin Le Grand { 510ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult); 511ddde725dSArmin Le Grand } 512ddde725dSArmin Le Grand 513ddde725dSArmin Le Grand // also consume for the implied single space 514ddde725dSArmin Le Grand rSvgTextPosition.consumeRotation(); 515ddde725dSArmin Le Grand } 516693be7f6SArmin Le Grand else 517693be7f6SArmin Le Grand { 518693be7f6SArmin Le Grand OSL_ENSURE(false, "Used primitive is not a text primitive (!)"); 519693be7f6SArmin Le Grand } 520693be7f6SArmin Le Grand } 521ddde725dSArmin Le Grand } 522ddde725dSArmin Le Grand } 523ddde725dSArmin Le Grand 524ddde725dSArmin Le Grand void SvgCharacterNode::whiteSpaceHandling() 525ddde725dSArmin Le Grand { 526ddde725dSArmin Le Grand if(XmlSpace_default == getXmlSpace()) 527ddde725dSArmin Le Grand { 528ddde725dSArmin Le Grand maText = whiteSpaceHandlingDefault(maText); 529ddde725dSArmin Le Grand } 530ddde725dSArmin Le Grand else 531ddde725dSArmin Le Grand { 532ddde725dSArmin Le Grand maText = whiteSpaceHandlingPreserve(maText); 533ddde725dSArmin Le Grand } 534ddde725dSArmin Le Grand } 535ddde725dSArmin Le Grand 536ddde725dSArmin Le Grand void SvgCharacterNode::addGap() 537ddde725dSArmin Le Grand { 538ddde725dSArmin Le Grand maText += rtl::OUString(sal_Unicode(' ')); 539ddde725dSArmin Le Grand } 540ddde725dSArmin Le Grand 541ddde725dSArmin Le Grand void SvgCharacterNode::concatenate(const rtl::OUString& rText) 542ddde725dSArmin Le Grand { 543ddde725dSArmin Le Grand maText += rText; 544ddde725dSArmin Le Grand } 545ddde725dSArmin Le Grand 546ddde725dSArmin Le Grand void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const 547ddde725dSArmin Le Grand { 548ddde725dSArmin Le Grand if(getText().getLength()) 549ddde725dSArmin Le Grand { 550ddde725dSArmin Le Grand const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes(); 551ddde725dSArmin Le Grand 552ddde725dSArmin Le Grand if(pSvgStyleAttributes) 553ddde725dSArmin Le Grand { 554ddde725dSArmin Le Grand decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes); 555ddde725dSArmin Le Grand } 556ddde725dSArmin Le Grand } 557ddde725dSArmin Le Grand } 558ddde725dSArmin Le Grand 559ddde725dSArmin Le Grand } // end of namespace svgreader 560ddde725dSArmin Le Grand } // end of namespace svgio 561ddde725dSArmin Le Grand 562ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 563ddde725dSArmin Le Grand 564ddde725dSArmin Le Grand namespace svgio 565ddde725dSArmin Le Grand { 566ddde725dSArmin Le Grand namespace svgreader 567ddde725dSArmin Le Grand { 568ddde725dSArmin Le Grand SvgTextPosition::SvgTextPosition( 569ddde725dSArmin Le Grand SvgTextPosition* pParent, 570ddde725dSArmin Le Grand const InfoProvider& rInfoProvider, 571ddde725dSArmin Le Grand const SvgTextPositions& rSvgTextPositions) 572ddde725dSArmin Le Grand : mpParent(pParent), 573ddde725dSArmin Le Grand maX(), // computed below 574ddde725dSArmin Le Grand maY(), // computed below 575ddde725dSArmin Le Grand maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)), 576ddde725dSArmin Le Grand mfTextLength(0.0), 577ddde725dSArmin Le Grand maPosition(), // computed below 578ddde725dSArmin Le Grand mnRotationIndex(0), 579ddde725dSArmin Le Grand mbLengthAdjust(rSvgTextPositions.getLengthAdjust()), 580ddde725dSArmin Le Grand mbAbsoluteX(false), 581ddde725dSArmin Le Grand mbAbsoluteY(false) 582ddde725dSArmin Le Grand { 583ddde725dSArmin Le Grand // get TextLength if provided 584ddde725dSArmin Le Grand if(rSvgTextPositions.getTextLength().isSet()) 585ddde725dSArmin Le Grand { 586ddde725dSArmin Le Grand mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length); 587ddde725dSArmin Le Grand } 588ddde725dSArmin Le Grand 589ddde725dSArmin Le Grand // SVG does not really define in which units a �rotate� for Text/TSpan is given, 590ddde725dSArmin Le Grand // but it seems to be degrees. Convert here to radians 591ddde725dSArmin Le Grand if(!maRotate.empty()) 592ddde725dSArmin Le Grand { 593ddde725dSArmin Le Grand const double fFactor(F_PI / 180.0); 594ddde725dSArmin Le Grand 595ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < maRotate.size(); a++) 596ddde725dSArmin Le Grand { 597ddde725dSArmin Le Grand maRotate[a] *= fFactor; 598ddde725dSArmin Le Grand } 599ddde725dSArmin Le Grand } 600ddde725dSArmin Le Grand 601ddde725dSArmin Le Grand // get text positions X 602ddde725dSArmin Le Grand const sal_uInt32 nSizeX(rSvgTextPositions.getX().size()); 603ddde725dSArmin Le Grand 604ddde725dSArmin Le Grand if(nSizeX) 605ddde725dSArmin Le Grand { 606ddde725dSArmin Le Grand // we have absolute positions, get first one as current text position X 607ddde725dSArmin Le Grand maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate)); 608ddde725dSArmin Le Grand mbAbsoluteX = true; 609ddde725dSArmin Le Grand 610ddde725dSArmin Le Grand if(nSizeX > 1) 611ddde725dSArmin Le Grand { 612ddde725dSArmin Le Grand // fill deltas to maX 613ddde725dSArmin Le Grand maX.reserve(nSizeX); 614ddde725dSArmin Le Grand 615ddde725dSArmin Le Grand for(sal_uInt32 a(1); a < nSizeX; a++) 616ddde725dSArmin Le Grand { 617ddde725dSArmin Le Grand maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX()); 618ddde725dSArmin Le Grand } 619ddde725dSArmin Le Grand } 620ddde725dSArmin Le Grand } 621ddde725dSArmin Le Grand else 622ddde725dSArmin Le Grand { 623ddde725dSArmin Le Grand // no absolute position, get from parent 624ddde725dSArmin Le Grand if(pParent) 625ddde725dSArmin Le Grand { 626ddde725dSArmin Le Grand maPosition.setX(pParent->getPosition().getX()); 627ddde725dSArmin Le Grand } 628ddde725dSArmin Le Grand 629ddde725dSArmin Le Grand const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size()); 630ddde725dSArmin Le Grand 631ddde725dSArmin Le Grand if(nSizeDx) 632ddde725dSArmin Le Grand { 633ddde725dSArmin Le Grand // relative positions given, translate position derived from parent 634ddde725dSArmin Le Grand maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate)); 635ddde725dSArmin Le Grand 636ddde725dSArmin Le Grand if(nSizeDx > 1) 637ddde725dSArmin Le Grand { 638ddde725dSArmin Le Grand // fill deltas to maX 639ddde725dSArmin Le Grand maX.reserve(nSizeDx); 640ddde725dSArmin Le Grand 641ddde725dSArmin Le Grand for(sal_uInt32 a(1); a < nSizeDx; a++) 642ddde725dSArmin Le Grand { 643ddde725dSArmin Le Grand maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate)); 644ddde725dSArmin Le Grand } 645ddde725dSArmin Le Grand } 646ddde725dSArmin Le Grand } 647ddde725dSArmin Le Grand } 648ddde725dSArmin Le Grand 649ddde725dSArmin Le Grand // get text positions Y 650ddde725dSArmin Le Grand const sal_uInt32 nSizeY(rSvgTextPositions.getY().size()); 651ddde725dSArmin Le Grand 652ddde725dSArmin Le Grand if(nSizeY) 653ddde725dSArmin Le Grand { 654ddde725dSArmin Le Grand // we have absolute positions, get first one as current text position Y 655ddde725dSArmin Le Grand maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate)); 656ddde725dSArmin Le Grand mbAbsoluteX = true; 657ddde725dSArmin Le Grand 658ddde725dSArmin Le Grand if(nSizeY > 1) 659ddde725dSArmin Le Grand { 660ddde725dSArmin Le Grand // fill deltas to maY 661ddde725dSArmin Le Grand maY.reserve(nSizeY); 662ddde725dSArmin Le Grand 663ddde725dSArmin Le Grand for(sal_uInt32 a(1); a < nSizeY; a++) 664ddde725dSArmin Le Grand { 665ddde725dSArmin Le Grand maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY()); 666ddde725dSArmin Le Grand } 667ddde725dSArmin Le Grand } 668ddde725dSArmin Le Grand } 669ddde725dSArmin Le Grand else 670ddde725dSArmin Le Grand { 671ddde725dSArmin Le Grand // no absolute position, get from parent 672ddde725dSArmin Le Grand if(pParent) 673ddde725dSArmin Le Grand { 674ddde725dSArmin Le Grand maPosition.setY(pParent->getPosition().getY()); 675ddde725dSArmin Le Grand } 676ddde725dSArmin Le Grand 677ddde725dSArmin Le Grand const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size()); 678ddde725dSArmin Le Grand 679ddde725dSArmin Le Grand if(nSizeDy) 680ddde725dSArmin Le Grand { 681ddde725dSArmin Le Grand // relative positions given, translate position derived from parent 682ddde725dSArmin Le Grand maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate)); 683ddde725dSArmin Le Grand 684ddde725dSArmin Le Grand if(nSizeDy > 1) 685ddde725dSArmin Le Grand { 686ddde725dSArmin Le Grand // fill deltas to maY 687ddde725dSArmin Le Grand maY.reserve(nSizeDy); 688ddde725dSArmin Le Grand 689ddde725dSArmin Le Grand for(sal_uInt32 a(1); a < nSizeDy; a++) 690ddde725dSArmin Le Grand { 691ddde725dSArmin Le Grand maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate)); 692ddde725dSArmin Le Grand } 693ddde725dSArmin Le Grand } 694ddde725dSArmin Le Grand } 695ddde725dSArmin Le Grand } 696ddde725dSArmin Le Grand } 697ddde725dSArmin Le Grand 698ddde725dSArmin Le Grand bool SvgTextPosition::isRotated() const 699ddde725dSArmin Le Grand { 700ddde725dSArmin Le Grand if(maRotate.empty()) 701ddde725dSArmin Le Grand { 702ddde725dSArmin Le Grand if(getParent()) 703ddde725dSArmin Le Grand { 704ddde725dSArmin Le Grand return getParent()->isRotated(); 705ddde725dSArmin Le Grand } 706ddde725dSArmin Le Grand else 707ddde725dSArmin Le Grand { 708ddde725dSArmin Le Grand return false; 709ddde725dSArmin Le Grand } 710ddde725dSArmin Le Grand } 711ddde725dSArmin Le Grand else 712ddde725dSArmin Le Grand { 713ddde725dSArmin Le Grand return true; 714ddde725dSArmin Le Grand } 715ddde725dSArmin Le Grand } 716ddde725dSArmin Le Grand 717ddde725dSArmin Le Grand double SvgTextPosition::consumeRotation() 718ddde725dSArmin Le Grand { 719ddde725dSArmin Le Grand double fRetval(0.0); 720ddde725dSArmin Le Grand 721ddde725dSArmin Le Grand if(maRotate.empty()) 722ddde725dSArmin Le Grand { 723ddde725dSArmin Le Grand if(getParent()) 724ddde725dSArmin Le Grand { 725ddde725dSArmin Le Grand fRetval = mpParent->consumeRotation(); 726ddde725dSArmin Le Grand } 727ddde725dSArmin Le Grand else 728ddde725dSArmin Le Grand { 729ddde725dSArmin Le Grand fRetval = 0.0; 730ddde725dSArmin Le Grand } 731ddde725dSArmin Le Grand } 732ddde725dSArmin Le Grand else 733ddde725dSArmin Le Grand { 734ddde725dSArmin Le Grand const sal_uInt32 nSize(maRotate.size()); 735ddde725dSArmin Le Grand 736ddde725dSArmin Le Grand if(mnRotationIndex < nSize) 737ddde725dSArmin Le Grand { 738ddde725dSArmin Le Grand fRetval = maRotate[mnRotationIndex++]; 739ddde725dSArmin Le Grand } 740ddde725dSArmin Le Grand else 741ddde725dSArmin Le Grand { 742ddde725dSArmin Le Grand fRetval = maRotate[nSize - 1]; 743ddde725dSArmin Le Grand } 744ddde725dSArmin Le Grand } 745ddde725dSArmin Le Grand 746ddde725dSArmin Le Grand return fRetval; 747ddde725dSArmin Le Grand } 748ddde725dSArmin Le Grand 749ddde725dSArmin Le Grand } // end of namespace svgreader 750ddde725dSArmin Le Grand } // end of namespace svgio 751ddde725dSArmin Le Grand 752ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 753ddde725dSArmin Le Grand // eof 754