diff options
-rw-r--r-- | svgio/source/svgreader/svganode.cxx | 24 | ||||
-rw-r--r-- | svgio/source/svgreader/svgcharacternode.cxx | 50 | ||||
-rw-r--r-- | svgio/source/svgreader/svgcirclenode.cxx | 36 | ||||
-rw-r--r-- | svgio/source/svgreader/svgclippathnode.cxx | 230 | ||||
-rw-r--r-- | svgio/source/svgreader/svgdocumenthandler.cxx | 760 | ||||
-rw-r--r-- | svgio/source/svgreader/svgellipsenode.cxx | 38 | ||||
-rw-r--r-- | svgio/source/svgreader/svgimagenode.cxx | 292 | ||||
-rw-r--r-- | svgio/source/svgreader/svglinenode.cxx | 38 | ||||
-rw-r--r-- | svgio/source/svgreader/svgmasknode.cxx | 216 | ||||
-rw-r--r-- | svgio/source/svgreader/svgnode.cxx | 278 | ||||
-rw-r--r-- | svgio/source/svgreader/svgpatternnode.cxx | 90 | ||||
-rw-r--r-- | svgio/source/svgreader/svgrectnode.cxx | 82 | ||||
-rw-r--r-- | svgio/source/svgreader/svgstyleattributes.cxx | 1194 | ||||
-rw-r--r-- | svgio/source/svgreader/svgstylenode.cxx | 204 | ||||
-rw-r--r-- | svgio/source/svgreader/svgsvgnode.cxx | 110 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtextnode.cxx | 78 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtextpathnode.cxx | 152 | ||||
-rw-r--r-- | svgio/source/svgreader/svgusenode.cxx | 80 |
18 files changed, 1976 insertions, 1976 deletions
diff --git a/svgio/source/svgreader/svganode.cxx b/svgio/source/svgreader/svganode.cxx index 8aac10dd1a3c..d2d64d04c359 100644 --- a/svgio/source/svgreader/svganode.cxx +++ b/svgio/source/svgreader/svganode.cxx @@ -81,21 +81,21 @@ namespace svgio // #i125258# for SVGTokenA decompose children const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle) - { - const double fOpacity(pStyle->getOpacity().getNumber()); + if(!pStyle) + return; - if(fOpacity > 0.0 && Display_none != getDisplay()) - { - drawinglayer::primitive2d::Primitive2DContainer aContent; + const double fOpacity(pStyle->getOpacity().getNumber()); - // decompose children - SvgNode::decomposeSvgNode(aContent, bReferenced); + if(fOpacity > 0.0 && Display_none != getDisplay()) + { + drawinglayer::primitive2d::Primitive2DContainer aContent; - if(!aContent.empty()) - { - pStyle->add_postProcess(rTarget, aContent, getTransform()); - } + // decompose children + SvgNode::decomposeSvgNode(aContent, bReferenced); + + if(!aContent.empty()) + { + pStyle->add_postProcess(rTarget, aContent, getTransform()); } } } diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx index 70e99384b440..edd77e2921eb 100644 --- a/svgio/source/svgreader/svgcharacternode.cxx +++ b/svgio/source/svgreader/svgcharacternode.cxx @@ -503,36 +503,36 @@ namespace svgio rSvgTextPosition, rSvgStyleAttributes)); - if(xRef.is() && (Visibility_visible == rSvgStyleAttributes.getVisibility())) - { - if(!rSvgTextPosition.isRotated()) - { - rTarget.push_back(xRef); - } - else - { - // need to apply rotations to each character as given - const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = - dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get()); + if(!(xRef.is() && (Visibility_visible == rSvgStyleAttributes.getVisibility()))) + return; - if(pCandidate) - { - const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition); - const drawinglayer::primitive2d::Primitive2DContainer& aResult( - alocalTextBreakupHelper.getResult()); + if(!rSvgTextPosition.isRotated()) + { + rTarget.push_back(xRef); + } + else + { + // need to apply rotations to each character as given + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = + dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get()); - if(!aResult.empty()) - { - rTarget.append(aResult); - } + if(pCandidate) + { + const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition); + const drawinglayer::primitive2d::Primitive2DContainer& aResult( + alocalTextBreakupHelper.getResult()); - // also consume for the implied single space - rSvgTextPosition.consumeRotation(); - } - else + if(!aResult.empty()) { - OSL_ENSURE(false, "Used primitive is not a text primitive (!)"); + rTarget.append(aResult); } + + // also consume for the implied single space + rSvgTextPosition.consumeRotation(); + } + else + { + OSL_ENSURE(false, "Used primitive is not a text primitive (!)"); } } } diff --git a/svgio/source/svgreader/svgcirclenode.cxx b/svgio/source/svgreader/svgcirclenode.cxx index b2b6b4a07b99..3684615691fb 100644 --- a/svgio/source/svgreader/svgcirclenode.cxx +++ b/svgio/source/svgreader/svgcirclenode.cxx @@ -115,28 +115,28 @@ namespace svgio { const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle && getR().isSet()) - { - const double fR(getR().solve(*this)); + if(!(pStyle && getR().isSet())) + return; - if(fR > 0.0) - { - const basegfx::B2DPolygon aPath( - basegfx::utils::createPolygonFromCircle( - basegfx::B2DPoint( - getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, - getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), - fR)); + const double fR(getR().solve(*this)); - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + if(fR <= 0.0) + return; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + const basegfx::B2DPolygon aPath( + basegfx::utils::createPolygonFromCircle( + basegfx::B2DPoint( + getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, + getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), + fR)); - if(!aNewTarget.empty()) - { - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } - } + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + + if(!aNewTarget.empty()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svgclippathnode.cxx b/svgio/source/svgreader/svgclippathnode.cxx index bda50ab3777f..090a795da3ac 100644 --- a/svgio/source/svgreader/svgclippathnode.cxx +++ b/svgio/source/svgreader/svgclippathnode.cxx @@ -103,23 +103,23 @@ namespace svgio // decompose children SvgNode::decomposeSvgNode(aNewTarget, bReferenced); - if(!aNewTarget.empty()) + if(aNewTarget.empty()) + return; + + if(getTransform()) { - if(getTransform()) - { - // create embedding group element with transformation - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - *getTransform(), - aNewTarget)); + // create embedding group element with transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *getTransform(), + aNewTarget)); - rTarget.push_back(xRef); - } - else - { - // append to current target - rTarget.append(aNewTarget); - } + rTarget.push_back(xRef); + } + else + { + // append to current target + rTarget.append(aNewTarget); } } @@ -127,132 +127,132 @@ namespace svgio drawinglayer::primitive2d::Primitive2DContainer& rContent, const basegfx::B2DHomMatrix* pTransform) const { - if(!rContent.empty() && Display_none != getDisplay()) - { - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; - drawinglayer::primitive2d::Primitive2DContainer aClipTarget; - basegfx::B2DPolyPolygon aClipPolyPolygon; + if(!(!rContent.empty() && Display_none != getDisplay())) + return; - // get clipPath definition as primitives - decomposeSvgNode(aClipTarget, true); + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::primitive2d::Primitive2DContainer aClipTarget; + basegfx::B2DPolyPolygon aClipPolyPolygon; - if(!aClipTarget.empty()) - { - // extract filled polygons as base for a mask PolyPolygon - drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, true); + // get clipPath definition as primitives + decomposeSvgNode(aClipTarget, true); - aExtractor.process(aClipTarget); + if(!aClipTarget.empty()) + { + // extract filled polygons as base for a mask PolyPolygon + drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, true); - const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour()); - const sal_uInt32 nSize(rResult.size()); + aExtractor.process(aClipTarget); - if(nSize > 1) - { - // merge to single clipPolyPolygon - aClipPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(rResult); - } - else - { - aClipPolyPolygon = rResult[0]; - } + const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour()); + const sal_uInt32 nSize(rResult.size()); + + if(nSize > 1) + { + // merge to single clipPolyPolygon + aClipPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(rResult); + } + else + { + aClipPolyPolygon = rResult[0]; } + } - if(aClipPolyPolygon.count()) + if(aClipPolyPolygon.count()) + { + if(objectBoundingBox == getClipPathUnits()) { - if(objectBoundingBox == getClipPathUnits()) - { - // clip is object-relative, transform using content transformation - const basegfx::B2DRange aContentRange(rContent.getB2DRange(aViewInformation2D)); + // clip is object-relative, transform using content transformation + const basegfx::B2DRange aContentRange(rContent.getB2DRange(aViewInformation2D)); - aClipPolyPolygon.transform( - basegfx::utils::createScaleTranslateB2DHomMatrix( - aContentRange.getRange(), - aContentRange.getMinimum())); - } - else // userSpaceOnUse + aClipPolyPolygon.transform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + aContentRange.getRange(), + aContentRange.getMinimum())); + } + else // userSpaceOnUse + { + // #i124852# + if(pTransform) { - // #i124852# - if(pTransform) - { - aClipPolyPolygon.transform(*pTransform); - } + aClipPolyPolygon.transform(*pTransform); } + } - // #i124313# try to avoid creating an embedding to a MaskPrimitive2D if - // possible; MaskPrimitive2D processing is potentially expensive - bool bCreateEmbedding(true); - bool bAddContent(true); - - if(basegfx::utils::isRectangle(aClipPolyPolygon)) - { - // ClipRegion is a rectangle, thus it is not expensive to tell - // if the content is completely inside or outside of it; get ranges - const basegfx::B2DRange aClipRange(aClipPolyPolygon.getB2DRange()); - const basegfx::B2DRange aContentRange( - rContent.getB2DRange( - aViewInformation2D)); + // #i124313# try to avoid creating an embedding to a MaskPrimitive2D if + // possible; MaskPrimitive2D processing is potentially expensive + bool bCreateEmbedding(true); + bool bAddContent(true); - if(aClipRange.isInside(aContentRange)) - { - // completely contained, no need to clip at all, so no need for embedding - bCreateEmbedding = false; - } - else if(aClipRange.overlaps(aContentRange)) - { - // overlap; embedding needed. ClipRegion can be minimized by using - // the intersection of the ClipRange and the ContentRange. Minimizing - // the ClipRegion potentially enhances further processing since - // usually clip operations are expensive. - basegfx::B2DRange aCommonRange(aContentRange); + if(basegfx::utils::isRectangle(aClipPolyPolygon)) + { + // ClipRegion is a rectangle, thus it is not expensive to tell + // if the content is completely inside or outside of it; get ranges + const basegfx::B2DRange aClipRange(aClipPolyPolygon.getB2DRange()); + const basegfx::B2DRange aContentRange( + rContent.getB2DRange( + aViewInformation2D)); - aCommonRange.intersect(aClipRange); - aClipPolyPolygon = basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aCommonRange)); - } - else - { - // not inside and no overlap -> completely outside - // no need for embedding, no need for content at all - bCreateEmbedding = false; - bAddContent = false; - } - } - else + if(aClipRange.isInside(aContentRange)) { - // ClipRegion is not a simple rectangle, it would be possible but expensive to - // tell if the content needs clipping or not. It is also dependent of - // the content's decomposition. To do this, a processor would be needed that - // is capable if processing the given sequence of primitives and decide - // if all is inside or all is outside. Such a ClipProcessor could be written, - // but for now just create the embedding + // completely contained, no need to clip at all, so no need for embedding + bCreateEmbedding = false; } - - if(bCreateEmbedding) + else if(aClipRange.overlaps(aContentRange)) { - // redefine target. Use MaskPrimitive2D with created clip - // geometry. Using the automatically set mbIsClipPathContent at - // SvgStyleAttributes the clip definition is without fill, stroke, - // and strokeWidth and forced to black - const drawinglayer::primitive2d::Primitive2DReference xEmbedTransparence( - new drawinglayer::primitive2d::MaskPrimitive2D( - aClipPolyPolygon, - rContent)); + // overlap; embedding needed. ClipRegion can be minimized by using + // the intersection of the ClipRange and the ContentRange. Minimizing + // the ClipRegion potentially enhances further processing since + // usually clip operations are expensive. + basegfx::B2DRange aCommonRange(aContentRange); - rContent = drawinglayer::primitive2d::Primitive2DContainer { xEmbedTransparence }; + aCommonRange.intersect(aClipRange); + aClipPolyPolygon = basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aCommonRange)); } else { - if(!bAddContent) - { - rContent.clear(); - } + // not inside and no overlap -> completely outside + // no need for embedding, no need for content at all + bCreateEmbedding = false; + bAddContent = false; } } else { - // An empty clipping path will completely clip away the element that had - // the clip-path property applied. (Svg spec) - rContent.clear(); + // ClipRegion is not a simple rectangle, it would be possible but expensive to + // tell if the content needs clipping or not. It is also dependent of + // the content's decomposition. To do this, a processor would be needed that + // is capable if processing the given sequence of primitives and decide + // if all is inside or all is outside. Such a ClipProcessor could be written, + // but for now just create the embedding } + + if(bCreateEmbedding) + { + // redefine target. Use MaskPrimitive2D with created clip + // geometry. Using the automatically set mbIsClipPathContent at + // SvgStyleAttributes the clip definition is without fill, stroke, + // and strokeWidth and forced to black + const drawinglayer::primitive2d::Primitive2DReference xEmbedTransparence( + new drawinglayer::primitive2d::MaskPrimitive2D( + aClipPolyPolygon, + rContent)); + + rContent = drawinglayer::primitive2d::Primitive2DContainer { xEmbedTransparence }; + } + else + { + if(!bAddContent) + { + rContent.clear(); + } + } + } + else + { + // An empty clipping path will completely clip away the element that had + // the clip-path property applied. (Svg spec) + rContent.clear(); } } diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx b/svgio/source/svgreader/svgdocumenthandler.cxx index d32534d9896e..9123135fa565 100644 --- a/svgio/source/svgreader/svgdocumenthandler.cxx +++ b/svgio/source/svgreader/svgdocumenthandler.cxx @@ -176,455 +176,455 @@ namespace svgio { if (bSkip) return; - if(!aName.isEmpty()) + if(aName.isEmpty()) + return; + + const SVGToken aSVGToken(StrToSVGToken(aName, false)); + + switch(aSVGToken) { - const SVGToken aSVGToken(StrToSVGToken(aName, false)); + /// structural elements + case SVGTokenSymbol: + { + /// new basic node for Symbol. Content gets scanned, but + /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) + mpTarget = new SvgSymbolNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenDefs: + case SVGTokenG: + { + /// new node for Defs/G + mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenSvg: + { + /// new node for Svg + mpTarget = new SvgSvgNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenUse: + { + /// new node for Use + mpTarget = new SvgUseNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenA: + { + /// new node for A + mpTarget = new SvgANode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - switch(aSVGToken) + /// shape elements + case SVGTokenCircle: { - /// structural elements - case SVGTokenSymbol: - { - /// new basic node for Symbol. Content gets scanned, but - /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) - mpTarget = new SvgSymbolNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenDefs: - case SVGTokenG: - { - /// new node for Defs/G - mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenSvg: - { - /// new node for Svg - mpTarget = new SvgSvgNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenUse: - { - /// new node for Use - mpTarget = new SvgUseNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenA: - { - /// new node for A - mpTarget = new SvgANode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// new node for Circle + mpTarget = new SvgCircleNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenEllipse: + { + /// new node for Ellipse + mpTarget = new SvgEllipseNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenLine: + { + /// new node for Line + mpTarget = new SvgLineNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPath: + { + /// new node for Path + mpTarget = new SvgPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPolygon: + { + /// new node for Polygon + mpTarget = new SvgPolyNode(maDocument, mpTarget, false); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPolyline: + { + /// new node for Polyline + mpTarget = new SvgPolyNode(maDocument, mpTarget, true); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenRect: + { + /// new node for Rect + mpTarget = new SvgRectNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenImage: + { + /// new node for Image + mpTarget = new SvgImageNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// shape elements - case SVGTokenCircle: - { - /// new node for Circle - mpTarget = new SvgCircleNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenEllipse: - { - /// new node for Ellipse - mpTarget = new SvgEllipseNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenLine: - { - /// new node for Line - mpTarget = new SvgLineNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenPath: - { - /// new node for Path - mpTarget = new SvgPathNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenPolygon: - { - /// new node for Polygon - mpTarget = new SvgPolyNode(maDocument, mpTarget, false); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenPolyline: - { - /// new node for Polyline - mpTarget = new SvgPolyNode(maDocument, mpTarget, true); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenRect: - { - /// new node for Rect - mpTarget = new SvgRectNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenImage: - { - /// new node for Image - mpTarget = new SvgImageNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// title and description + case SVGTokenTitle: + case SVGTokenDesc: + { + /// new node for Title and/or Desc + mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget); + break; + } - /// title and description - case SVGTokenTitle: - case SVGTokenDesc: - { - /// new node for Title and/or Desc - mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget); - break; - } + /// gradients + case SVGTokenLinearGradient: + case SVGTokenRadialGradient: + { + mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// gradients - case SVGTokenLinearGradient: - case SVGTokenRadialGradient: - { - mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// gradient stops + case SVGTokenStop: + { + mpTarget = new SvgGradientStopNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// gradient stops - case SVGTokenStop: - { - mpTarget = new SvgGradientStopNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// text + case SVGTokenText: + { + mpTarget = new SvgTextNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTspan: + { + mpTarget = new SvgTspanNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTref: + { + mpTarget = new SvgTrefNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTextPath: + { + mpTarget = new SvgTextPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// text - case SVGTokenText: - { - mpTarget = new SvgTextNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenTspan: - { - mpTarget = new SvgTspanNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenTref: + /// styles (as stylesheets) + case SVGTokenStyle: + { + SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget); + mpTarget = pNew; + const sal_uInt32 nAttributes(xAttribs->getLength()); + + if(0 == nAttributes) { - mpTarget = new SvgTrefNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; + // #i125326# no attributes, thus also no type="text/css". This is allowed to be missing, + // thus do mark this style as CssStyle. This is required to read the contained + // text (which defines the css style) + pNew->setTextCss(true); } - case SVGTokenTextPath: + else { - mpTarget = new SvgTextPathNode(maDocument, mpTarget); + // #i125326# there are attributes, read them. This will set isTextCss to true if + // a type="text/css" is contained as exact match, else not mpTarget->parseAttributes(xAttribs); - break; } - /// styles (as stylesheets) - case SVGTokenStyle: + if(pNew->isTextCss()) { - SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget); - mpTarget = pNew; - const sal_uInt32 nAttributes(xAttribs->getLength()); - - if(0 == nAttributes) - { - // #i125326# no attributes, thus also no type="text/css". This is allowed to be missing, - // thus do mark this style as CssStyle. This is required to read the contained - // text (which defines the css style) - pNew->setTextCss(true); - } - else - { - // #i125326# there are attributes, read them. This will set isTextCss to true if - // a type="text/css" is contained as exact match, else not - mpTarget->parseAttributes(xAttribs); - } - - if(pNew->isTextCss()) - { - // if it is a Css style, allow reading text between the start and end tag (see - // SvgDocHdl::characters for details) - maCssContents.emplace_back(); - } - break; + // if it is a Css style, allow reading text between the start and end tag (see + // SvgDocHdl::characters for details) + maCssContents.emplace_back(); } + break; + } - /// structural elements clip-path and mask. Content gets scanned, but - /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) - case SVGTokenClipPathNode: - { - /// new node for ClipPath - mpTarget = new SvgClipPathNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } - case SVGTokenMask: - { - /// new node for Mask - mpTarget = new SvgMaskNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// structural elements clip-path and mask. Content gets scanned, but + /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) + case SVGTokenClipPathNode: + { + /// new node for ClipPath + mpTarget = new SvgClipPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenMask: + { + /// new node for Mask + mpTarget = new SvgMaskNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// structural element marker - case SVGTokenMarker: - { - /// new node for marker - mpTarget = new SvgMarkerNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// structural element marker + case SVGTokenMarker: + { + /// new node for marker + mpTarget = new SvgMarkerNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - /// structural element pattern - case SVGTokenPattern: - { - /// new node for pattern - mpTarget = new SvgPatternNode(maDocument, mpTarget); - mpTarget->parseAttributes(xAttribs); - break; - } + /// structural element pattern + case SVGTokenPattern: + { + /// new node for pattern + mpTarget = new SvgPatternNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } - // ignore FlowRoot and child nodes - case SVGTokenFlowRoot: - { - bSkip = true; - break; - } + // ignore FlowRoot and child nodes + case SVGTokenFlowRoot: + { + bSkip = true; + break; + } - default: - { - /// invalid token, ignore - SAL_WARN( "svgio", "Unknown Base SvgToken <" + aName + "> (!)" ); - break; - } + default: + { + /// invalid token, ignore + SAL_WARN( "svgio", "Unknown Base SvgToken <" + aName + "> (!)" ); + break; } } } void SvgDocHdl::endElement( const OUString& aName ) { - if(!aName.isEmpty()) + if(aName.isEmpty()) + return; + + const SVGToken aSVGToken(StrToSVGToken(aName, false)); + SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : nullptr); + SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : nullptr); + SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : nullptr); + + // if we are in skipping mode and we reach the flowRoot end tag: stop skipping mode + if(bSkip && aSVGToken == SVGTokenFlowRoot) + bSkip = false; + // we are in skipping mode: do nothing until we found the flowRoot end tag + else if(bSkip) + return; + + switch(aSVGToken) { - const SVGToken aSVGToken(StrToSVGToken(aName, false)); - SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : nullptr); - SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : nullptr); - SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : nullptr); - - // if we are in skipping mode and we reach the flowRoot end tag: stop skipping mode - if(bSkip && aSVGToken == SVGTokenFlowRoot) - bSkip = false; - // we are in skipping mode: do nothing until we found the flowRoot end tag - else if(bSkip) - return; - - switch(aSVGToken) - { - /// valid tokens for which a new one was created - - /// structural elements - case SVGTokenDefs: - case SVGTokenG: - case SVGTokenSvg: - case SVGTokenSymbol: - case SVGTokenUse: - case SVGTokenA: - - /// shape elements - case SVGTokenCircle: - case SVGTokenEllipse: - case SVGTokenLine: - case SVGTokenPath: - case SVGTokenPolygon: - case SVGTokenPolyline: - case SVGTokenRect: - case SVGTokenImage: - - /// title and description - case SVGTokenTitle: - case SVGTokenDesc: - - /// gradients - case SVGTokenLinearGradient: - case SVGTokenRadialGradient: - - /// gradient stops - case SVGTokenStop: - - /// text - case SVGTokenText: - case SVGTokenTspan: - case SVGTokenTextPath: - case SVGTokenTref: - - /// styles (as stylesheets) - case SVGTokenStyle: - - /// structural elements clip-path and mask - case SVGTokenClipPathNode: - case SVGTokenMask: - - /// structural element marker - case SVGTokenMarker: - - /// structural element pattern - case SVGTokenPattern: - - /// content handling after parsing + /// valid tokens for which a new one was created + + /// structural elements + case SVGTokenDefs: + case SVGTokenG: + case SVGTokenSvg: + case SVGTokenSymbol: + case SVGTokenUse: + case SVGTokenA: + + /// shape elements + case SVGTokenCircle: + case SVGTokenEllipse: + case SVGTokenLine: + case SVGTokenPath: + case SVGTokenPolygon: + case SVGTokenPolyline: + case SVGTokenRect: + case SVGTokenImage: + + /// title and description + case SVGTokenTitle: + case SVGTokenDesc: + + /// gradients + case SVGTokenLinearGradient: + case SVGTokenRadialGradient: + + /// gradient stops + case SVGTokenStop: + + /// text + case SVGTokenText: + case SVGTokenTspan: + case SVGTokenTextPath: + case SVGTokenTref: + + /// styles (as stylesheets) + case SVGTokenStyle: + + /// structural elements clip-path and mask + case SVGTokenClipPathNode: + case SVGTokenMask: + + /// structural element marker + case SVGTokenMarker: + + /// structural element pattern + case SVGTokenPattern: + + /// content handling after parsing + { + if(mpTarget) { - if(mpTarget) - { - if(!mpTarget->getParent()) - { - // last element closing, save this tree - maDocument.appendNode(std::unique_ptr<SvgNode>(mpTarget)); - } - - mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); - } - else + if(!mpTarget->getParent()) { - OSL_ENSURE(false, "Closing token, but no context (!)"); + // last element closing, save this tree + maDocument.appendNode(std::unique_ptr<SvgNode>(mpTarget)); } - break; + + mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); } - default: + else { - /// invalid token, ignore + OSL_ENSURE(false, "Closing token, but no context (!)"); } + break; } - - if(pSvgTitleDescNode && mpTarget) + default: { - const OUString& aText(pSvgTitleDescNode->getText()); + /// invalid token, ignore + } + } - if(!aText.isEmpty()) + if(pSvgTitleDescNode && mpTarget) + { + const OUString& aText(pSvgTitleDescNode->getText()); + + if(!aText.isEmpty()) + { + if(SVGTokenTitle == aSVGToken) { - if(SVGTokenTitle == aSVGToken) - { - mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText); - } - else // if(SVGTokenDesc == aSVGToken) - { - mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText); - } + mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText); + } + else // if(SVGTokenDesc == aSVGToken) + { + mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText); } } + } - if(pCssStyle && pCssStyle->isTextCss()) + if(pCssStyle && pCssStyle->isTextCss()) + { + // css style parsing + if(!maCssContents.empty()) { - // css style parsing - if(!maCssContents.empty()) - { - // need to interpret css styles and remember them as StyleSheets - // #125325# Caution! the Css content may contain block comments - // (see http://www.w3.org/wiki/CSS_basics#CSS_comments). These need - // to be removed first - const OUString aCommentFreeSource(removeBlockComments(*(maCssContents.end() - 1))); - - if(aCommentFreeSource.getLength()) - { - pCssStyle->addCssStyleSheet(aCommentFreeSource); - } + // need to interpret css styles and remember them as StyleSheets + // #125325# Caution! the Css content may contain block comments + // (see http://www.w3.org/wiki/CSS_basics#CSS_comments). These need + // to be removed first + const OUString aCommentFreeSource(removeBlockComments(*(maCssContents.end() - 1))); - maCssContents.pop_back(); - } - else + if(aCommentFreeSource.getLength()) { - OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); + pCssStyle->addCssStyleSheet(aCommentFreeSource); } - } - if(pWhitespaceCheck) + maCssContents.pop_back(); + } + else { - // cleanup read strings - whiteSpaceHandling(pWhitespaceCheck, nullptr); + OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); } } + + if(pWhitespaceCheck) + { + // cleanup read strings + whiteSpaceHandling(pWhitespaceCheck, nullptr); + } } void SvgDocHdl::characters( const OUString& aChars ) { const sal_uInt32 nLength(aChars.getLength()); - if(mpTarget && nLength) + if(!(mpTarget && nLength)) + return; + + switch(mpTarget->getType()) { - switch(mpTarget->getType()) + case SVGTokenText: + case SVGTokenTspan: + case SVGTokenTextPath: { - case SVGTokenText: - case SVGTokenTspan: - case SVGTokenTextPath: - { - const auto& rChilds = mpTarget->getChildren(); - SvgCharacterNode* pTarget = nullptr; + const auto& rChilds = mpTarget->getChildren(); + SvgCharacterNode* pTarget = nullptr; - if(!rChilds.empty()) - { - pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1].get()); - } + if(!rChilds.empty()) + { + pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1].get()); + } - if(pTarget) - { - // concatenate to current character span - pTarget->concatenate(aChars); - } - else - { - // add character span as simplified tspan (no arguments) - // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode - new SvgCharacterNode(maDocument, mpTarget, aChars); - } - break; + if(pTarget) + { + // concatenate to current character span + pTarget->concatenate(aChars); } - case SVGTokenStyle: + else { - SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); + // add character span as simplified tspan (no arguments) + // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode + new SvgCharacterNode(maDocument, mpTarget, aChars); + } + break; + } + case SVGTokenStyle: + { + SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); - if(rSvgStyleNode.isTextCss()) + if(rSvgStyleNode.isTextCss()) + { + // collect characters for css style + if(!maCssContents.empty()) { - // collect characters for css style - if(!maCssContents.empty()) - { - const OUString aTrimmedChars(aChars.trim()); + const OUString aTrimmedChars(aChars.trim()); - if(!aTrimmedChars.isEmpty()) - { - std::vector< OUString >::iterator aString(maCssContents.end() - 1); - (*aString) += aTrimmedChars; - } - } - else + if(!aTrimmedChars.isEmpty()) { - OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); + std::vector< OUString >::iterator aString(maCssContents.end() - 1); + (*aString) += aTrimmedChars; } } - break; + else + { + OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); + } } - case SVGTokenTitle: - case SVGTokenDesc: - { - SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget); + break; + } + case SVGTokenTitle: + case SVGTokenDesc: + { + SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget); - // add text directly to SvgTitleDescNode - rSvgTitleDescNode.concatenate(aChars); - break; - } - default: - { - // characters not used by a known node - break; - } + // add text directly to SvgTitleDescNode + rSvgTitleDescNode.concatenate(aChars); + break; + } + default: + { + // characters not used by a known node + break; } } } diff --git a/svgio/source/svgreader/svgellipsenode.cxx b/svgio/source/svgreader/svgellipsenode.cxx index c76b5c538c03..4454b9d696f2 100644 --- a/svgio/source/svgreader/svgellipsenode.cxx +++ b/svgio/source/svgreader/svgellipsenode.cxx @@ -129,29 +129,29 @@ namespace svgio { const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle && getRx().isSet() && getRy().isSet()) - { - const double fRx(getRx().solve(*this, xcoordinate)); - const double fRy(getRy().solve(*this, ycoordinate)); + if(!(pStyle && getRx().isSet() && getRy().isSet())) + return; - if(fRx > 0.0 && fRy > 0.0) - { - const basegfx::B2DPolygon aPath( - basegfx::utils::createPolygonFromEllipse( - basegfx::B2DPoint( - getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, - getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), - fRx, fRy)); + const double fRx(getRx().solve(*this, xcoordinate)); + const double fRy(getRy().solve(*this, ycoordinate)); - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + if(!(fRx > 0.0 && fRy > 0.0)) + return; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + const basegfx::B2DPolygon aPath( + basegfx::utils::createPolygonFromEllipse( + basegfx::B2DPoint( + getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, + getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), + fRx, fRy)); - if(!aNewTarget.empty()) - { - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } - } + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + + if(!aNewTarget.empty()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svgimagenode.cxx b/svgio/source/svgreader/svgimagenode.cxx index 7224eabb8f2d..1e0861c86b03 100644 --- a/svgio/source/svgreader/svgimagenode.cxx +++ b/svgio/source/svgreader/svgimagenode.cxx @@ -193,169 +193,169 @@ namespace svgio // get size range and create path const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle && getWidth().isSet() && getHeight().isSet()) - { - const double fWidth(getWidth().solve(*this, xcoordinate)); - const double fHeight(getHeight().solve(*this, ycoordinate)); + if(!(pStyle && getWidth().isSet() && getHeight().isSet())) + return; - if(fWidth > 0.0 && fHeight > 0.0) - { - BitmapEx aBitmapEx; - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + const double fWidth(getWidth().solve(*this, xcoordinate)); + const double fHeight(getHeight().solve(*this, ycoordinate)); - // prepare Target and ViewBox for evtl. AspectRatio mappings - const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); - const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); - const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight); - basegfx::B2DRange aViewBox(aTarget); + if(!(fWidth > 0.0 && fHeight > 0.0)) + return; - if(!maMimeType.isEmpty() && !maData.isEmpty()) - { - // use embedded base64 encoded data - css::uno::Sequence< sal_Int8 > aPass; - ::comphelper::Base64::decode(aPass, maData); + BitmapEx aBitmapEx; + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - if(aPass.hasElements()) - { - SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), StreamMode::READ); - Graphic aGraphic; - - if(ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic( - aGraphic, - OUString(), - aStream)) - { - extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); - } - } - } - else if(!maUrl.isEmpty()) - { - const OUString& rPath = getDocument().getAbsolutePath(); - OUString aAbsUrl; - try { - aAbsUrl = rtl::Uri::convertRelToAbs(rPath, maUrl); - } catch (rtl::MalformedUriException & e) { - SAL_WARN( - "svg", - "caught rtl::MalformedUriException \"" - << e.getMessage() << "\""); - } + // prepare Target and ViewBox for evtl. AspectRatio mappings + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight); + basegfx::B2DRange aViewBox(aTarget); - if (!aAbsUrl.isEmpty() && rPath != aAbsUrl) - { - SvFileStream aStream(aAbsUrl, StreamMode::STD_READ); - Graphic aGraphic; - - if(ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic( - aGraphic, - aAbsUrl, - aStream)) - { - extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); - } - } - } - else if(!maXLink.isEmpty()) - { - const SvgNode* pXLink = getDocument().findSvgNodeById(maXLink); - - if(pXLink && Display_none != pXLink->getDisplay()) - { - pXLink->decomposeSvgNode(aNewTarget, true); + if(!maMimeType.isEmpty() && !maData.isEmpty()) + { + // use embedded base64 encoded data + css::uno::Sequence< sal_Int8 > aPass; + ::comphelper::Base64::decode(aPass, maData); - if(!aNewTarget.empty()) - { - aViewBox = aNewTarget.getB2DRange(drawinglayer::geometry::ViewInformation2D()); - } - } - } + if(aPass.hasElements()) + { + SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), StreamMode::READ); + Graphic aGraphic; - if(!aBitmapEx.IsEmpty() && 0 != aBitmapEx.GetSizePixel().Width() && 0 != aBitmapEx.GetSizePixel().Height()) + if(ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic( + aGraphic, + OUString(), + aStream)) { - // calculate centered unit size - const double fAspectRatio = static_cast<double>(aBitmapEx.GetSizePixel().Width()) / static_cast<double>(aBitmapEx.GetSizePixel().Height()); + extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); + } + } + } + else if(!maUrl.isEmpty()) + { + const OUString& rPath = getDocument().getAbsolutePath(); + OUString aAbsUrl; + try { + aAbsUrl = rtl::Uri::convertRelToAbs(rPath, maUrl); + } catch (rtl::MalformedUriException & e) { + SAL_WARN( + "svg", + "caught rtl::MalformedUriException \"" + << e.getMessage() << "\""); + } - if(basegfx::fTools::equal(fAspectRatio, 0.0)) - { - // use unit range - aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); - } - else if(basegfx::fTools::more(fAspectRatio, 0.0)) - { - // width bigger height - const double fHalfHeight((1.0 / fAspectRatio) * 0.5); - aViewBox = basegfx::B2DRange( - 0.0, - 0.5 - fHalfHeight, - 1.0, - 0.5 + fHalfHeight); - } - else - { - // height bigger width - const double fHalfWidth(fAspectRatio * 0.5); - aViewBox = basegfx::B2DRange( - 0.5 - fHalfWidth, - 0.0, - 0.5 + fHalfWidth, - 1.0); - } + if (!aAbsUrl.isEmpty() && rPath != aAbsUrl) + { + SvFileStream aStream(aAbsUrl, StreamMode::STD_READ); + Graphic aGraphic; - // create content from created bitmap, use calculated unit range size - // as transformation to map the picture data correctly - aNewTarget.resize(1); - aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D( - aBitmapEx, - basegfx::utils::createScaleTranslateB2DHomMatrix( - aViewBox.getRange(), - aViewBox.getMinimum())); + if(ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic( + aGraphic, + aAbsUrl, + aStream)) + { + extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); } + } + } + else if(!maXLink.isEmpty()) + { + const SvgNode* pXLink = getDocument().findSvgNodeById(maXLink); + + if(pXLink && Display_none != pXLink->getDisplay()) + { + pXLink->decomposeSvgNode(aNewTarget, true); if(!aNewTarget.empty()) { - if(aTarget.equal(aViewBox)) - { - // just add to rTarget - rTarget.append(aNewTarget); - } - else - { - // create mapping - const SvgAspectRatio& rRatio = maSvgAspectRatio; - - // even when ratio is not set, use the defaults - // let mapping be created from SvgAspectRatio - const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox)); - - if(!aEmbeddingTransform.isIdentity()) - { - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - aEmbeddingTransform, - aNewTarget)); - - aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } - - if(!rRatio.isMeetOrSlice()) - { - // need to embed in MaskPrimitive2D to ensure clipping - const drawinglayer::primitive2d::Primitive2DReference xMask( - new drawinglayer::primitive2d::MaskPrimitive2D( - basegfx::B2DPolyPolygon( - basegfx::utils::createPolygonFromRect(aTarget)), - aNewTarget)); - - aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xMask }; - } - - // embed and add to rTarget, take local extra-transform into account - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } + aViewBox = aNewTarget.getB2DRange(drawinglayer::geometry::ViewInformation2D()); } } } + + if(!aBitmapEx.IsEmpty() && 0 != aBitmapEx.GetSizePixel().Width() && 0 != aBitmapEx.GetSizePixel().Height()) + { + // calculate centered unit size + const double fAspectRatio = static_cast<double>(aBitmapEx.GetSizePixel().Width()) / static_cast<double>(aBitmapEx.GetSizePixel().Height()); + + if(basegfx::fTools::equal(fAspectRatio, 0.0)) + { + // use unit range + aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); + } + else if(basegfx::fTools::more(fAspectRatio, 0.0)) + { + // width bigger height + const double fHalfHeight((1.0 / fAspectRatio) * 0.5); + aViewBox = basegfx::B2DRange( + 0.0, + 0.5 - fHalfHeight, + 1.0, + 0.5 + fHalfHeight); + } + else + { + // height bigger width + const double fHalfWidth(fAspectRatio * 0.5); + aViewBox = basegfx::B2DRange( + 0.5 - fHalfWidth, + 0.0, + 0.5 + fHalfWidth, + 1.0); + } + + // create content from created bitmap, use calculated unit range size + // as transformation to map the picture data correctly + aNewTarget.resize(1); + aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D( + aBitmapEx, + basegfx::utils::createScaleTranslateB2DHomMatrix( + aViewBox.getRange(), + aViewBox.getMinimum())); + } + + if(aNewTarget.empty()) + return; + + if(aTarget.equal(aViewBox)) + { + // just add to rTarget + rTarget.append(aNewTarget); + } + else + { + // create mapping + const SvgAspectRatio& rRatio = maSvgAspectRatio; + + // even when ratio is not set, use the defaults + // let mapping be created from SvgAspectRatio + const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox)); + + if(!aEmbeddingTransform.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; + } + + if(!rRatio.isMeetOrSlice()) + { + // need to embed in MaskPrimitive2D to ensure clipping + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect(aTarget)), + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xMask }; + } + + // embed and add to rTarget, take local extra-transform into account + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svglinenode.cxx b/svgio/source/svgreader/svglinenode.cxx index bce24f675334..bb3eae92adee 100644 --- a/svgio/source/svgreader/svglinenode.cxx +++ b/svgio/source/svgreader/svglinenode.cxx @@ -123,31 +123,31 @@ namespace svgio { const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle) - { - const basegfx::B2DPoint X( - getX1().isSet() ? getX1().solve(*this, xcoordinate) : 0.0, - getY1().isSet() ? getY1().solve(*this, ycoordinate) : 0.0); - const basegfx::B2DPoint Y( - getX2().isSet() ? getX2().solve(*this, xcoordinate) : 0.0, - getY2().isSet() ? getY2().solve(*this, ycoordinate) : 0.0); + if(!pStyle) + return; - // X and Y may be equal, do not drop them. Markers or linecaps 'round' and 'square' - // need to be drawn for zero-length lines too. + const basegfx::B2DPoint X( + getX1().isSet() ? getX1().solve(*this, xcoordinate) : 0.0, + getY1().isSet() ? getY1().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DPoint Y( + getX2().isSet() ? getX2().solve(*this, xcoordinate) : 0.0, + getY2().isSet() ? getY2().solve(*this, ycoordinate) : 0.0); - basegfx::B2DPolygon aPath; + // X and Y may be equal, do not drop them. Markers or linecaps 'round' and 'square' + // need to be drawn for zero-length lines too. - aPath.append(X); - aPath.append(Y); + basegfx::B2DPolygon aPath; - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + aPath.append(X); + aPath.append(Y); - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - if(!aNewTarget.empty()) - { - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + + if(!aNewTarget.empty()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svgmasknode.cxx b/svgio/source/svgreader/svgmasknode.cxx index 85d9b7f2e4b5..f2a919c4582f 100644 --- a/svgio/source/svgreader/svgmasknode.cxx +++ b/svgio/source/svgreader/svgmasknode.cxx @@ -170,148 +170,148 @@ namespace svgio // decompose children SvgNode::decomposeSvgNode(aNewTarget, bReferenced); - if(!aNewTarget.empty()) - { - if(getTransform()) - { - // create embedding group element with transformation - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - *getTransform(), - aNewTarget)); + if(aNewTarget.empty()) + return; - aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + if(getTransform()) + { + // create embedding group element with transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *getTransform(), + aNewTarget)); - // append to current target - rTarget.append(aNewTarget); + aNewTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; } + + // append to current target + rTarget.append(aNewTarget); } void SvgMaskNode::apply( drawinglayer::primitive2d::Primitive2DContainer& rTarget, const basegfx::B2DHomMatrix* pTransform) const { - if(!rTarget.empty() && Display_none != getDisplay()) - { - drawinglayer::primitive2d::Primitive2DContainer aMaskTarget; + if(!(!rTarget.empty() && Display_none != getDisplay())) + return; + + drawinglayer::primitive2d::Primitive2DContainer aMaskTarget; - // get mask definition as primitives - decomposeSvgNode(aMaskTarget, true); + // get mask definition as primitives + decomposeSvgNode(aMaskTarget, true); - if(!aMaskTarget.empty()) + if(!aMaskTarget.empty()) + { + // get range of content to be masked + const basegfx::B2DRange aContentRange( + rTarget.getB2DRange( + drawinglayer::geometry::ViewInformation2D())); + const double fContentWidth(aContentRange.getWidth()); + const double fContentHeight(aContentRange.getHeight()); + + if(fContentWidth > 0.0 && fContentHeight > 0.0) { - // get range of content to be masked - const basegfx::B2DRange aContentRange( - rTarget.getB2DRange( - drawinglayer::geometry::ViewInformation2D())); - const double fContentWidth(aContentRange.getWidth()); - const double fContentHeight(aContentRange.getHeight()); - - if(fContentWidth > 0.0 && fContentHeight > 0.0) + // create OffscreenBufferRange + basegfx::B2DRange aOffscreenBufferRange; + + if(objectBoundingBox == maMaskUnits) { - // create OffscreenBufferRange - basegfx::B2DRange aOffscreenBufferRange; + // fractions or percentages of the bounding box of the element to which the mask is applied + const double fX(Unit_percent == getX().getUnit() ? getX().getNumber() * 0.01 : getX().getNumber()); + const double fY(Unit_percent == getY().getUnit() ? getY().getNumber() * 0.01 : getY().getNumber()); + const double fW(Unit_percent == getWidth().getUnit() ? getWidth().getNumber() * 0.01 : getWidth().getNumber()); + const double fH(Unit_percent == getHeight().getUnit() ? getHeight().getNumber() * 0.01 : getHeight().getNumber()); + + aOffscreenBufferRange = basegfx::B2DRange( + aContentRange.getMinX() + (fX * fContentWidth), + aContentRange.getMinY() + (fY * fContentHeight), + aContentRange.getMinX() + ((fX + fW) * fContentWidth), + aContentRange.getMinY() + ((fY + fH) * fContentHeight)); + } + else + { + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + + aOffscreenBufferRange = basegfx::B2DRange( + fX, + fY, + fX + (getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0), + fY + (getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0)); + } - if(objectBoundingBox == maMaskUnits) - { - // fractions or percentages of the bounding box of the element to which the mask is applied - const double fX(Unit_percent == getX().getUnit() ? getX().getNumber() * 0.01 : getX().getNumber()); - const double fY(Unit_percent == getY().getUnit() ? getY().getNumber() * 0.01 : getY().getNumber()); - const double fW(Unit_percent == getWidth().getUnit() ? getWidth().getNumber() * 0.01 : getWidth().getNumber()); - const double fH(Unit_percent == getHeight().getUnit() ? getHeight().getNumber() * 0.01 : getHeight().getNumber()); - - aOffscreenBufferRange = basegfx::B2DRange( - aContentRange.getMinX() + (fX * fContentWidth), - aContentRange.getMinY() + (fY * fContentHeight), - aContentRange.getMinX() + ((fX + fW) * fContentWidth), - aContentRange.getMinY() + ((fY + fH) * fContentHeight)); - } - else - { - const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); - const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); - - aOffscreenBufferRange = basegfx::B2DRange( - fX, - fY, - fX + (getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0), - fY + (getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0)); - } + if(objectBoundingBox == maMaskContentUnits) + { + // mask is object-relative, embed in content transformation + const drawinglayer::primitive2d::Primitive2DReference xTransform( + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::utils::createScaleTranslateB2DHomMatrix( + aContentRange.getRange(), + aContentRange.getMinimum()), + aMaskTarget)); - if(objectBoundingBox == maMaskContentUnits) + aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xTransform }; + } + else // userSpaceOnUse + { + // #i124852# + if(pTransform) { - // mask is object-relative, embed in content transformation const drawinglayer::primitive2d::Primitive2DReference xTransform( new drawinglayer::primitive2d::TransformPrimitive2D( - basegfx::utils::createScaleTranslateB2DHomMatrix( - aContentRange.getRange(), - aContentRange.getMinimum()), + *pTransform, aMaskTarget)); aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xTransform }; } - else // userSpaceOnUse - { - // #i124852# - if(pTransform) - { - const drawinglayer::primitive2d::Primitive2DReference xTransform( - new drawinglayer::primitive2d::TransformPrimitive2D( - *pTransform, - aMaskTarget)); - - aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xTransform }; - } - } - - // embed content to a ModifiedColorPrimitive2D since the definitions - // how content is used as alpha is special for Svg - { - const drawinglayer::primitive2d::Primitive2DReference xInverseMask( - new drawinglayer::primitive2d::ModifiedColorPrimitive2D( - aMaskTarget, - basegfx::BColorModifierSharedPtr( - new basegfx::BColorModifier_luminance_to_alpha()))); + } - aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xInverseMask }; - } + // embed content to a ModifiedColorPrimitive2D since the definitions + // how content is used as alpha is special for Svg + { + const drawinglayer::primitive2d::Primitive2DReference xInverseMask( + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + aMaskTarget, + basegfx::BColorModifierSharedPtr( + new basegfx::BColorModifier_luminance_to_alpha()))); - // prepare new content - drawinglayer::primitive2d::Primitive2DReference xNewContent( - new drawinglayer::primitive2d::TransparencePrimitive2D( - rTarget, - aMaskTarget)); + aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xInverseMask }; + } - // output up to now is defined by aContentRange and mask is oriented - // relative to it. It is possible that aOffscreenBufferRange defines - // a smaller area. In that case, embed to a mask primitive - if(!aOffscreenBufferRange.isInside(aContentRange)) - { - xNewContent = new drawinglayer::primitive2d::MaskPrimitive2D( - basegfx::B2DPolyPolygon( - basegfx::utils::createPolygonFromRect( - aOffscreenBufferRange)), - drawinglayer::primitive2d::Primitive2DContainer { xNewContent }); - } + // prepare new content + drawinglayer::primitive2d::Primitive2DReference xNewContent( + new drawinglayer::primitive2d::TransparencePrimitive2D( + rTarget, + aMaskTarget)); - // redefine target. Use TransparencePrimitive2D with created mask - // geometry - rTarget = drawinglayer::primitive2d::Primitive2DContainer { xNewContent }; - } - else + // output up to now is defined by aContentRange and mask is oriented + // relative to it. It is possible that aOffscreenBufferRange defines + // a smaller area. In that case, embed to a mask primitive + if(!aOffscreenBufferRange.isInside(aContentRange)) { - // content is geometrically empty - rTarget.clear(); + xNewContent = new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect( + aOffscreenBufferRange)), + drawinglayer::primitive2d::Primitive2DContainer { xNewContent }); } + + // redefine target. Use TransparencePrimitive2D with created mask + // geometry + rTarget = drawinglayer::primitive2d::Primitive2DContainer { xNewContent }; } else { - // An empty clipping path will completely clip away the element that had - // the clip-path property applied. (Svg spec) + // content is geometrically empty rTarget.clear(); } } + else + { + // An empty clipping path will completely clip away the element that had + // the clip-path property applied. (Svg spec) + rTarget.clear(); + } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svgnode.cxx b/svgio/source/svgreader/svgnode.cxx index 61b0a9138fa9..88b9a72ec196 100644 --- a/svgio/source/svgreader/svgnode.cxx +++ b/svgio/source/svgreader/svgnode.cxx @@ -47,118 +47,118 @@ namespace svgio { const SvgDocument& rDocument = getDocument(); - if(rDocument.hasGlobalCssStyleAttributes()) + if(!rDocument.hasGlobalCssStyleAttributes()) + return; + + const SvgNode* pParent = rCurrent.getParent(); + + // check for ID (highest priority) + if(rCurrent.getId()) { - const SvgNode* pParent = rCurrent.getParent(); + const OUString& rId = *rCurrent.getId(); - // check for ID (highest priority) - if(rCurrent.getId()) + if(rId.getLength()) { - const OUString& rId = *rCurrent.getId(); + const OUString aNewConcatenated( + "#" + rId + aConcatenated); - if(rId.getLength()) + if(pParent) { - const OUString aNewConcatenated( - "#" + rId + aConcatenated); - - if(pParent) - { - // check for combined selectors at parent firstso that higher specificity will be in front - fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); - } + // check for combined selectors at parent firstso that higher specificity will be in front + fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); + } - const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); - if(pNew) - { - // add CssStyle if found - maCssStyleVector.push_back(pNew); - } + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); } } + } - // check for 'class' references (a list of entries is allowed) - if(rCurrent.getClass()) + // check for 'class' references (a list of entries is allowed) + if(rCurrent.getClass()) + { + const OUString& rClassList = *rCurrent.getClass(); + const sal_Int32 nLen(rClassList.getLength()); + + if(nLen) { - const OUString& rClassList = *rCurrent.getClass(); - const sal_Int32 nLen(rClassList.getLength()); + std::vector< OUString > aParts; + sal_Int32 nPos(0); + OUStringBuffer aToken; - if(nLen) + while(nPos < nLen) { - std::vector< OUString > aParts; - sal_Int32 nPos(0); - OUStringBuffer aToken; + const sal_Int32 nInitPos(nPos); + copyToLimiter(rClassList, u' ', nPos, aToken, nLen); + skip_char(rClassList, u' ', nPos, nLen); + const OUString aPart(aToken.makeStringAndClear().trim()); - while(nPos < nLen) + if(aPart.getLength()) { - const sal_Int32 nInitPos(nPos); - copyToLimiter(rClassList, u' ', nPos, aToken, nLen); - skip_char(rClassList, u' ', nPos, nLen); - const OUString aPart(aToken.makeStringAndClear().trim()); - - if(aPart.getLength()) - { - aParts.push_back(aPart); - } - - if(nInitPos == nPos) - { - OSL_ENSURE(false, "Could not interpret on current position (!)"); - nPos++; - } + aParts.push_back(aPart); } - for(size_t a(0); a < aParts.size(); a++) + if(nInitPos == nPos) { - const OUString aNewConcatenated( - "." + aParts[a] + aConcatenated); + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } - if(pParent) - { - // check for combined selectors at parent firstso that higher specificity will be in front - fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); - } + for(size_t a(0); a < aParts.size(); a++) + { + const OUString aNewConcatenated( + "." + aParts[a] + aConcatenated); - const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + if(pParent) + { + // check for combined selectors at parent firstso that higher specificity will be in front + fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); + } - if(pNew) - { - // add CssStyle if found - maCssStyleVector.push_back(pNew); - } + const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); } } } + } - // check for class-dependent references to CssStyles - if(!rClassStr.isEmpty()) - { - OUString aNewConcatenated(aConcatenated); + // check for class-dependent references to CssStyles + if(rClassStr.isEmpty()) + return; - if(!rCurrent.getId() && !rCurrent.getClass() && 0 == aConcatenated.indexOf(rClassStr)) - { - // no new CssStyle Selector and already starts with rClassStr, do not concatenate; - // we pass an 'empty' node (in the sense of CssStyle Selector) - } - else - { - aNewConcatenated = rClassStr + aConcatenated; - } + OUString aNewConcatenated(aConcatenated); - if(pParent) - { - // check for combined selectors at parent firstso that higher specificity will be in front - fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); - } + if(!rCurrent.getId() && !rCurrent.getClass() && 0 == aConcatenated.indexOf(rClassStr)) + { + // no new CssStyle Selector and already starts with rClassStr, do not concatenate; + // we pass an 'empty' node (in the sense of CssStyle Selector) + } + else + { + aNewConcatenated = rClassStr + aConcatenated; + } - const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + if(pParent) + { + // check for combined selectors at parent firstso that higher specificity will be in front + fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated); + } - if(pNew) - { - // add CssStyle if found - maCssStyleVector.push_back(pNew); - } - } + const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); } } @@ -500,84 +500,84 @@ namespace svgio const auto& rChildren = getChildren(); - if(!rChildren.empty()) - { - mbDecomposing = true; + if(rChildren.empty()) + return; - const sal_uInt32 nCount(rChildren.size()); + mbDecomposing = true; - for(sal_uInt32 a(0); a < nCount; a++) - { - SvgNode* pCandidate = rChildren[a].get(); + const sal_uInt32 nCount(rChildren.size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + SvgNode* pCandidate = rChildren[a].get(); - if(pCandidate && Display_none != pCandidate->getDisplay()) + if(pCandidate && Display_none != pCandidate->getDisplay()) + { + const auto& rGrandChildren = pCandidate->getChildren(); + const SvgStyleAttributes* pChildStyles = pCandidate->getSvgStyleAttributes(); + // decompose: + // - visible terminal nodes + // - all non-terminal nodes (might contain visible nodes down the hierarchy) + if( !rGrandChildren.empty() || ( pChildStyles && (Visibility_visible == pChildStyles->getVisibility())) ) { - const auto& rGrandChildren = pCandidate->getChildren(); - const SvgStyleAttributes* pChildStyles = pCandidate->getSvgStyleAttributes(); - // decompose: - // - visible terminal nodes - // - all non-terminal nodes (might contain visible nodes down the hierarchy) - if( !rGrandChildren.empty() || ( pChildStyles && (Visibility_visible == pChildStyles->getVisibility())) ) - { - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - pCandidate->decomposeSvgNode(aNewTarget, bReferenced); + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + pCandidate->decomposeSvgNode(aNewTarget, bReferenced); - if(!aNewTarget.empty()) - { - rTarget.append(aNewTarget); - } + if(!aNewTarget.empty()) + { + rTarget.append(aNewTarget); } } - else if(!pCandidate) - { - OSL_ENSURE(false, "Null-Pointer in child node list (!)"); - } } + else if(!pCandidate) + { + OSL_ENSURE(false, "Null-Pointer in child node list (!)"); + } + } - if(!rTarget.empty()) + if(!rTarget.empty()) + { + const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); + if(pStyles) { - const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); - if(pStyles) + // check if we have Title or Desc + const OUString& rTitle = pStyles->getTitle(); + const OUString& rDesc = pStyles->getDesc(); + + if(!rTitle.isEmpty() || !rDesc.isEmpty()) { - // check if we have Title or Desc - const OUString& rTitle = pStyles->getTitle(); - const OUString& rDesc = pStyles->getDesc(); + // default object name is empty + OUString aObjectName; - if(!rTitle.isEmpty() || !rDesc.isEmpty()) + // use path as object name when outmost element + if(SVGTokenSvg == getType()) { - // default object name is empty - OUString aObjectName; + aObjectName = getDocument().getAbsolutePath(); - // use path as object name when outmost element - if(SVGTokenSvg == getType()) + if(!aObjectName.isEmpty()) { - aObjectName = getDocument().getAbsolutePath(); + INetURLObject aURL(aObjectName); - if(!aObjectName.isEmpty()) - { - INetURLObject aURL(aObjectName); - - aObjectName = aURL.getName( - INetURLObject::LAST_SEGMENT, - true, - INetURLObject::DecodeMechanism::WithCharset); - } + aObjectName = aURL.getName( + INetURLObject::LAST_SEGMENT, + true, + INetURLObject::DecodeMechanism::WithCharset); } + } - // pack in ObjectInfoPrimitive2D group - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::ObjectInfoPrimitive2D( - rTarget, - aObjectName, - rTitle, - rDesc)); + // pack in ObjectInfoPrimitive2D group + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::ObjectInfoPrimitive2D( + rTarget, + aObjectName, + rTitle, + rDesc)); - rTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + rTarget = drawinglayer::primitive2d::Primitive2DContainer { xRef }; } } - mbDecomposing = false; } + mbDecomposing = false; } const basegfx::B2DRange SvgNode::getCurrentViewPort() const diff --git a/svgio/source/svgreader/svgpatternnode.cxx b/svgio/source/svgreader/svgpatternnode.cxx index 0096f7ae5772..bb2317bc7d6f 100644 --- a/svgio/source/svgreader/svgpatternnode.cxx +++ b/svgio/source/svgreader/svgpatternnode.cxx @@ -198,63 +198,63 @@ namespace svgio double fTargetWidth(rGeoRange.getWidth()); double fTargetHeight(rGeoRange.getHeight()); - if(fTargetWidth > 0.0 && fTargetHeight > 0.0) - { - const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox); + if(!(fTargetWidth > 0.0 && fTargetHeight > 0.0)) + return; - if(objectBoundingBox == aPatternUnits) - { - rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0; - rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0; + const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox); - if(Unit_percent == getWidth().getUnit()) - { - rfW *= 0.01; - } + if(objectBoundingBox == aPatternUnits) + { + rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0; + rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0; - if(Unit_percent == getHeight().getUnit()) - { - rfH *= 0.01; - } - } - else + if(Unit_percent == getWidth().getUnit()) { - rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0; - rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0; - - // make relative to rGeoRange - rfW /= fTargetWidth; - rfH /= fTargetHeight; + rfW *= 0.01; } - if(rfW > 0.0 && rfH > 0.0) + if(Unit_percent == getHeight().getUnit()) { - if(objectBoundingBox == aPatternUnits) - { - rfX = (getX().isSet()) ? getX().getNumber() : 0.0; - rfY = (getY().isSet()) ? getY().getNumber() : 0.0; + rfH *= 0.01; + } + } + else + { + rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0; + rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0; - if(Unit_percent == getX().getUnit()) - { - rfX *= 0.01; - } + // make relative to rGeoRange + rfW /= fTargetWidth; + rfH /= fTargetHeight; + } - if(Unit_percent == getY().getUnit()) - { - rfY *= 0.01; - } - } - else - { - rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0; - rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0; + if(!(rfW > 0.0 && rfH > 0.0)) + return; - // make relative to rGeoRange - rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth; - rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight; - } + if(objectBoundingBox == aPatternUnits) + { + rfX = (getX().isSet()) ? getX().getNumber() : 0.0; + rfY = (getY().isSet()) ? getY().getNumber() : 0.0; + + if(Unit_percent == getX().getUnit()) + { + rfX *= 0.01; + } + + if(Unit_percent == getY().getUnit()) + { + rfY *= 0.01; } } + else + { + rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0; + rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0; + + // make relative to rGeoRange + rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth; + rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight; + } } const drawinglayer::primitive2d::Primitive2DContainer& SvgPatternNode::getPatternPrimitives() const diff --git a/svgio/source/svgreader/svgrectnode.cxx b/svgio/source/svgreader/svgrectnode.cxx index c0ff40925f2d..d8c9ce6afb91 100644 --- a/svgio/source/svgreader/svgrectnode.cxx +++ b/svgio/source/svgreader/svgrectnode.cxx @@ -158,57 +158,57 @@ namespace svgio // get size range and create path const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle && getWidth().isSet() && getHeight().isSet()) - { - const double fWidth(getWidth().solve(*this, xcoordinate)); - const double fHeight(getHeight().solve(*this, ycoordinate)); + if(!(pStyle && getWidth().isSet() && getHeight().isSet())) + return; - if(fWidth > 0.0 && fHeight > 0.0) - { - const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); - const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); - const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + fHeight); - basegfx::B2DPolygon aPath; + const double fWidth(getWidth().solve(*this, xcoordinate)); + const double fHeight(getHeight().solve(*this, ycoordinate)); - if(getRx().isSet() || getRy().isSet()) - { - double frX(getRx().isSet() ? getRx().solve(*this, xcoordinate) : 0.0); - double frY(getRy().isSet() ? getRy().solve(*this, ycoordinate) : 0.0); + if(!(fWidth > 0.0 && fHeight > 0.0)) + return; - frX = std::max(0.0, frX); - frY = std::max(0.0, frY); + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + fHeight); + basegfx::B2DPolygon aPath; - if(0.0 == frY && frX > 0.0) - { - frY = frX; - } - else if(0.0 == frX && frY > 0.0) - { - frX = frY; - } + if(getRx().isSet() || getRy().isSet()) + { + double frX(getRx().isSet() ? getRx().solve(*this, xcoordinate) : 0.0); + double frY(getRy().isSet() ? getRy().solve(*this, ycoordinate) : 0.0); + + frX = std::max(0.0, frX); + frY = std::max(0.0, frY); + + if(0.0 == frY && frX > 0.0) + { + frY = frX; + } + else if(0.0 == frX && frY > 0.0) + { + frX = frY; + } - frX /= fWidth; - frY /= fHeight; + frX /= fWidth; + frY /= fHeight; - frX = std::min(0.5, frX); - frY = std::min(0.5, frY); + frX = std::min(0.5, frX); + frY = std::min(0.5, frY); - aPath = basegfx::utils::createPolygonFromRect(aRange, frX * 2.0, frY * 2.0); - } - else - { - aPath = basegfx::utils::createPolygonFromRect(aRange); - } + aPath = basegfx::utils::createPolygonFromRect(aRange, frX * 2.0, frY * 2.0); + } + else + { + aPath = basegfx::utils::createPolygonFromRect(aRange); + } - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget, nullptr); - if(!aNewTarget.empty()) - { - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } - } + if(!aNewTarget.empty()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } } // end of namespace svgreader diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx index b0c45fb90372..9b6b81cbcdb2 100644 --- a/svgio/source/svgreader/svgstyleattributes.cxx +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -262,76 +262,76 @@ namespace svgio drawinglayer::primitive2d::Primitive2DContainer& rTarget, drawinglayer::primitive2d::Primitive2DContainer const & rSource) const { - if(!rSource.empty()) - { - // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D - // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill()) - // set. When another fill is used and also evtl. stroke is set it gets necessary to - // dismantle to geometry and add needed primitives - const basegfx::BColor* pFill = getFill(); - const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); - const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); - const basegfx::BColor* pStroke = getStroke(); - const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); - const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); - basegfx::B2DPolyPolygon aMergedArea; - - if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern) - { - // text geometry is needed, create - // use neutral ViewInformation and create LineGeometryExtractor2D - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; - drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D); - - // process - aExtractor.process(rSource); - - // get results - const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget(); - const sal_uInt32 nResultCount(rResult.size()); - basegfx::B2DPolyPolygonVector aTextFillVector; - aTextFillVector.reserve(nResultCount); - - for(sal_uInt32 a(0); a < nResultCount; a++) - { - const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a]; + if(rSource.empty()) + return; - if(rCandidate.getIsFilled()) - { - aTextFillVector.push_back(rCandidate.getB2DPolyPolygon()); - } - } + // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D + // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill()) + // set. When another fill is used and also evtl. stroke is set it gets necessary to + // dismantle to geometry and add needed primitives + const basegfx::BColor* pFill = getFill(); + const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); + const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); + const basegfx::BColor* pStroke = getStroke(); + const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); + const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); + basegfx::B2DPolyPolygon aMergedArea; - if(!aTextFillVector.empty()) - { - aMergedArea = basegfx::utils::mergeToSinglePolyPolygon(aTextFillVector); - } - } + if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern) + { + // text geometry is needed, create + // use neutral ViewInformation and create LineGeometryExtractor2D + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D); - const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern); + // process + aExtractor.process(rSource); - // add fill. Use geometry even for simple color fill when stroke - // is used, else text rendering and the geometry-based stroke will - // normally not really match optically due to diverse system text - // renderers - if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed)) - { - // create text fill content based on geometry - add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange()); - } - else if(pFill) + // get results + const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget(); + const sal_uInt32 nResultCount(rResult.size()); + basegfx::B2DPolyPolygonVector aTextFillVector; + aTextFillVector.reserve(nResultCount); + + for(sal_uInt32 a(0); a < nResultCount; a++) { - // add the already prepared primitives for single color fill - rTarget.append(rSource); + const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a]; + + if(rCandidate.getIsFilled()) + { + aTextFillVector.push_back(rCandidate.getB2DPolyPolygon()); + } } - // add stroke - if(aMergedArea.count() && bStrokeUsed) + if(!aTextFillVector.empty()) { - // create text stroke content - add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange()); + aMergedArea = basegfx::utils::mergeToSinglePolyPolygon(aTextFillVector); } } + + const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern); + + // add fill. Use geometry even for simple color fill when stroke + // is used, else text rendering and the geometry-based stroke will + // normally not really match optically due to diverse system text + // renderers + if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed)) + { + // create text fill content based on geometry + add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange()); + } + else if(pFill) + { + // add the already prepared primitives for single color fill + rTarget.append(rSource); + } + + // add stroke + if(aMergedArea.count() && bStrokeUsed) + { + // create text stroke content + add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange()); + } } void SvgStyleAttributes::add_fillGradient( @@ -346,127 +346,127 @@ namespace svgio // get the color stops rFillGradient.collectGradientEntries(aSvgGradientEntryVector); - if(!aSvgGradientEntryVector.empty()) + if(aSvgGradientEntryVector.empty()) + return; + + basegfx::B2DHomMatrix aGeoToUnit; + basegfx::B2DHomMatrix aGradientTransform; + + if(rFillGradient.getGradientTransform()) { - basegfx::B2DHomMatrix aGeoToUnit; - basegfx::B2DHomMatrix aGradientTransform; + aGradientTransform = *rFillGradient.getGradientTransform(); + } - if(rFillGradient.getGradientTransform()) - { - aGradientTransform = *rFillGradient.getGradientTransform(); - } + if(userSpaceOnUse == rFillGradient.getGradientUnits()) + { + aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY()); + aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight()); + } + + if(SVGTokenLinearGradient == rFillGradient.getType()) + { + basegfx::B2DPoint aStart(0.0, 0.0); + basegfx::B2DPoint aEnd(1.0, 0.0); if(userSpaceOnUse == rFillGradient.getGradientUnits()) { - aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY()); - aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight()); + // all possible units + aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate)); + aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate)); + aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate)); + aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate)); + } + else + { + // fractions or percent relative to object bounds + const SvgNumber X1(rFillGradient.getX1()); + const SvgNumber Y1(rFillGradient.getY1()); + const SvgNumber X2(rFillGradient.getX2()); + const SvgNumber Y2(rFillGradient.getY2()); + + aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber()); + aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber()); + aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber()); + aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber()); } - if(SVGTokenLinearGradient == rFillGradient.getType()) + if(!aGeoToUnit.isIdentity()) { - basegfx::B2DPoint aStart(0.0, 0.0); - basegfx::B2DPoint aEnd(1.0, 0.0); + aStart *= aGeoToUnit; + aEnd *= aGeoToUnit; + } - if(userSpaceOnUse == rFillGradient.getGradientUnits()) - { - // all possible units - aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate)); - aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate)); - aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate)); - aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate)); - } - else - { - // fractions or percent relative to object bounds - const SvgNumber X1(rFillGradient.getX1()); - const SvgNumber Y1(rFillGradient.getY1()); - const SvgNumber X2(rFillGradient.getX2()); - const SvgNumber Y2(rFillGradient.getY2()); - - aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber()); - aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber()); - aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber()); - aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber()); - } + rTarget.push_back( + new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D( + aGradientTransform, + rPath, + aSvgGradientEntryVector, + aStart, + aEnd, + userSpaceOnUse != rFillGradient.getGradientUnits(), + rFillGradient.getSpreadMethod())); + } + else + { + basegfx::B2DPoint aStart(0.5, 0.5); + basegfx::B2DPoint aFocal; + double fRadius(0.5); + const SvgNumber* pFx = rFillGradient.getFx(); + const SvgNumber* pFy = rFillGradient.getFy(); + const bool bFocal(pFx || pFy); + + if(userSpaceOnUse == rFillGradient.getGradientUnits()) + { + // all possible units + aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate)); + aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate)); + fRadius = rFillGradient.getR().solve(mrOwner); - if(!aGeoToUnit.isIdentity()) + if(bFocal) { - aStart *= aGeoToUnit; - aEnd *= aGeoToUnit; + aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX()); + aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY()); } - - rTarget.push_back( - new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D( - aGradientTransform, - rPath, - aSvgGradientEntryVector, - aStart, - aEnd, - userSpaceOnUse != rFillGradient.getGradientUnits(), - rFillGradient.getSpreadMethod())); } else { - basegfx::B2DPoint aStart(0.5, 0.5); - basegfx::B2DPoint aFocal; - double fRadius(0.5); - const SvgNumber* pFx = rFillGradient.getFx(); - const SvgNumber* pFy = rFillGradient.getFy(); - const bool bFocal(pFx || pFy); + // fractions or percent relative to object bounds + const SvgNumber Cx(rFillGradient.getCx()); + const SvgNumber Cy(rFillGradient.getCy()); + const SvgNumber R(rFillGradient.getR()); - if(userSpaceOnUse == rFillGradient.getGradientUnits()) - { - // all possible units - aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate)); - aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate)); - fRadius = rFillGradient.getR().solve(mrOwner); + aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber()); + aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber()); + fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber(); - if(bFocal) - { - aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX()); - aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY()); - } - } - else + if(bFocal) { - // fractions or percent relative to object bounds - const SvgNumber Cx(rFillGradient.getCx()); - const SvgNumber Cy(rFillGradient.getCy()); - const SvgNumber R(rFillGradient.getR()); - - aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber()); - aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber()); - fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber(); - - if(bFocal) - { - aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX()); - aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY()); - } + aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX()); + aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY()); } + } - if(!aGeoToUnit.isIdentity()) - { - aStart *= aGeoToUnit; - fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength(); + if(!aGeoToUnit.isIdentity()) + { + aStart *= aGeoToUnit; + fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength(); - if(bFocal) - { - aFocal *= aGeoToUnit; - } + if(bFocal) + { + aFocal *= aGeoToUnit; } - - rTarget.push_back( - new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D( - aGradientTransform, - rPath, - aSvgGradientEntryVector, - aStart, - fRadius, - userSpaceOnUse != rFillGradient.getGradientUnits(), - rFillGradient.getSpreadMethod(), - bFocal ? &aFocal : nullptr)); } + + rTarget.push_back( + new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D( + aGradientTransform, + rPath, + aSvgGradientEntryVector, + aStart, + fRadius, + userSpaceOnUse != rFillGradient.getGradientUnits(), + rFillGradient.getSpreadMethod(), + bFocal ? &aFocal : nullptr)); } } @@ -513,85 +513,85 @@ namespace svgio // fill polyPolygon with given pattern const drawinglayer::primitive2d::Primitive2DContainer& rPrimitives = rFillPattern.getPatternPrimitives(); - if(!rPrimitives.empty()) - { - double fTargetWidth(rGeoRange.getWidth()); - double fTargetHeight(rGeoRange.getHeight()); - - if(fTargetWidth > 0.0 && fTargetHeight > 0.0) - { - // get relative values from pattern - double fX(0.0); - double fY(0.0); - double fW(0.0); - double fH(0.0); + if(rPrimitives.empty()) + return; - rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner); + double fTargetWidth(rGeoRange.getWidth()); + double fTargetHeight(rGeoRange.getHeight()); - if(fW > 0.0 && fH > 0.0) - { - // build the reference range relative to the rGeoRange - const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH); + if(!(fTargetWidth > 0.0 && fTargetHeight > 0.0)) + return; - // find out how the content is mapped to the reference range - basegfx::B2DHomMatrix aMapPrimitivesToUnitRange; - const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox(); + // get relative values from pattern + double fX(0.0); + double fY(0.0); + double fW(0.0); + double fH(0.0); - if(pViewBox) - { - // use viewBox/preserveAspectRatio - const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio(); - const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0); + rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner); - if(rRatio.isSet()) - { - // let mapping be created from SvgAspectRatio - aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox); - } - else - { - // choose default mapping - aMapPrimitivesToUnitRange = SvgAspectRatio::createLinearMapping(aUnitRange, *pViewBox); - } - } - else - { - // use patternContentUnits - const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse); + if(!(fW > 0.0 && fH > 0.0)) + return; - if(userSpaceOnUse == aPatternContentUnits) - { - // create relative mapping to unit coordinates - aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight)); - } - else - { - aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH); - } - } + // build the reference range relative to the rGeoRange + const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH); - // apply aMapPrimitivesToUnitRange to content when used - drawinglayer::primitive2d::Primitive2DContainer aPrimitives(rPrimitives); + // find out how the content is mapped to the reference range + basegfx::B2DHomMatrix aMapPrimitivesToUnitRange; + const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox(); - if(!aMapPrimitivesToUnitRange.isIdentity()) - { - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - aMapPrimitivesToUnitRange, - aPrimitives)); + if(pViewBox) + { + // use viewBox/preserveAspectRatio + const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio(); + const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0); - aPrimitives = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox); + } + else + { + // choose default mapping + aMapPrimitivesToUnitRange = SvgAspectRatio::createLinearMapping(aUnitRange, *pViewBox); + } + } + else + { + // use patternContentUnits + const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse); - // embed in PatternFillPrimitive2D - rTarget.push_back( - new drawinglayer::primitive2d::PatternFillPrimitive2D( - rPath, - aPrimitives, - aReferenceRange)); - } + if(userSpaceOnUse == aPatternContentUnits) + { + // create relative mapping to unit coordinates + aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight)); } + else + { + aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH); + } + } + + // apply aMapPrimitivesToUnitRange to content when used + drawinglayer::primitive2d::Primitive2DContainer aPrimitives(rPrimitives); + + if(!aMapPrimitivesToUnitRange.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aMapPrimitivesToUnitRange, + aPrimitives)); + + aPrimitives = drawinglayer::primitive2d::Primitive2DContainer { xRef }; } + + // embed in PatternFillPrimitive2D + rTarget.push_back( + new drawinglayer::primitive2d::PatternFillPrimitive2D( + rPath, + aPrimitives, + aReferenceRange)); } void SvgStyleAttributes::add_fill( @@ -603,50 +603,50 @@ namespace svgio const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); - if(pFill || pFillGradient || pFillPattern) - { - const double fFillOpacity(getFillOpacity().solve(mrOwner)); + if(!(pFill || pFillGradient || pFillPattern)) + return; - if(basegfx::fTools::more(fFillOpacity, 0.0)) - { - drawinglayer::primitive2d::Primitive2DContainer aNewFill; + const double fFillOpacity(getFillOpacity().solve(mrOwner)); - if(pFillGradient) - { - // create fill content with SVG gradient primitive - add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange); - } - else if(pFillPattern) - { - // create fill content with SVG pattern primitive - add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange); - } - else // if(pFill) - { - // create fill content - aNewFill.resize(1); - aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( - rPath, - *pFill); - } + if(!basegfx::fTools::more(fFillOpacity, 0.0)) + return; - if(!aNewFill.empty()) - { - if(basegfx::fTools::less(fFillOpacity, 1.0)) - { - // embed in UnifiedTransparencePrimitive2D - rTarget.push_back( - new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( - aNewFill, - 1.0 - fFillOpacity)); - } - else - { - // append - rTarget.append(aNewFill); - } - } - } + drawinglayer::primitive2d::Primitive2DContainer aNewFill; + + if(pFillGradient) + { + // create fill content with SVG gradient primitive + add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange); + } + else if(pFillPattern) + { + // create fill content with SVG pattern primitive + add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange); + } + else // if(pFill) + { + // create fill content + aNewFill.resize(1); + aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + rPath, + *pFill); + } + + if(aNewFill.empty()) + return; + + if(basegfx::fTools::less(fFillOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + rTarget.push_back( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aNewFill, + 1.0 - fFillOpacity)); + } + else + { + // append + rTarget.append(aNewFill); } } @@ -659,151 +659,151 @@ namespace svgio const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); - if(pStroke || pStrokeGradient || pStrokePattern) - { - drawinglayer::primitive2d::Primitive2DContainer aNewStroke; - const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner)); + if(!(pStroke || pStrokeGradient || pStrokePattern)) + return; - if(basegfx::fTools::more(fStrokeOpacity, 0.0)) - { - // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all - const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner) : 1.0); + drawinglayer::primitive2d::Primitive2DContainer aNewStroke; + const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner)); - if(basegfx::fTools::more(fStrokeWidth, 0.0)) - { - drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; + if(!basegfx::fTools::more(fStrokeOpacity, 0.0)) + return; - // if we have a line with two identical points it is not really a line, - // but used by SVG sometimes to paint a single dot.In that case, create - // the geometry for a single dot - if(1 == rPath.count()) - { - const basegfx::B2DPolygon& aSingle(rPath.getB2DPolygon(0)); + // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all + const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner) : 1.0); - if(2 == aSingle.count() && aSingle.getB2DPoint(0).equal(aSingle.getB2DPoint(1))) - { - aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( - basegfx::B2DPolyPolygon( - basegfx::utils::createPolygonFromCircle( - aSingle.getB2DPoint(0), - fStrokeWidth * (1.44 * 0.5))), - pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0)); - } - } + if(!basegfx::fTools::more(fStrokeWidth, 0.0)) + return; - if(!aNewLinePrimitive.is()) - { - // get LineJoin, LineCap and stroke array - const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin())); - const css::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap())); - ::std::vector< double > aDashArray; + drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; - if(!getStrokeDasharray().empty()) - { - aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner); - } + // if we have a line with two identical points it is not really a line, + // but used by SVG sometimes to paint a single dot.In that case, create + // the geometry for a single dot + if(1 == rPath.count()) + { + const basegfx::B2DPolygon& aSingle(rPath.getB2DPolygon(0)); - // convert svg:stroke-miterlimit to LineAttrute:mfMiterMinimumAngle - // The default needs to be set explicitly, because svg default <> Draw default - double fMiterMinimumAngle; - if (getStrokeMiterLimit().isSet()) - { - fMiterMinimumAngle = 2.0 * asin(1.0/getStrokeMiterLimit().getNumber()); - } - else - { - fMiterMinimumAngle = 2.0 * asin(0.25); // 1.0/default 4.0 - } + if(2 == aSingle.count() && aSingle.getB2DPoint(0).equal(aSingle.getB2DPoint(1))) + { + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromCircle( + aSingle.getB2DPoint(0), + fStrokeWidth * (1.44 * 0.5))), + pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0)); + } + } - // todo: Handle getStrokeDashOffset() + if(!aNewLinePrimitive.is()) + { + // get LineJoin, LineCap and stroke array + const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin())); + const css::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap())); + ::std::vector< double > aDashArray; - // prepare line attribute - const drawinglayer::attribute::LineAttribute aLineAttribute( - pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), - fStrokeWidth, - aB2DLineJoin, - aLineCap, - fMiterMinimumAngle); + if(!getStrokeDasharray().empty()) + { + aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner); + } - if(aDashArray.empty()) - { - aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - rPath, - aLineAttribute); - } - else - { - const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray); + // convert svg:stroke-miterlimit to LineAttrute:mfMiterMinimumAngle + // The default needs to be set explicitly, because svg default <> Draw default + double fMiterMinimumAngle; + if (getStrokeMiterLimit().isSet()) + { + fMiterMinimumAngle = 2.0 * asin(1.0/getStrokeMiterLimit().getNumber()); + } + else + { + fMiterMinimumAngle = 2.0 * asin(0.25); // 1.0/default 4.0 + } - aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - rPath, - aLineAttribute, - aStrokeAttribute); - } - } + // todo: Handle getStrokeDashOffset() - if(pStrokeGradient || pStrokePattern) - { - // put primitive into Primitive2DReference and Primitive2DSequence - const drawinglayer::primitive2d::Primitive2DContainer aSeq { aNewLinePrimitive }; + // prepare line attribute + const drawinglayer::attribute::LineAttribute aLineAttribute( + pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), + fStrokeWidth, + aB2DLineJoin, + aLineCap, + fMiterMinimumAngle); + + if(aDashArray.empty()) + { + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute); + } + else + { + const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray); - // use neutral ViewInformation and create LineGeometryExtractor2D - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; - drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D); + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute, + aStrokeAttribute); + } + } - // process - aExtractor.process(aSeq); + if(pStrokeGradient || pStrokePattern) + { + // put primitive into Primitive2DReference and Primitive2DSequence + const drawinglayer::primitive2d::Primitive2DContainer aSeq { aNewLinePrimitive }; - // check for fill rsults - const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills()); + // use neutral ViewInformation and create LineGeometryExtractor2D + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D); - if(!rLineFillVector.empty()) - { - const basegfx::B2DPolyPolygon aMergedArea( - basegfx::utils::mergeToSinglePolyPolygon( - rLineFillVector)); + // process + aExtractor.process(aSeq); - if(aMergedArea.count()) - { - if(pStrokeGradient) - { - // create fill content with SVG gradient primitive. Use original GeoRange, - // e.g. from circle without LineWidth - add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange); - } - else // if(pStrokePattern) - { - // create fill content with SVG pattern primitive. Use GeoRange - // from the expanded data, e.g. circle with extended geo by half linewidth - add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange()); - } - } - } - } - else // if(pStroke) + // check for fill rsults + const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills()); + + if(!rLineFillVector.empty()) + { + const basegfx::B2DPolyPolygon aMergedArea( + basegfx::utils::mergeToSinglePolyPolygon( + rLineFillVector)); + + if(aMergedArea.count()) + { + if(pStrokeGradient) { - aNewStroke.push_back(aNewLinePrimitive); + // create fill content with SVG gradient primitive. Use original GeoRange, + // e.g. from circle without LineWidth + add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange); } - - if(!aNewStroke.empty()) + else // if(pStrokePattern) { - if(basegfx::fTools::less(fStrokeOpacity, 1.0)) - { - // embed in UnifiedTransparencePrimitive2D - rTarget.push_back( - new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( - aNewStroke, - 1.0 - fStrokeOpacity)); - } - else - { - // append - rTarget.append(aNewStroke); - } + // create fill content with SVG pattern primitive. Use GeoRange + // from the expanded data, e.g. circle with extended geo by half linewidth + add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange()); } } } } + else // if(pStroke) + { + aNewStroke.push_back(aNewLinePrimitive); + } + + if(aNewStroke.empty()) + return; + + if(basegfx::fTools::less(fStrokeOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + rTarget.push_back( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aNewStroke, + 1.0 - fStrokeOpacity)); + } + else + { + // append + rTarget.append(aNewStroke); + } } bool SvgStyleAttributes::prepare_singleMarker( @@ -906,174 +906,174 @@ namespace svgio const SvgMarkerNode* pMid = accessMarkerMidXLink(); const SvgMarkerNode* pEnd = accessMarkerEndXLink(); - if(pStart || pMid || pEnd) + if(!(pStart || pMid || pEnd)) + return; + + const sal_uInt32 nSubPathCount(rPath.count()); + + if(!nSubPathCount) + return; + + // remember prepared marker; pStart, pMid and pEnd may all be equal when + // only 'marker' was used instead of 'marker-start', 'marker-mid' or 'marker-end', + // see 'case SVGTokenMarker' in this file; thus in this case only one common + // marker in primitive form will be prepared + const SvgMarkerNode* pPrepared = nullptr; + + // values for the prepared marker, results of prepare_singleMarker + drawinglayer::primitive2d::Primitive2DContainer aPreparedMarkerPrimitives; + basegfx::B2DHomMatrix aPreparedMarkerTransform; + basegfx::B2DRange aPreparedMarkerClipRange; + + for (sal_uInt32 a(0); a < nSubPathCount; a++) { - const sal_uInt32 nSubPathCount(rPath.count()); + // iterate over sub-paths + const basegfx::B2DPolygon& aSubPolygonPath(rPath.getB2DPolygon(a)); + const sal_uInt32 nSubPolygonPointCount(aSubPolygonPath.count()); + const bool bSubPolygonPathIsClosed(aSubPolygonPath.isClosed()); - if(nSubPathCount) + if(nSubPolygonPointCount) { - // remember prepared marker; pStart, pMid and pEnd may all be equal when - // only 'marker' was used instead of 'marker-start', 'marker-mid' or 'marker-end', - // see 'case SVGTokenMarker' in this file; thus in this case only one common - // marker in primitive form will be prepared - const SvgMarkerNode* pPrepared = nullptr; + // for each sub-path, create one marker per point (when closed, two markers + // need to pe created for the 1st point) + const sal_uInt32 nTargetMarkerCount(bSubPolygonPathIsClosed ? nSubPolygonPointCount + 1 : nSubPolygonPointCount); - // values for the prepared marker, results of prepare_singleMarker - drawinglayer::primitive2d::Primitive2DContainer aPreparedMarkerPrimitives; - basegfx::B2DHomMatrix aPreparedMarkerTransform; - basegfx::B2DRange aPreparedMarkerClipRange; - - for (sal_uInt32 a(0); a < nSubPathCount; a++) + for (sal_uInt32 b(0); b < nTargetMarkerCount; b++) { - // iterate over sub-paths - const basegfx::B2DPolygon& aSubPolygonPath(rPath.getB2DPolygon(a)); - const sal_uInt32 nSubPolygonPointCount(aSubPolygonPath.count()); - const bool bSubPolygonPathIsClosed(aSubPolygonPath.isClosed()); + const bool bIsFirstMarker(!a && !b); + const bool bIsLastMarker(nSubPathCount - 1 == a && nTargetMarkerCount - 1 == b); + const SvgMarkerNode* pNeeded = nullptr; + + if(bIsFirstMarker) + { + // 1st point in 1st sub-polygon, use pStart + pNeeded = pStart; + } + else if(bIsLastMarker) + { + // last point in last sub-polygon, use pEnd + pNeeded = pEnd; + } + else + { + // anything in-between, use pMid + pNeeded = pMid; + } - if(nSubPolygonPointCount) + if(pHelpPointIndices && !pHelpPointIndices->empty()) { - // for each sub-path, create one marker per point (when closed, two markers - // need to pe created for the 1st point) - const sal_uInt32 nTargetMarkerCount(bSubPolygonPathIsClosed ? nSubPolygonPointCount + 1 : nSubPolygonPointCount); + const basegfx::utils::PointIndexSet::const_iterator aFound( + pHelpPointIndices->find(basegfx::utils::PointIndex(a, b))); - for (sal_uInt32 b(0); b < nTargetMarkerCount; b++) + if(aFound != pHelpPointIndices->end()) { - const bool bIsFirstMarker(!a && !b); - const bool bIsLastMarker(nSubPathCount - 1 == a && nTargetMarkerCount - 1 == b); - const SvgMarkerNode* pNeeded = nullptr; + // this point is a pure helper point; do not create a marker for it + continue; + } + } - if(bIsFirstMarker) - { - // 1st point in 1st sub-polygon, use pStart - pNeeded = pStart; - } - else if(bIsLastMarker) - { - // last point in last sub-polygon, use pEnd - pNeeded = pEnd; - } - else - { - // anything in-between, use pMid - pNeeded = pMid; - } + if(!pNeeded) + { + // no marker needs to be created for this point + continue; + } - if(pHelpPointIndices && !pHelpPointIndices->empty()) - { - const basegfx::utils::PointIndexSet::const_iterator aFound( - pHelpPointIndices->find(basegfx::utils::PointIndex(a, b))); - - if(aFound != pHelpPointIndices->end()) - { - // this point is a pure helper point; do not create a marker for it - continue; - } - } + if(pPrepared != pNeeded) + { + // if needed marker is not yet prepared, do it now + if(prepare_singleMarker(aPreparedMarkerPrimitives, aPreparedMarkerTransform, aPreparedMarkerClipRange, *pNeeded)) + { + pPrepared = pNeeded; + } + else + { + // error: could not prepare given marker + OSL_ENSURE(false, "OOps, could not prepare given marker as primitives (!)"); + pPrepared = nullptr; + continue; + } + } - if(!pNeeded) - { - // no marker needs to be created for this point - continue; - } + // prepare complete transform + basegfx::B2DHomMatrix aCombinedTransform(aPreparedMarkerTransform); + + // get rotation + if(pPrepared->getOrientAuto()) + { + const sal_uInt32 nPointIndex(b % nSubPolygonPointCount); + + // get entering and leaving tangents; this will search backward/forward + // in the polygon to find tangents unequal to zero, skipping empty edges + // see basegfx descriptions) + // Hint: Mozilla, Inkscape and others use only leaving tangent for start marker + // and entering tangent for end marker. To achieve this (if wanted) it is possible + // to make the fetch of aEntering/aLeaving dependent on bIsFirstMarker/bIsLastMarker. + // This is not done here, see comment 14 in task #1232379# + // or http://www.w3.org/TR/SVG/painting.html#OrientAttribute + basegfx::B2DVector aEntering( + basegfx::utils::getTangentEnteringPoint( + aSubPolygonPath, + nPointIndex)); + basegfx::B2DVector aLeaving( + basegfx::utils::getTangentLeavingPoint( + aSubPolygonPath, + nPointIndex)); + const bool bEntering(!aEntering.equalZero()); + const bool bLeaving(!aLeaving.equalZero()); + + if(bEntering || bLeaving) + { + basegfx::B2DVector aSum(0.0, 0.0); - if(pPrepared != pNeeded) + if(bEntering) { - // if needed marker is not yet prepared, do it now - if(prepare_singleMarker(aPreparedMarkerPrimitives, aPreparedMarkerTransform, aPreparedMarkerClipRange, *pNeeded)) - { - pPrepared = pNeeded; - } - else - { - // error: could not prepare given marker - OSL_ENSURE(false, "OOps, could not prepare given marker as primitives (!)"); - pPrepared = nullptr; - continue; - } + aSum += aEntering.normalize(); } - // prepare complete transform - basegfx::B2DHomMatrix aCombinedTransform(aPreparedMarkerTransform); - - // get rotation - if(pPrepared->getOrientAuto()) + if(bLeaving) { - const sal_uInt32 nPointIndex(b % nSubPolygonPointCount); - - // get entering and leaving tangents; this will search backward/forward - // in the polygon to find tangents unequal to zero, skipping empty edges - // see basegfx descriptions) - // Hint: Mozilla, Inkscape and others use only leaving tangent for start marker - // and entering tangent for end marker. To achieve this (if wanted) it is possible - // to make the fetch of aEntering/aLeaving dependent on bIsFirstMarker/bIsLastMarker. - // This is not done here, see comment 14 in task #1232379# - // or http://www.w3.org/TR/SVG/painting.html#OrientAttribute - basegfx::B2DVector aEntering( - basegfx::utils::getTangentEnteringPoint( - aSubPolygonPath, - nPointIndex)); - basegfx::B2DVector aLeaving( - basegfx::utils::getTangentLeavingPoint( - aSubPolygonPath, - nPointIndex)); - const bool bEntering(!aEntering.equalZero()); - const bool bLeaving(!aLeaving.equalZero()); - - if(bEntering || bLeaving) - { - basegfx::B2DVector aSum(0.0, 0.0); - - if(bEntering) - { - aSum += aEntering.normalize(); - } - - if(bLeaving) - { - aSum += aLeaving.normalize(); - } - - if(!aSum.equalZero()) - { - const double fAngle(atan2(aSum.getY(), aSum.getX())); - - // apply rotation - aCombinedTransform.rotate(fAngle); - } - } + aSum += aLeaving.normalize(); } - else + + if(!aSum.equalZero()) { + const double fAngle(atan2(aSum.getY(), aSum.getX())); + // apply rotation - aCombinedTransform.rotate(pPrepared->getAngle()); + aCombinedTransform.rotate(fAngle); } + } + } + else + { + // apply rotation + aCombinedTransform.rotate(pPrepared->getAngle()); + } - // get and apply target position - const basegfx::B2DPoint aPoint(aSubPolygonPath.getB2DPoint(b % nSubPolygonPointCount)); - - aCombinedTransform.translate(aPoint.getX(), aPoint.getY()); + // get and apply target position + const basegfx::B2DPoint aPoint(aSubPolygonPath.getB2DPoint(b % nSubPolygonPointCount)); - // prepare marker - drawinglayer::primitive2d::Primitive2DReference xMarker( - new drawinglayer::primitive2d::TransformPrimitive2D( - aCombinedTransform, - aPreparedMarkerPrimitives)); + aCombinedTransform.translate(aPoint.getX(), aPoint.getY()); - if(!aPreparedMarkerClipRange.isEmpty()) - { - // marker needs to be clipped, it's bigger as the mapping - basegfx::B2DPolyPolygon aClipPolygon(basegfx::utils::createPolygonFromRect(aPreparedMarkerClipRange)); + // prepare marker + drawinglayer::primitive2d::Primitive2DReference xMarker( + new drawinglayer::primitive2d::TransformPrimitive2D( + aCombinedTransform, + aPreparedMarkerPrimitives)); - aClipPolygon.transform(aCombinedTransform); - xMarker = new drawinglayer::primitive2d::MaskPrimitive2D( - aClipPolygon, - drawinglayer::primitive2d::Primitive2DContainer { xMarker }); - } + if(!aPreparedMarkerClipRange.isEmpty()) + { + // marker needs to be clipped, it's bigger as the mapping + basegfx::B2DPolyPolygon aClipPolygon(basegfx::utils::createPolygonFromRect(aPreparedMarkerClipRange)); - // add marker - rTarget.push_back(xMarker); - } + aClipPolygon.transform(aCombinedTransform); + xMarker = new drawinglayer::primitive2d::MaskPrimitive2D( + aClipPolygon, + drawinglayer::primitive2d::Primitive2DContainer { xMarker }); } + + // add marker + rTarget.push_back(xMarker); } } } @@ -1153,98 +1153,98 @@ namespace svgio const drawinglayer::primitive2d::Primitive2DContainer& rSource, const basegfx::B2DHomMatrix* pTransform) const { - if(!rSource.empty()) + if(rSource.empty()) + return; + + const double fOpacity(getOpacity().solve(mrOwner)); + + if(basegfx::fTools::equalZero(fOpacity)) { - const double fOpacity(getOpacity().solve(mrOwner)); + return; + } - if(basegfx::fTools::equalZero(fOpacity)) - { - return; - } + drawinglayer::primitive2d::Primitive2DContainer aSource(rSource); - drawinglayer::primitive2d::Primitive2DContainer aSource(rSource); + if(basegfx::fTools::less(fOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aSource, + 1.0 - fOpacity)); - if(basegfx::fTools::less(fOpacity, 1.0)) - { - // embed in UnifiedTransparencePrimitive2D - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( - aSource, - 1.0 - fOpacity)); + aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; + } - aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + if(pTransform) + { + // create embedding group element with transformation. This applies the given + // transformation to the graphical content, but *not* to mask and/or clip (as needed) + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *pTransform, + aSource)); - if(pTransform) - { - // create embedding group element with transformation. This applies the given - // transformation to the graphical content, but *not* to mask and/or clip (as needed) - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - *pTransform, - aSource)); + aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; + } - aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + const SvgClipPathNode* pClip = accessClipPathXLink(); + while(pClip) + { + // #i124852# transform may be needed when userSpaceOnUse + pClip->apply(aSource, pTransform); + pClip = pClip->getSvgStyleAttributes()->accessClipPathXLink(); + } - const SvgClipPathNode* pClip = accessClipPathXLink(); - while(pClip) + if(!aSource.empty()) // test again, applied clipPath may have lead to empty geometry + { + const SvgMaskNode* pMask = accessMaskXLink(); + if(pMask) { // #i124852# transform may be needed when userSpaceOnUse - pClip->apply(aSource, pTransform); - pClip = pClip->getSvgStyleAttributes()->accessClipPathXLink(); + pMask->apply(aSource, pTransform); } + } - if(!aSource.empty()) // test again, applied clipPath may have lead to empty geometry - { - const SvgMaskNode* pMask = accessMaskXLink(); - if(pMask) - { - // #i124852# transform may be needed when userSpaceOnUse - pMask->apply(aSource, pTransform); - } - } + // This is part of the SVG import of self-written SVGs from + // Draw/Impress containing multiple Slides/Pages. To be able + // to later 'break' these to multiple Pages if wanted, embed + // each Page-Content in a identifiable Primitive Grouping + // Object. + // This is the case when the current Node is a GroupNode, has + // class="Page" set, has a parent that also is a GroupNode + // at which class="Slide" is set. + // Multiple Slides/Pages are possible for Draw and Impress. + if(SVGTokenG == mrOwner.getType() && mrOwner.getClass()) + { + const OUString aOwnerClass(*mrOwner.getClass()); - // This is part of the SVG import of self-written SVGs from - // Draw/Impress containing multiple Slides/Pages. To be able - // to later 'break' these to multiple Pages if wanted, embed - // each Page-Content in a identifiable Primitive Grouping - // Object. - // This is the case when the current Node is a GroupNode, has - // class="Page" set, has a parent that also is a GroupNode - // at which class="Slide" is set. - // Multiple Slides/Pages are possible for Draw and Impress. - if(SVGTokenG == mrOwner.getType() && mrOwner.getClass()) + if("Page" == aOwnerClass) { - const OUString aOwnerClass(*mrOwner.getClass()); + const SvgNode* pParent(mrOwner.getParent()); - if("Page" == aOwnerClass) + if(nullptr != pParent && SVGTokenG == pParent->getType() && pParent->getClass()) { - const SvgNode* pParent(mrOwner.getParent()); + const OUString aParentClass(*pParent->getClass()); - if(nullptr != pParent && SVGTokenG == pParent->getType() && pParent->getClass()) + if("Slide" == aParentClass) { - const OUString aParentClass(*pParent->getClass()); - - if("Slide" == aParentClass) - { - // embed to grouping primitive to identify the - // Slide/Page information - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::PageHierarchyPrimitive2D( - aSource)); + // embed to grouping primitive to identify the + // Slide/Page information + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::PageHierarchyPrimitive2D( + aSource)); - aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; - } + aSource = drawinglayer::primitive2d::Primitive2DContainer { xRef }; } } } + } - if(!aSource.empty()) // test again, applied mask may have lead to empty geometry - { - // append to current target - rTarget.append(aSource); - } + if(!aSource.empty()) // test again, applied mask may have lead to empty geometry + { + // append to current target + rTarget.append(aSource); } } diff --git a/svgio/source/svgreader/svgstylenode.cxx b/svgio/source/svgreader/svgstylenode.cxx index 5fdd73e9828b..68a101fb9637 100644 --- a/svgio/source/svgreader/svgstylenode.cxx +++ b/svgio/source/svgreader/svgstylenode.cxx @@ -85,100 +85,100 @@ namespace svgio { // aSelectors: CssStyle selectors, any combination, no comma separations, no spaces at start/end // rNewStyle: the already prepared style to register on that name - if(!aSelectors.isEmpty()) - { - std::vector< OUString > aSelectorParts; - const sal_Int32 nLen(aSelectors.getLength()); - sal_Int32 nPos(0); - OUStringBuffer aToken; + if(aSelectors.isEmpty()) + return; - // split into single tokens (currently only space separator) - while(nPos < nLen) - { - const sal_Int32 nInitPos(nPos); - copyToLimiter(aSelectors, u' ', nPos, aToken, nLen); - skip_char(aSelectors, u' ', nPos, nLen); - const OUString aSelectorPart(aToken.makeStringAndClear().trim()); + std::vector< OUString > aSelectorParts; + const sal_Int32 nLen(aSelectors.getLength()); + sal_Int32 nPos(0); + OUStringBuffer aToken; - if(!aSelectorPart.isEmpty()) - { - aSelectorParts.push_back(aSelectorPart); - } + // split into single tokens (currently only space separator) + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + copyToLimiter(aSelectors, u' ', nPos, aToken, nLen); + skip_char(aSelectors, u' ', nPos, nLen); + const OUString aSelectorPart(aToken.makeStringAndClear().trim()); - if(nInitPos == nPos) - { - OSL_ENSURE(false, "Could not interpret on current position (!)"); - nPos++; - } + if(!aSelectorPart.isEmpty()) + { + aSelectorParts.push_back(aSelectorPart); } - if(!aSelectorParts.empty()) + if(nInitPos == nPos) { - OUStringBuffer aConcatenatedSelector; + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } - // re-combine without spaces, create a unique name (for now) - for(size_t a(0); a < aSelectorParts.size(); a++) - { - aConcatenatedSelector.append(aSelectorParts[a]); - } + if(aSelectorParts.empty()) + return; - // CssStyles in SVG are currently not completely supported; the current idea for - // supporting the needed minimal set is to register CssStyles associated to a string - // which is just the space-char cleaned, concatenated Selectors. The part to 'match' - // these is in fillCssStyleVectorUsingHierarchyAndSelectors. There, the same string is - // built up using the priorities of local CssStyle, Id, Class and other info combined - // with the existing hierarchy. This creates a specificity and priority-sorted local - // list for each node which is then chained using get/setCssStyleParent. - // The current solution is capable of solving space-separated selectors which can be - // mixed between Id, Class and type specifiers. - // When CssStyles need more specific solving, the start point is here; remember the - // needed infos not in maIdStyleTokenMapperList at the document, but select evtl. - // more specific infos there in a class capable of handling more complex matchings. - // Additionally fillCssStyleVector (or the mechanism above that when a linked list of - // SvgStyleAttributes will not do it) will have to be adapted to make use of it. - - // register new style at document for (evtl. concatenated) stylename - const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedSelector.makeStringAndClear(), rNewStyle); - } + OUStringBuffer aConcatenatedSelector; + + // re-combine without spaces, create a unique name (for now) + for(size_t a(0); a < aSelectorParts.size(); a++) + { + aConcatenatedSelector.append(aSelectorParts[a]); } + + // CssStyles in SVG are currently not completely supported; the current idea for + // supporting the needed minimal set is to register CssStyles associated to a string + // which is just the space-char cleaned, concatenated Selectors. The part to 'match' + // these is in fillCssStyleVectorUsingHierarchyAndSelectors. There, the same string is + // built up using the priorities of local CssStyle, Id, Class and other info combined + // with the existing hierarchy. This creates a specificity and priority-sorted local + // list for each node which is then chained using get/setCssStyleParent. + // The current solution is capable of solving space-separated selectors which can be + // mixed between Id, Class and type specifiers. + // When CssStyles need more specific solving, the start point is here; remember the + // needed infos not in maIdStyleTokenMapperList at the document, but select evtl. + // more specific infos there in a class capable of handling more complex matchings. + // Additionally fillCssStyleVector (or the mechanism above that when a linked list of + // SvgStyleAttributes will not do it) will have to be adapted to make use of it. + + // register new style at document for (evtl. concatenated) stylename + const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedSelector.makeStringAndClear(), rNewStyle); } void SvgStyleNode::addCssStyleSheet(const OUString& aSelectors, const OUString& aContent) { // aSelectors: possible comma-separated list of CssStyle definitions, no spaces at start/end // aContent: the svg style definitions as string - if(!aSelectors.isEmpty() && !aContent.isEmpty()) - { - // create new style and add to local list (for ownership control) - SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this); - maSvgStyleAttributes.push_back(pNewStyle); + if(!(!aSelectors.isEmpty() && !aContent.isEmpty())) + return; - // fill with content - pNewStyle->readCssStyle(aContent); + // create new style and add to local list (for ownership control) + SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this); + maSvgStyleAttributes.push_back(pNewStyle); - // comma-separated split (Css abbreviation for same style for multiple selectors) - const sal_Int32 nLen(aSelectors.getLength()); - sal_Int32 nPos(0); - OUStringBuffer aToken; + // fill with content + pNewStyle->readCssStyle(aContent); - while(nPos < nLen) - { - const sal_Int32 nInitPos(nPos); - copyToLimiter(aSelectors, u',', nPos, aToken, nLen); - skip_char(aSelectors, u' ', u',', nPos, nLen); + // comma-separated split (Css abbreviation for same style for multiple selectors) + const sal_Int32 nLen(aSelectors.getLength()); + sal_Int32 nPos(0); + OUStringBuffer aToken; - const OUString aSingleName(aToken.makeStringAndClear().trim()); + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + copyToLimiter(aSelectors, u',', nPos, aToken, nLen); + skip_char(aSelectors, u' ', u',', nPos, nLen); - if(aSingleName.getLength()) - { - addCssStyleSheet(aSingleName, *pNewStyle); - } + const OUString aSingleName(aToken.makeStringAndClear().trim()); - if(nInitPos == nPos) - { - OSL_ENSURE(false, "Could not interpret on current position (!)"); - nPos++; - } + if(aSingleName.getLength()) + { + addCssStyleSheet(aSingleName, *pNewStyle); + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; } } } @@ -187,41 +187,41 @@ namespace svgio { const sal_Int32 nLen(aSelectorsAndContent.getLength()); - if(nLen) - { - sal_Int32 nPos(0); - OUStringBuffer aToken; + if(!nLen) + return; - while(nPos < nLen) - { - // read the full selectors (may be multiple, comma-separated) - const sal_Int32 nInitPos(nPos); - skip_char(aSelectorsAndContent, u' ', nPos, nLen); - copyToLimiter(aSelectorsAndContent, u'{', nPos, aToken, nLen); - skip_char(aSelectorsAndContent, u' ', u'{', nPos, nLen); + sal_Int32 nPos(0); + OUStringBuffer aToken; - const OUString aSelectors(aToken.makeStringAndClear().trim()); - OUString aContent; + while(nPos < nLen) + { + // read the full selectors (may be multiple, comma-separated) + const sal_Int32 nInitPos(nPos); + skip_char(aSelectorsAndContent, u' ', nPos, nLen); + copyToLimiter(aSelectorsAndContent, u'{', nPos, aToken, nLen); + skip_char(aSelectorsAndContent, u' ', u'{', nPos, nLen); - if(!aSelectors.isEmpty() && nPos < nLen) - { - // isolate content as text, embraced by '{' and '}' - copyToLimiter(aSelectorsAndContent, u'}', nPos, aToken, nLen); - skip_char(aSelectorsAndContent, u' ', u'}', nPos, nLen); + const OUString aSelectors(aToken.makeStringAndClear().trim()); + OUString aContent; - aContent = aToken.makeStringAndClear().trim(); - } + if(!aSelectors.isEmpty() && nPos < nLen) + { + // isolate content as text, embraced by '{' and '}' + copyToLimiter(aSelectorsAndContent, u'}', nPos, aToken, nLen); + skip_char(aSelectorsAndContent, u' ', u'}', nPos, nLen); - if(!aSelectors.isEmpty() && !aContent.isEmpty()) - { - addCssStyleSheet(aSelectors, aContent); - } + aContent = aToken.makeStringAndClear().trim(); + } - if(nInitPos == nPos) - { - OSL_ENSURE(false, "Could not interpret on current position (!)"); - nPos++; - } + if(!aSelectors.isEmpty() && !aContent.isEmpty()) + { + addCssStyleSheet(aSelectors, aContent); + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; } } } diff --git a/svgio/source/svgreader/svgsvgnode.cxx b/svgio/source/svgreader/svgsvgnode.cxx index 0d42099eff3b..72775f16b9a4 100644 --- a/svgio/source/svgreader/svgsvgnode.cxx +++ b/svgio/source/svgreader/svgsvgnode.cxx @@ -50,58 +50,58 @@ namespace svgio // #i125258# void SvgSvgNode::initializeStyleAttributes() { - if(!mbStyleAttributesInitialized) + if(mbStyleAttributesInitialized) + return; + + // #i125258# determine if initial values need to be initialized with hard values + // for the case that this is the outmost SVG statement and it has no parent + // stale (CssStyle for svg may be defined) + bool bSetInitialValues(true); + + if(getParent()) { - // #i125258# determine if initial values need to be initialized with hard values - // for the case that this is the outmost SVG statement and it has no parent - // stale (CssStyle for svg may be defined) - bool bSetInitialValues(true); + // #i125258# no initial values when it's a SVG element embedded in SVG + bSetInitialValues = false; + } - if(getParent()) - { - // #i125258# no initial values when it's a SVG element embedded in SVG - bSetInitialValues = false; - } + if(bSetInitialValues) + { + const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); - if(bSetInitialValues) + if(pStyles && pStyles->getParentStyle()) { - const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); + // SVG has a parent style (probably CssStyle), check if fill is set there anywhere + // already. If yes, do not set the default fill (black) + bool bFillSet(false); + const SvgStyleAttributes* pParentStyle = pStyles->getParentStyle(); - if(pStyles && pStyles->getParentStyle()) + while(pParentStyle && !bFillSet) { - // SVG has a parent style (probably CssStyle), check if fill is set there anywhere - // already. If yes, do not set the default fill (black) - bool bFillSet(false); - const SvgStyleAttributes* pParentStyle = pStyles->getParentStyle(); - - while(pParentStyle && !bFillSet) - { - bFillSet = pParentStyle->isFillSet(); - pParentStyle = pParentStyle->getParentStyle(); - } - - if(bFillSet) - { - // #125258# no initial values when SVG has a parent style at which a fill - // is already set - bSetInitialValues = false; - } + bFillSet = pParentStyle->isFillSet(); + pParentStyle = pParentStyle->getParentStyle(); } - } - if(bSetInitialValues) - { - // #i125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done, - // just setting may revert an already set valid value) - if(!maSvgStyleAttributes.isFillSet()) + if(bFillSet) { - // #i125258# initial fill is black (see SVG1.1 spec) - maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); + // #125258# no initial values when SVG has a parent style at which a fill + // is already set + bSetInitialValues = false; } } + } - mbStyleAttributesInitialized = true; + if(bSetInitialValues) + { + // #i125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done, + // just setting may revert an already set valid value) + if(!maSvgStyleAttributes.isFillSet()) + { + // #i125258# initial fill is black (see SVG1.1 spec) + maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); + } } + + mbStyleAttributesInitialized = true; } SvgSvgNode::~SvgSvgNode() @@ -709,22 +709,22 @@ namespace svgio } } - if(aSequence.empty() && !getParent() && getViewBox()) - { - // tdf#118232 No geometry, Outermost SVG element and we have a ViewBox. - // Create a HiddenGeometry Primitive containing an expanded - // hairline geometry to have the size contained - const drawinglayer::primitive2d::Primitive2DReference xLine( - new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( - basegfx::utils::createPolygonFromRect( - *getViewBox()), - basegfx::BColor(0.0, 0.0, 0.0))); - const drawinglayer::primitive2d::Primitive2DReference xHidden( - new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( - drawinglayer::primitive2d::Primitive2DContainer { xLine })); - - rTarget.push_back(xHidden); - } + if(!(aSequence.empty() && !getParent() && getViewBox())) + return; + + // tdf#118232 No geometry, Outermost SVG element and we have a ViewBox. + // Create a HiddenGeometry Primitive containing an expanded + // hairline geometry to have the size contained + const drawinglayer::primitive2d::Primitive2DReference xLine( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + basegfx::utils::createPolygonFromRect( + *getViewBox()), + basegfx::BColor(0.0, 0.0, 0.0))); + const drawinglayer::primitive2d::Primitive2DReference xHidden( + new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( + drawinglayer::primitive2d::Primitive2DContainer { xLine })); + + rTarget.push_back(xHidden); } const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const diff --git a/svgio/source/svgreader/svgtextnode.cxx b/svgio/source/svgreader/svgtextnode.cxx index 58e9621420df..bc6d824877df 100644 --- a/svgio/source/svgreader/svgtextnode.cxx +++ b/svgio/source/svgreader/svgtextnode.cxx @@ -89,21 +89,21 @@ namespace svgio drawinglayer::primitive2d::Primitive2DContainer& rTarget, drawinglayer::primitive2d::Primitive2DContainer const & rSource) { - if(!rSource.empty()) - { - const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes(); + if(rSource.empty()) + return; - if(pAttributes) - { - // add text with taking all Fill/Stroke attributes into account - pAttributes->add_text(rTarget, rSource); - } - else - { - // should not happen, every subnode from SvgTextNode will at least - // return the attributes from SvgTextNode. Nonetheless, add text - rTarget.append(rSource); - } + const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes(); + + if(pAttributes) + { + // add text with taking all Fill/Stroke attributes into account + pAttributes->add_text(rTarget, rSource); + } + else + { + // should not happen, every subnode from SvgTextNode will at least + // return the attributes from SvgTextNode. Nonetheless, add text + rTarget.append(rSource); } } @@ -225,37 +225,37 @@ namespace svgio // SVGTokenTref and SVGTokenTextPath. These increase a given current text position const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); - if(pStyle && !getChildren().empty()) - { - const double fOpacity(pStyle->getOpacity().getNumber()); + if(!(pStyle && !getChildren().empty())) + return; - if(fOpacity > 0.0) - { - SvgTextPosition aSvgTextPosition(nullptr, *this, maSvgTextPositions); - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - const auto& rChildren = getChildren(); - const sal_uInt32 nCount(rChildren.size()); + const double fOpacity(pStyle->getOpacity().getNumber()); - for(sal_uInt32 a(0); a < nCount; a++) - { - const SvgNode& rCandidate = *rChildren[a]; + if(fOpacity <= 0.0) + return; - DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition); - } + SvgTextPosition aSvgTextPosition(nullptr, *this, maSvgTextPositions); + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; + const auto& rChildren = getChildren(); + const sal_uInt32 nCount(rChildren.size()); - if(!aNewTarget.empty()) - { - drawinglayer::primitive2d::Primitive2DContainer aNewTarget2; + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgNode& rCandidate = *rChildren[a]; - addTextPrimitives(*this, aNewTarget2, aNewTarget); - aNewTarget = aNewTarget2; - } + DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition); + } - if(!aNewTarget.empty()) - { - pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); - } - } + if(!aNewTarget.empty()) + { + drawinglayer::primitive2d::Primitive2DContainer aNewTarget2; + + addTextPrimitives(*this, aNewTarget2, aNewTarget); + aNewTarget = aNewTarget2; + } + + if(!aNewTarget.empty()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); } } diff --git a/svgio/source/svgreader/svgtextpathnode.cxx b/svgio/source/svgreader/svgtextpathnode.cxx index 4e7567566317..f11bc2e7fbd2 100644 --- a/svgio/source/svgreader/svgtextpathnode.cxx +++ b/svgio/source/svgreader/svgtextpathnode.cxx @@ -346,96 +346,96 @@ namespace svgio drawinglayer::primitive2d::Primitive2DContainer& rTarget, const basegfx::B2DPoint& rTextStart) const { - if(!rPathContent.empty()) + if(rPathContent.empty()) + return; + + const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink)); + + if(!pSvgPathNode) + return; + + const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath(); + + if(!(pPolyPolyPath && pPolyPolyPath->count())) + return; + + basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0)); + + if(pSvgPathNode->getTransform()) { - const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink)); + aPolygon.transform(*pSvgPathNode->getTransform()); + } - if(pSvgPathNode) + const double fBasegfxPathLength(basegfx::utils::getLength(aPolygon)); + + if(basegfx::fTools::equalZero(fBasegfxPathLength)) + return; + + double fUserToBasegfx(1.0); // multiply: user->basegfx, divide: basegfx->user + + if(pSvgPathNode->getPathLength().isSet()) + { + const double fUserLength(pSvgPathNode->getPathLength().solve(*this)); + + if(fUserLength > 0.0 && !basegfx::fTools::equal(fUserLength, fBasegfxPathLength)) { - const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath(); + fUserToBasegfx = fUserLength / fBasegfxPathLength; + } + } - if(pPolyPolyPath && pPolyPolyPath->count()) - { - basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0)); + double fPosition(0.0); - if(pSvgPathNode->getTransform()) - { - aPolygon.transform(*pSvgPathNode->getTransform()); - } + if(getStartOffset().isSet()) + { + if(Unit_percent == getStartOffset().getUnit()) + { + // percent are relative to path length + fPosition = getStartOffset().getNumber() * 0.01 * fBasegfxPathLength; + } + else + { + fPosition = getStartOffset().solve(*this) * fUserToBasegfx; + } + } - const double fBasegfxPathLength(basegfx::utils::getLength(aPolygon)); + if(fPosition < 0.0) + return; - if(!basegfx::fTools::equalZero(fBasegfxPathLength)) - { - double fUserToBasegfx(1.0); // multiply: user->basegfx, divide: basegfx->user + const sal_Int32 nLength(rPathContent.size()); + sal_Int32 nCurrent(0); - if(pSvgPathNode->getPathLength().isSet()) - { - const double fUserLength(pSvgPathNode->getPathLength().solve(*this)); + while(fPosition < fBasegfxPathLength && nCurrent < nLength) + { + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = nullptr; + const drawinglayer::primitive2d::Primitive2DReference xReference(rPathContent[nCurrent]); - if(fUserLength > 0.0 && !basegfx::fTools::equal(fUserLength, fBasegfxPathLength)) - { - fUserToBasegfx = fUserLength / fBasegfxPathLength; - } - } + if(xReference.is()) + { + pCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xReference.get()); + } - double fPosition(0.0); + if(pCandidate) + { + const pathTextBreakupHelper aPathTextBreakupHelper( + *pCandidate, + aPolygon, + fBasegfxPathLength, + fPosition, + rTextStart); - if(getStartOffset().isSet()) - { - if(Unit_percent == getStartOffset().getUnit()) - { - // percent are relative to path length - fPosition = getStartOffset().getNumber() * 0.01 * fBasegfxPathLength; - } - else - { - fPosition = getStartOffset().solve(*this) * fUserToBasegfx; - } - } + const drawinglayer::primitive2d::Primitive2DContainer& aResult( + aPathTextBreakupHelper.getResult()); - if(fPosition >= 0.0) - { - const sal_Int32 nLength(rPathContent.size()); - sal_Int32 nCurrent(0); - - while(fPosition < fBasegfxPathLength && nCurrent < nLength) - { - const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = nullptr; - const drawinglayer::primitive2d::Primitive2DReference xReference(rPathContent[nCurrent]); - - if(xReference.is()) - { - pCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xReference.get()); - } - - if(pCandidate) - { - const pathTextBreakupHelper aPathTextBreakupHelper( - *pCandidate, - aPolygon, - fBasegfxPathLength, - fPosition, - rTextStart); - - const drawinglayer::primitive2d::Primitive2DContainer& aResult( - aPathTextBreakupHelper.getResult()); - - if(!aResult.empty()) - { - rTarget.append(aResult); - } - - // advance position to consumed - fPosition = aPathTextBreakupHelper.getPosition(); - } - - nCurrent++; - } - } - } + if(!aResult.empty()) + { + rTarget.append(aResult); } + + // advance position to consumed + fPosition = aPathTextBreakupHelper.getPosition(); } + + nCurrent++; } } diff --git a/svgio/source/svgreader/svgusenode.cxx b/svgio/source/svgreader/svgusenode.cxx index 5904a143068a..a54c9fb46c3e 100644 --- a/svgio/source/svgreader/svgusenode.cxx +++ b/svgio/source/svgreader/svgusenode.cxx @@ -142,50 +142,50 @@ namespace svgio // try to access link to content const SvgNode* pXLink = getDocument().findSvgNodeById(maXLink); - if (pXLink && Display_none != pXLink->getDisplay() && !mbDecomposingSvgNode) - { - // decompose children - drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - - // todo: in case mpXLink is a SVGTokenSvg or SVGTokenSymbol the - // SVG docs want the getWidth() and getHeight() from this node - // to be valid for the subtree. - mbDecomposingSvgNode = true; - const_cast< SvgNode* >(pXLink)->setAlternativeParent(this); - pXLink->decomposeSvgNode(aNewTarget, true); - const_cast< SvgNode* >(pXLink)->setAlternativeParent(); - mbDecomposingSvgNode = false; - - if(!aNewTarget.empty()) - { - basegfx::B2DHomMatrix aTransform; + if (!(pXLink && Display_none != pXLink->getDisplay() && !mbDecomposingSvgNode)) + return; - if(getX().isSet() || getY().isSet()) - { - aTransform.translate( - getX().solve(*this, xcoordinate), - getY().solve(*this, ycoordinate)); - } + // decompose children + drawinglayer::primitive2d::Primitive2DContainer aNewTarget; - if(getTransform()) - { - aTransform = *getTransform() * aTransform; - } + // todo: in case mpXLink is a SVGTokenSvg or SVGTokenSymbol the + // SVG docs want the getWidth() and getHeight() from this node + // to be valid for the subtree. + mbDecomposingSvgNode = true; + const_cast< SvgNode* >(pXLink)->setAlternativeParent(this); + pXLink->decomposeSvgNode(aNewTarget, true); + const_cast< SvgNode* >(pXLink)->setAlternativeParent(); + mbDecomposingSvgNode = false; - if(!aTransform.isIdentity()) - { - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - aTransform, - aNewTarget)); + if(aNewTarget.empty()) + return; - rTarget.push_back(xRef); - } - else - { - rTarget.append(aNewTarget); - } - } + basegfx::B2DHomMatrix aTransform; + + if(getX().isSet() || getY().isSet()) + { + aTransform.translate( + getX().solve(*this, xcoordinate), + getY().solve(*this, ycoordinate)); + } + + if(getTransform()) + { + aTransform = *getTransform() * aTransform; + } + + if(!aTransform.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + aNewTarget)); + + rTarget.push_back(xRef); + } + else + { + rTarget.append(aNewTarget); } } |