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/svgsvgnode.hxx> 26ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx> 27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 29ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx> 30ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx> 31ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx> 3241923119SArmin Le Grand #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 3341923119SArmin Le Grand #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx> 34ddde725dSArmin Le Grand 35ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 36ddde725dSArmin Le Grand 37ddde725dSArmin Le Grand namespace svgio 38ddde725dSArmin Le Grand { 39ddde725dSArmin Le Grand namespace svgreader 40ddde725dSArmin Le Grand { 41ddde725dSArmin Le Grand SvgSvgNode::SvgSvgNode( 42ddde725dSArmin Le Grand SvgDocument& rDocument, 43ddde725dSArmin Le Grand SvgNode* pParent) 44ddde725dSArmin Le Grand : SvgNode(SVGTokenSvg, rDocument, pParent), 45ddde725dSArmin Le Grand maSvgStyleAttributes(*this), 46ddde725dSArmin Le Grand mpViewBox(0), 47ddde725dSArmin Le Grand maSvgAspectRatio(), 48ddde725dSArmin Le Grand maX(), 49ddde725dSArmin Le Grand maY(), 50ddde725dSArmin Le Grand maWidth(), 51ddde725dSArmin Le Grand maHeight(), 52ddde725dSArmin Le Grand maVersion() 53ddde725dSArmin Le Grand { 54ddde725dSArmin Le Grand if(!getParent()) 55ddde725dSArmin Le Grand { 56ddde725dSArmin Le Grand // initial fill is black 57ddde725dSArmin Le Grand maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); 58ddde725dSArmin Le Grand } 59ddde725dSArmin Le Grand } 60ddde725dSArmin Le Grand 61ddde725dSArmin Le Grand SvgSvgNode::~SvgSvgNode() 62ddde725dSArmin Le Grand { 63ddde725dSArmin Le Grand if(mpViewBox) delete mpViewBox; 64ddde725dSArmin Le Grand } 65ddde725dSArmin Le Grand 66ddde725dSArmin Le Grand const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const 67ddde725dSArmin Le Grand { 68ddde725dSArmin Le Grand return &maSvgStyleAttributes; 69ddde725dSArmin Le Grand } 70ddde725dSArmin Le Grand 71ddde725dSArmin Le Grand void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 72ddde725dSArmin Le Grand { 73ddde725dSArmin Le Grand // call parent 74ddde725dSArmin Le Grand SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 75ddde725dSArmin Le Grand 76ddde725dSArmin Le Grand // read style attributes 77ddde725dSArmin Le Grand maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 78ddde725dSArmin Le Grand 79ddde725dSArmin Le Grand // parse own 80ddde725dSArmin Le Grand switch(aSVGToken) 81ddde725dSArmin Le Grand { 82ddde725dSArmin Le Grand case SVGTokenStyle: 83ddde725dSArmin Le Grand { 84ddde725dSArmin Le Grand maSvgStyleAttributes.readStyle(aContent); 85ddde725dSArmin Le Grand break; 86ddde725dSArmin Le Grand } 87ddde725dSArmin Le Grand case SVGTokenViewBox: 88ddde725dSArmin Le Grand { 89ddde725dSArmin Le Grand const basegfx::B2DRange aRange(readViewBox(aContent, *this)); 90ddde725dSArmin Le Grand 91ddde725dSArmin Le Grand if(!aRange.isEmpty()) 92ddde725dSArmin Le Grand { 93ddde725dSArmin Le Grand setViewBox(&aRange); 94ddde725dSArmin Le Grand } 95ddde725dSArmin Le Grand break; 96ddde725dSArmin Le Grand } 97ddde725dSArmin Le Grand case SVGTokenPreserveAspectRatio: 98ddde725dSArmin Le Grand { 99ddde725dSArmin Le Grand setSvgAspectRatio(readSvgAspectRatio(aContent)); 100ddde725dSArmin Le Grand break; 101ddde725dSArmin Le Grand } 102ddde725dSArmin Le Grand case SVGTokenX: 103ddde725dSArmin Le Grand { 104ddde725dSArmin Le Grand SvgNumber aNum; 105ddde725dSArmin Le Grand 106ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 107ddde725dSArmin Le Grand { 108ddde725dSArmin Le Grand setX(aNum); 109ddde725dSArmin Le Grand } 110ddde725dSArmin Le Grand break; 111ddde725dSArmin Le Grand } 112ddde725dSArmin Le Grand case SVGTokenY: 113ddde725dSArmin Le Grand { 114ddde725dSArmin Le Grand SvgNumber aNum; 115ddde725dSArmin Le Grand 116ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 117ddde725dSArmin Le Grand { 118ddde725dSArmin Le Grand setY(aNum); 119ddde725dSArmin Le Grand } 120ddde725dSArmin Le Grand break; 121ddde725dSArmin Le Grand } 122ddde725dSArmin Le Grand case SVGTokenWidth: 123ddde725dSArmin Le Grand { 124ddde725dSArmin Le Grand SvgNumber aNum; 125ddde725dSArmin Le Grand 126ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 127ddde725dSArmin Le Grand { 128ddde725dSArmin Le Grand if(aNum.isPositive()) 129ddde725dSArmin Le Grand { 130ddde725dSArmin Le Grand setWidth(aNum); 131ddde725dSArmin Le Grand } 132ddde725dSArmin Le Grand } 133ddde725dSArmin Le Grand break; 134ddde725dSArmin Le Grand } 135ddde725dSArmin Le Grand case SVGTokenHeight: 136ddde725dSArmin Le Grand { 137ddde725dSArmin Le Grand SvgNumber aNum; 138ddde725dSArmin Le Grand 139ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 140ddde725dSArmin Le Grand { 141ddde725dSArmin Le Grand if(aNum.isPositive()) 142ddde725dSArmin Le Grand { 143ddde725dSArmin Le Grand setHeight(aNum); 144ddde725dSArmin Le Grand } 145ddde725dSArmin Le Grand } 146ddde725dSArmin Le Grand break; 147ddde725dSArmin Le Grand } 148ddde725dSArmin Le Grand case SVGTokenVersion: 149ddde725dSArmin Le Grand { 150ddde725dSArmin Le Grand SvgNumber aNum; 151ddde725dSArmin Le Grand 152ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 153ddde725dSArmin Le Grand { 154ddde725dSArmin Le Grand setVersion(aNum); 155ddde725dSArmin Le Grand } 156ddde725dSArmin Le Grand break; 157e2bf1e9dSArmin Le Grand } 158e2bf1e9dSArmin Le Grand default: 159e2bf1e9dSArmin Le Grand { 160e2bf1e9dSArmin Le Grand break; 161ddde725dSArmin Le Grand } 162ddde725dSArmin Le Grand } 163ddde725dSArmin Le Grand } 164ddde725dSArmin Le Grand 165ddde725dSArmin Le Grand void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 166ddde725dSArmin Le Grand { 167ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence aSequence; 168ddde725dSArmin Le Grand 169ddde725dSArmin Le Grand // decompose childs 170ddde725dSArmin Le Grand SvgNode::decomposeSvgNode(aSequence, bReferenced); 171ddde725dSArmin Le Grand 172ddde725dSArmin Le Grand if(aSequence.hasElements()) 173ddde725dSArmin Le Grand { 174ddde725dSArmin Le Grand if(getParent()) 175ddde725dSArmin Le Grand { 176*bca0eb5dSArmin Le Grand const bool bWidthIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit()); 177*bca0eb5dSArmin Le Grand const bool bHeightIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit()); 178*bca0eb5dSArmin Le Grand const SvgSvgNode* pParentSvgSvgNode = 0; 179*bca0eb5dSArmin Le Grand double fW(0.0); 180*bca0eb5dSArmin Le Grand double fH(0.0); 181*bca0eb5dSArmin Le Grand 182*bca0eb5dSArmin Le Grand // #122594# if width/height is not given, it's 100% (see 5.1.2 The �svg� element in SVG1.1 spec). 183*bca0eb5dSArmin Le Grand // If it is relative, the question is to what. The previous implementatin assumed relative to the 184*bca0eb5dSArmin Le Grand // local ViewBox which is implied by (4.2 Basic data types): 185*bca0eb5dSArmin Le Grand // 186*bca0eb5dSArmin Le Grand // "Note that the non-property <length> definition also allows a percentage unit identifier. 187*bca0eb5dSArmin Le Grand // The meaning of a percentage length value depends on the attribute for which the percentage 188*bca0eb5dSArmin Le Grand // length value has been specified. Two common cases are: (a) when a percentage length value 189*bca0eb5dSArmin Le Grand // represents a percentage of the viewport width or height (refer to the section that discusses 190*bca0eb5dSArmin Le Grand // units in general), and (b) when a percentage length value represents a percentage of the 191*bca0eb5dSArmin Le Grand // bounding box width or height on a given object (refer to the section that describes object 192*bca0eb5dSArmin Le Grand // bounding box units)." 193*bca0eb5dSArmin Le Grand // 194*bca0eb5dSArmin Le Grand // This is not closer specified for the SVG element itself as non-outmost element, but comparisons 195*bca0eb5dSArmin Le Grand // with common browsers shows that it's mostly interpreted relative to the viewBox of the parent. 196*bca0eb5dSArmin Le Grand // Adding code to search the parent SVG element and calculating width/height relative to it's 197*bca0eb5dSArmin Le Grand // viewBox width/height (and no longer to the local viewBox). 198*bca0eb5dSArmin Le Grand if(bWidthIsRelative || bHeightIsRelative) 199*bca0eb5dSArmin Le Grand { 200*bca0eb5dSArmin Le Grand for(const SvgNode* pParent = getParent(); pParent && !pParentSvgSvgNode; pParent = pParent->getParent()) 201*bca0eb5dSArmin Le Grand { 202*bca0eb5dSArmin Le Grand pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); 203*bca0eb5dSArmin Le Grand } 204*bca0eb5dSArmin Le Grand } 205*bca0eb5dSArmin Le Grand 206*bca0eb5dSArmin Le Grand if(bWidthIsRelative) 207*bca0eb5dSArmin Le Grand { 208*bca0eb5dSArmin Le Grand fW = getWidth().isSet() ? getWidth().getNumber() * 0.01 : 1.0; 209*bca0eb5dSArmin Le Grand 210*bca0eb5dSArmin Le Grand if(pParentSvgSvgNode) 211*bca0eb5dSArmin Le Grand { 212*bca0eb5dSArmin Le Grand fW *= pParentSvgSvgNode->getViewBox()->getWidth(); 213*bca0eb5dSArmin Le Grand } 214*bca0eb5dSArmin Le Grand } 215*bca0eb5dSArmin Le Grand else 216*bca0eb5dSArmin Le Grand { 217*bca0eb5dSArmin Le Grand fW = getWidth().solve(*this, xcoordinate); 218*bca0eb5dSArmin Le Grand } 219*bca0eb5dSArmin Le Grand 220*bca0eb5dSArmin Le Grand if(bHeightIsRelative) 221*bca0eb5dSArmin Le Grand { 222*bca0eb5dSArmin Le Grand fH = getHeight().isSet() ? getHeight().getNumber() * 0.01 : 1.0; 223*bca0eb5dSArmin Le Grand 224*bca0eb5dSArmin Le Grand if(pParentSvgSvgNode) 225*bca0eb5dSArmin Le Grand { 226*bca0eb5dSArmin Le Grand fH *= pParentSvgSvgNode->getViewBox()->getHeight(); 227*bca0eb5dSArmin Le Grand } 228*bca0eb5dSArmin Le Grand } 229*bca0eb5dSArmin Le Grand else 230*bca0eb5dSArmin Le Grand { 231*bca0eb5dSArmin Le Grand fH = getHeight().solve(*this, ycoordinate); 232*bca0eb5dSArmin Le Grand } 233*bca0eb5dSArmin Le Grand 234ddde725dSArmin Le Grand if(getViewBox()) 235ddde725dSArmin Le Grand { 236ddde725dSArmin Le Grand // Svg defines that with no width or no height the viewBox content is empty, 237ddde725dSArmin Le Grand // so both need to exist 238ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) 239ddde725dSArmin Le Grand { 240ddde725dSArmin Le Grand // create target range homing x,y, width and height as given 241ddde725dSArmin Le Grand const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); 242ddde725dSArmin Le Grand const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); 243ddde725dSArmin Le Grand const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH); 244ddde725dSArmin Le Grand 245ddde725dSArmin Le Grand if(aTarget.equal(*getViewBox())) 246ddde725dSArmin Le Grand { 247ddde725dSArmin Le Grand // no mapping needed, append 248ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 249ddde725dSArmin Le Grand } 250ddde725dSArmin Le Grand else 251ddde725dSArmin Le Grand { 252ddde725dSArmin Le Grand // create mapping 253ddde725dSArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio(); 254ddde725dSArmin Le Grand 255ddde725dSArmin Le Grand if(rRatio.isSet()) 256ddde725dSArmin Le Grand { 257ddde725dSArmin Le Grand // let mapping be created from SvgAspectRatio 258ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform( 259ddde725dSArmin Le Grand rRatio.createMapping(aTarget, *getViewBox())); 260ddde725dSArmin Le Grand 261ddde725dSArmin Le Grand // prepare embedding in transformation 262ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 263ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 264ddde725dSArmin Le Grand aEmbeddingTransform, 265ddde725dSArmin Le Grand aSequence)); 266ddde725dSArmin Le Grand 267ddde725dSArmin Le Grand if(rRatio.isMeetOrSlice()) 268ddde725dSArmin Le Grand { 269ddde725dSArmin Le Grand // embed in transformation 270ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); 271ddde725dSArmin Le Grand } 272ddde725dSArmin Le Grand else 273ddde725dSArmin Le Grand { 274ddde725dSArmin Le Grand // need to embed in MaskPrimitive2D, too 275ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 276ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 277ddde725dSArmin Le Grand basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), 278ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); 279ddde725dSArmin Le Grand 280ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 281ddde725dSArmin Le Grand } 282ddde725dSArmin Le Grand } 283ddde725dSArmin Le Grand else 284ddde725dSArmin Le Grand { 285ddde725dSArmin Le Grand // choose default mapping 286ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform( 287ddde725dSArmin Le Grand rRatio.createLinearMapping( 288ddde725dSArmin Le Grand aTarget, *getViewBox())); 289ddde725dSArmin Le Grand 290ddde725dSArmin Le Grand // embed in transformation 291ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 292ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 293ddde725dSArmin Le Grand aEmbeddingTransform, 294ddde725dSArmin Le Grand aSequence)); 295ddde725dSArmin Le Grand 296ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xTransform); 297ddde725dSArmin Le Grand } 298ddde725dSArmin Le Grand } 299ddde725dSArmin Le Grand } 300ddde725dSArmin Le Grand } 301ddde725dSArmin Le Grand else 302ddde725dSArmin Le Grand { 303ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 304ddde725dSArmin Le Grand if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) 305ddde725dSArmin Le Grand { 306ddde725dSArmin Le Grand // check if we have a x,y position 307ddde725dSArmin Le Grand const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); 308ddde725dSArmin Le Grand const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); 309ddde725dSArmin Le Grand 310ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) 311ddde725dSArmin Le Grand { 312ddde725dSArmin Le Grand // embed in transform 313ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 314ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 315ddde725dSArmin Le Grand basegfx::tools::createTranslateB2DHomMatrix(fX, fY), 316ddde725dSArmin Le Grand aSequence)); 317ddde725dSArmin Le Grand 318ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 319ddde725dSArmin Le Grand } 320ddde725dSArmin Le Grand 321ddde725dSArmin Le Grand // embed in MaskPrimitive2D to clip 322ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 323ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 324ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 325ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 326ddde725dSArmin Le Grand basegfx::B2DRange(fX, fY, fX + fW, fY + fH))), 327ddde725dSArmin Le Grand aSequence)); 328ddde725dSArmin Le Grand 329ddde725dSArmin Le Grand // append 330ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 331ddde725dSArmin Le Grand } 332ddde725dSArmin Le Grand } 333ddde725dSArmin Le Grand } 334ddde725dSArmin Le Grand else 335ddde725dSArmin Le Grand { 336ddde725dSArmin Le Grand // Outermost SVG element; create target range homing width and height as given. 337ddde725dSArmin Le Grand // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback 338ddde725dSArmin Le Grand // width and height of din A 4 (21 x 29,7 cm) 339ddde725dSArmin Le Grand double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : (210.0 * 3.543307)); 340ddde725dSArmin Le Grand double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : (297.0 * 3.543307)); 341ddde725dSArmin Le Grand 342ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 343ddde725dSArmin Le Grand if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) 344ddde725dSArmin Le Grand { 345ddde725dSArmin Le Grand const basegfx::B2DRange aSvgCanvasRange(0.0, 0.0, fW, fH); 346ddde725dSArmin Le Grand 347ddde725dSArmin Le Grand if(getViewBox()) 348ddde725dSArmin Le Grand { 349ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) 350ddde725dSArmin Le Grand { 351ddde725dSArmin Le Grand // create mapping 352ddde725dSArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio(); 353ddde725dSArmin Le Grand basegfx::B2DHomMatrix aViewBoxMapping; 354ddde725dSArmin Le Grand 355ddde725dSArmin Le Grand if(rRatio.isSet()) 356ddde725dSArmin Le Grand { 357ddde725dSArmin Le Grand // let mapping be created from SvgAspectRatio 358ddde725dSArmin Le Grand aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); 359ddde725dSArmin Le Grand 360ddde725dSArmin Le Grand // no need to check ratio here for slice, the outermost Svg will 361ddde725dSArmin Le Grand // be clipped anyways (see below) 362ddde725dSArmin Le Grand } 363ddde725dSArmin Le Grand else 364ddde725dSArmin Le Grand { 365ddde725dSArmin Le Grand // choose default mapping 366ddde725dSArmin Le Grand aViewBoxMapping = rRatio.createLinearMapping(aSvgCanvasRange, *getViewBox()); 367ddde725dSArmin Le Grand } 368ddde725dSArmin Le Grand 369ddde725dSArmin Le Grand // scale content to viewBox definitions 370ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 371ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 372ddde725dSArmin Le Grand aViewBoxMapping, 373ddde725dSArmin Le Grand aSequence)); 374ddde725dSArmin Le Grand 375ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 376ddde725dSArmin Le Grand } 377ddde725dSArmin Le Grand } 378ddde725dSArmin Le Grand 379ddde725dSArmin Le Grand // to be completely correct in Svg sense it is necessary to clip 380ddde725dSArmin Le Grand // the whole content to the given canvas. I choose here to do this 381ddde725dSArmin Le Grand // initially despite I found various examples of Svg files out there 382ddde725dSArmin Le Grand // which have no correct values for this clipping. It's correct 383ddde725dSArmin Le Grand // due to the Svg spec. 384ddde725dSArmin Le Grand bool bDoCorrectCanvasClipping(true); 385ddde725dSArmin Le Grand 386ddde725dSArmin Le Grand if(bDoCorrectCanvasClipping) 387ddde725dSArmin Le Grand { 388ddde725dSArmin Le Grand // different from Svg we have the possibility with primitives to get 38941923119SArmin Le Grand // a correct bounding box for the geometry. Get it for evtl. taking action 390ddde725dSArmin Le Grand const basegfx::B2DRange aContentRange( 391ddde725dSArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 392ddde725dSArmin Le Grand aSequence, 393ddde725dSArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 394ddde725dSArmin Le Grand 39541923119SArmin Le Grand if(aSvgCanvasRange.isInside(aContentRange)) 396ddde725dSArmin Le Grand { 39741923119SArmin Le Grand // no clip needed, but an invisible HiddenGeometryPrimitive2D 39841923119SArmin Le Grand // to allow getting the full Svg range using the primitive mechanisms. 39941923119SArmin Le Grand // This is needed since e.g. an SdrObject using this as graphic will 40041923119SArmin Le Grand // create a mapping transformation to exactly map the content to it's 40141923119SArmin Le Grand // real life size 40241923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xLine( 40341923119SArmin Le Grand new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( 40441923119SArmin Le Grand basegfx::tools::createPolygonFromRect( 40541923119SArmin Le Grand aSvgCanvasRange), 40641923119SArmin Le Grand basegfx::BColor(0.0, 0.0, 0.0))); 40741923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xHidden( 40841923119SArmin Le Grand new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( 40941923119SArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1))); 41041923119SArmin Le Grand 41141923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden); 41241923119SArmin Le Grand } 41341923119SArmin Le Grand else if(aSvgCanvasRange.overlaps(aContentRange)) 41441923119SArmin Le Grand { 41541923119SArmin Le Grand // Clip is necessary. This will make Svg images evtl. smaller 41641923119SArmin Le Grand // than wanted from Svg (the free space which may be around it is 41741923119SArmin Le Grand // conform to the Svg spec), but avoids an expensive and unneccessary 41841923119SArmin Le Grand // clip. Keep the full Svg range here to get the correct mappings 41941923119SArmin Le Grand // to objects using this. Optimizations can be done in the processors 420ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 421ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 422ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 423ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 424ddde725dSArmin Le Grand aSvgCanvasRange)), 425ddde725dSArmin Le Grand aSequence)); 426ddde725dSArmin Le Grand 427ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); 428ddde725dSArmin Le Grand } 42941923119SArmin Le Grand else 43041923119SArmin Le Grand { 43141923119SArmin Le Grand // not inside, no overlap. Empty Svg 43241923119SArmin Le Grand aSequence.realloc(0); 43341923119SArmin Le Grand } 434ddde725dSArmin Le Grand } 435ddde725dSArmin Le Grand 43641923119SArmin Le Grand if(aSequence.hasElements()) 437ddde725dSArmin Le Grand { 438ddde725dSArmin Le Grand // embed in transform primitive to scale to 1/100th mm 439ddde725dSArmin Le Grand // where 1 mm == 3.543307 px to get from Svg coordinates to 440ddde725dSArmin Le Grand // drawinglayer ones 441ddde725dSArmin Le Grand const double fScaleTo100thmm(100.0 / 3.543307); 442ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aTransform( 443ddde725dSArmin Le Grand basegfx::tools::createScaleB2DHomMatrix( 444ddde725dSArmin Le Grand fScaleTo100thmm, 445ddde725dSArmin Le Grand fScaleTo100thmm)); 446ddde725dSArmin Le Grand 447ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 448ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 449ddde725dSArmin Le Grand aTransform, 450ddde725dSArmin Le Grand aSequence)); 451ddde725dSArmin Le Grand 452ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 453ddde725dSArmin Le Grand 45441923119SArmin Le Grand // append to result 45541923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 45641923119SArmin Le Grand } 457ddde725dSArmin Le Grand } 458ddde725dSArmin Le Grand } 459ddde725dSArmin Le Grand } 460ddde725dSArmin Le Grand } 461ddde725dSArmin Le Grand 462ddde725dSArmin Le Grand const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const 463ddde725dSArmin Le Grand { 464ddde725dSArmin Le Grand if(getViewBox()) 465ddde725dSArmin Le Grand { 466ddde725dSArmin Le Grand return getViewBox(); 467ddde725dSArmin Le Grand } 468ddde725dSArmin Le Grand else 469ddde725dSArmin Le Grand { 470ddde725dSArmin Le Grand return SvgNode::getCurrentViewPort(); 471ddde725dSArmin Le Grand } 472ddde725dSArmin Le Grand } 473ddde725dSArmin Le Grand 474ddde725dSArmin Le Grand } // end of namespace svgreader 475ddde725dSArmin Le Grand } // end of namespace svgio 476ddde725dSArmin Le Grand 477ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 478ddde725dSArmin Le Grand // eof 479