1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_svgio.hxx" 24 25 #include <svgio/svgreader/svgclippathnode.hxx> 26 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 27 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 28 #include <basegfx/matrix/b2dhommatrixtools.hxx> 29 #include <drawinglayer/geometry/viewinformation2d.hxx> 30 #include <drawinglayer/processor2d/contourextractor2d.hxx> 31 #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 32 33 ////////////////////////////////////////////////////////////////////////////// 34 35 namespace svgio 36 { 37 namespace svgreader 38 { SvgClipPathNode(SvgDocument & rDocument,SvgNode * pParent)39 SvgClipPathNode::SvgClipPathNode( 40 SvgDocument& rDocument, 41 SvgNode* pParent) 42 : SvgNode(SVGTokenClipPathNode, rDocument, pParent), 43 maSvgStyleAttributes(*this), 44 mpaTransform(0), 45 maClipPathUnits(userSpaceOnUse) 46 { 47 } 48 ~SvgClipPathNode()49 SvgClipPathNode::~SvgClipPathNode() 50 { 51 if(mpaTransform) delete mpaTransform; 52 } 53 getSvgStyleAttributes() const54 const SvgStyleAttributes* SvgClipPathNode::getSvgStyleAttributes() const 55 { 56 return &maSvgStyleAttributes; 57 } 58 parseAttribute(const rtl::OUString & rTokenName,SVGToken aSVGToken,const rtl::OUString & aContent)59 void SvgClipPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 60 { 61 // call parent 62 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 63 64 // read style attributes 65 maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 66 67 // parse own 68 switch(aSVGToken) 69 { 70 case SVGTokenStyle: 71 { 72 maSvgStyleAttributes.readStyle(aContent); 73 break; 74 } 75 case SVGTokenTransform: 76 { 77 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); 78 79 if(!aMatrix.isIdentity()) 80 { 81 setTransform(&aMatrix); 82 } 83 break; 84 } 85 case SVGTokenClipPathUnits: 86 { 87 if(aContent.getLength()) 88 { 89 if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) 90 { 91 setClipPathUnits(userSpaceOnUse); 92 } 93 else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) 94 { 95 setClipPathUnits(objectBoundingBox); 96 } 97 } 98 break; 99 } 100 default: 101 { 102 break; 103 } 104 } 105 } 106 decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence & rTarget,bool bReferenced) const107 void SvgClipPathNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 108 { 109 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 110 111 // decompose childs 112 SvgNode::decomposeSvgNode(aNewTarget, bReferenced); 113 114 if(aNewTarget.hasElements()) 115 { 116 if(getTransform()) 117 { 118 // create embedding group element with transformation 119 const drawinglayer::primitive2d::Primitive2DReference xRef( 120 new drawinglayer::primitive2d::TransformPrimitive2D( 121 *getTransform(), 122 aNewTarget)); 123 124 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); 125 } 126 else 127 { 128 // append to current target 129 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); 130 } 131 } 132 } 133 apply(drawinglayer::primitive2d::Primitive2DSequence & rContent,const basegfx::B2DHomMatrix * pTransform) const134 void SvgClipPathNode::apply( 135 drawinglayer::primitive2d::Primitive2DSequence& rContent, 136 const basegfx::B2DHomMatrix* pTransform) const 137 { 138 if(rContent.hasElements() && Display_none != getDisplay()) 139 { 140 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 141 drawinglayer::primitive2d::Primitive2DSequence aClipTarget; 142 basegfx::B2DPolyPolygon aClipPolyPolygon; 143 144 // get clipPath definition as primitives 145 decomposeSvgNode(aClipTarget, true); 146 147 if(aClipTarget.hasElements()) 148 { 149 // extract filled plygons as base for a mask PolyPolygon 150 drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, true); 151 152 aExtractor.process(aClipTarget); 153 154 const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour()); 155 const sal_uInt32 nSize(rResult.size()); 156 157 if(nSize > 1) 158 { 159 // merge to single clipPolyPolygon 160 aClipPolyPolygon = basegfx::tools::mergeToSinglePolyPolygon(rResult); 161 } 162 else 163 { 164 aClipPolyPolygon = rResult[0]; 165 } 166 } 167 168 if(aClipPolyPolygon.count()) 169 { 170 if(objectBoundingBox == getClipPathUnits()) 171 { 172 // clip is object-relative, transform using content transformation 173 const basegfx::B2DRange aContentRange( 174 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 175 rContent, 176 aViewInformation2D)); 177 178 aClipPolyPolygon.transform( 179 basegfx::tools::createScaleTranslateB2DHomMatrix( 180 aContentRange.getRange(), 181 aContentRange.getMinimum())); 182 } 183 else // userSpaceOnUse 184 { 185 // #i124852# 186 if(pTransform) 187 { 188 aClipPolyPolygon.transform(*pTransform); 189 } 190 } 191 192 // redefine target. Use MaskPrimitive2D with created clip 193 // geometry. Using the automatically set mbIsClipPathContent at 194 // SvgStyleAttributes the clip definition is without fill, stroke, 195 // and strokeWidth and forced to black 196 const drawinglayer::primitive2d::Primitive2DReference xEmbedTransparence( 197 new drawinglayer::primitive2d::MaskPrimitive2D( 198 aClipPolyPolygon, 199 rContent)); 200 201 rContent = drawinglayer::primitive2d::Primitive2DSequence(&xEmbedTransparence, 1); 202 } 203 else 204 { 205 // An empty clipping path will completely clip away the element that had 206 // the �clip-path� property applied. (Svg spec) 207 rContent.realloc(0); 208 } 209 } 210 } 211 212 } // end of namespace svgreader 213 } // end of namespace svgio 214 215 ////////////////////////////////////////////////////////////////////////////// 216 // eof 217