1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_svgio.hxx" 24 25 #include <svgio/svgreader/svgtextnode.hxx> 26 #include <svgio/svgreader/svgcharacternode.hxx> 27 #include <svgio/svgreader/svgstyleattributes.hxx> 28 #include <svgio/svgreader/svgtrefnode.hxx> 29 #include <svgio/svgreader/svgtextpathnode.hxx> 30 #include <svgio/svgreader/svgtspannode.hxx> 31 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 32 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 33 34 ////////////////////////////////////////////////////////////////////////////// 35 36 namespace svgio 37 { 38 namespace svgreader 39 { 40 SvgTextNode::SvgTextNode( 41 SvgDocument& rDocument, 42 SvgNode* pParent) 43 : SvgNode(SVGTokenText, rDocument, pParent), 44 maSvgStyleAttributes(*this), 45 mpaTransform(0), 46 maSvgTextPositions() 47 { 48 } 49 50 SvgTextNode::~SvgTextNode() 51 { 52 if(mpaTransform) delete mpaTransform; 53 } 54 55 const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const 56 { 57 static rtl::OUString aClassStr(rtl::OUString::createFromAscii("text")); 58 maSvgStyleAttributes.checkForCssStyle(aClassStr); 59 60 return &maSvgStyleAttributes; 61 } 62 63 void SvgTextNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 64 { 65 // call parent 66 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 67 68 // read style attributes 69 maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 70 71 // read text position attributes 72 maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent); 73 74 // parse own 75 switch(aSVGToken) 76 { 77 case SVGTokenStyle: 78 { 79 maSvgStyleAttributes.readStyle(aContent); 80 break; 81 } 82 case SVGTokenTransform: 83 { 84 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); 85 86 if(!aMatrix.isIdentity()) 87 { 88 setTransform(&aMatrix); 89 } 90 break; 91 } 92 default: 93 { 94 break; 95 } 96 } 97 } 98 99 void SvgTextNode::addTextPrimitives( 100 const SvgNode& rCandidate, 101 drawinglayer::primitive2d::Primitive2DSequence& rTarget, 102 drawinglayer::primitive2d::Primitive2DSequence& rSource) const 103 { 104 if(rSource.hasElements()) 105 { 106 const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes(); 107 108 if(pAttributes) 109 { 110 // add text with taking all Fill/Stroke attributes into account 111 pAttributes->add_text(rTarget, rSource); 112 } 113 else 114 { 115 // should not happen, every subnode from SvgTextNode will at least 116 // return the attributes from SvgTextNode. Nonetheless, add text 117 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource); 118 } 119 } 120 } 121 122 void SvgTextNode::DecomposeChild(const SvgNode& rCandidate, drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const 123 { 124 switch(rCandidate.getType()) 125 { 126 case SVGTokenCharacter: 127 { 128 // direct SvgTextPathNode derivates, decompose them 129 const SvgCharacterNode& rSvgCharacterNode = static_cast< const SvgCharacterNode& >(rCandidate); 130 rSvgCharacterNode.decomposeText(rTarget, rSvgTextPosition); 131 break; 132 } 133 case SVGTokenTextPath: 134 { 135 // direct TextPath decompose 136 const SvgTextPathNode& rSvgTextPathNode = static_cast< const SvgTextPathNode& >(rCandidate); 137 const SvgNodeVector& rChildren = rSvgTextPathNode.getChildren(); 138 const sal_uInt32 nCount(rChildren.size()); 139 140 if(nCount && rSvgTextPathNode.isValid()) 141 { 142 // remember original TextStart to later detect hor/ver offsets 143 const basegfx::B2DPoint aTextStart(rSvgTextPosition.getPosition()); 144 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 145 146 // decompose to regular TextPrimitives 147 for(sal_uInt32 a(0); a < nCount; a++) 148 { 149 DecomposeChild(*rChildren[a], aNewTarget, rSvgTextPosition); 150 } 151 152 if(aNewTarget.hasElements()) 153 { 154 const drawinglayer::primitive2d::Primitive2DSequence aPathContent(aNewTarget); 155 aNewTarget.realloc(0); 156 157 // dismantle TextPrimitives and map them on curve/path 158 rSvgTextPathNode.decomposePathNode(aPathContent, aNewTarget, aTextStart); 159 } 160 161 if(aNewTarget.hasElements()) 162 { 163 addTextPrimitives(rCandidate, rTarget, aNewTarget); 164 } 165 } 166 167 break; 168 } 169 case SVGTokenTspan: 170 { 171 // Tspan may have children, call recursively 172 const SvgTspanNode& rSvgTspanNode = static_cast< const SvgTspanNode& >(rCandidate); 173 const SvgNodeVector& rChildren = rSvgTspanNode.getChildren(); 174 const sal_uInt32 nCount(rChildren.size()); 175 176 if(nCount) 177 { 178 SvgTextPosition aSvgTextPosition(&rSvgTextPosition, rSvgTspanNode, rSvgTspanNode.getSvgTextPositions()); 179 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 180 181 for(sal_uInt32 a(0); a < nCount; a++) 182 { 183 DecomposeChild(*rChildren[a], aNewTarget, aSvgTextPosition); 184 } 185 186 rSvgTextPosition.setPosition(aSvgTextPosition.getPosition()); 187 188 if(aNewTarget.hasElements()) 189 { 190 addTextPrimitives(rCandidate, rTarget, aNewTarget); 191 } 192 } 193 break; 194 } 195 case SVGTokenTref: 196 { 197 const SvgTrefNode& rSvgTrefNode = static_cast< const SvgTrefNode& >(rCandidate); 198 const SvgTextNode* pRefText = rSvgTrefNode.getReferencedSvgTextNode(); 199 200 if(pRefText) 201 { 202 const SvgNodeVector& rChildren = pRefText->getChildren(); 203 const sal_uInt32 nCount(rChildren.size()); 204 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 205 206 if(nCount) 207 { 208 for(sal_uInt32 a(0); a < nCount; a++) 209 { 210 const SvgNode& rChildCandidate = *rChildren[a]; 211 const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(this); 212 213 DecomposeChild(rChildCandidate, aNewTarget, rSvgTextPosition); 214 const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(0); 215 } 216 217 if(aNewTarget.hasElements()) 218 { 219 addTextPrimitives(rCandidate, rTarget, aNewTarget); 220 } 221 } 222 } 223 224 break; 225 } 226 default: 227 { 228 OSL_ENSURE(false, "Unexpected node in text token (!)"); 229 break; 230 } 231 } 232 } 233 234 void SvgTextNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced`*/) const 235 { 236 // text has a group of child nodes, allowed are SVGTokenCharacter, SVGTokenTspan, 237 // SVGTokenTref and SVGTokenTextPath. These increase a given current text position 238 const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); 239 240 if(pStyle && !getChildren().empty()) 241 { 242 const double fOpacity(pStyle->getOpacity().getNumber()); 243 244 if(fOpacity > 0.0) 245 { 246 SvgTextPosition aSvgTextPosition(0, *this, getSvgTextPositions()); 247 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 248 const SvgNodeVector& rChildren = getChildren(); 249 const sal_uInt32 nCount(rChildren.size()); 250 251 for(sal_uInt32 a(0); a < nCount; a++) 252 { 253 const SvgNode& rCandidate = *rChildren[a]; 254 255 DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition); 256 } 257 258 if(aNewTarget.hasElements()) 259 { 260 drawinglayer::primitive2d::Primitive2DSequence aNewTarget2; 261 262 addTextPrimitives(*this, aNewTarget2, aNewTarget); 263 aNewTarget = aNewTarget2; 264 } 265 266 if(aNewTarget.hasElements()) 267 { 268 pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); 269 } 270 } 271 } 272 } 273 } // end of namespace svgreader 274 } // end of namespace svgio 275 276 ////////////////////////////////////////////////////////////////////////////// 277 // eof 278