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/svgusenode.hxx>
26 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
27 #include <svgio/svgreader/svgdocument.hxx>
28 
29 //////////////////////////////////////////////////////////////////////////////
30 
31 namespace svgio
32 {
33     namespace svgreader
34     {
35         SvgUseNode::SvgUseNode(
36             SvgDocument& rDocument,
37             SvgNode* pParent)
38         :   SvgNode(SVGTokenG, rDocument, pParent),
39             maSvgStyleAttributes(*this),
40             mpaTransform(0),
41             maX(),
42             maY(),
43             maWidth(),
44             maHeight(),
45             maXLink()
46         {
47         }
48 
49         SvgUseNode::~SvgUseNode()
50         {
51             if(mpaTransform) delete mpaTransform;
52         }
53 
54         const SvgStyleAttributes* SvgUseNode::getSvgStyleAttributes() const
55         {
56             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("use"));
57             maSvgStyleAttributes.checkForCssStyle(aClassStr);
58 
59             return &maSvgStyleAttributes;
60         }
61 
62         void SvgUseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
63         {
64             // call parent
65             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
66 
67             // read style attributes
68             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
69 
70             // parse own
71             switch(aSVGToken)
72             {
73                 case SVGTokenStyle:
74                 {
75                     maSvgStyleAttributes.readStyle(aContent);
76                     break;
77                 }
78                 case SVGTokenTransform:
79                 {
80                     const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
81 
82                     if(!aMatrix.isIdentity())
83                     {
84                         setTransform(&aMatrix);
85                     }
86                     break;
87                 }
88                 case SVGTokenX:
89                 {
90                     SvgNumber aNum;
91 
92                     if(readSingleNumber(aContent, aNum))
93                     {
94                         setX(aNum);
95                     }
96                     break;
97                 }
98                 case SVGTokenY:
99                 {
100                     SvgNumber aNum;
101 
102                     if(readSingleNumber(aContent, aNum))
103                     {
104                         setY(aNum);
105                     }
106                     break;
107                 }
108                 case SVGTokenWidth:
109                 {
110                     SvgNumber aNum;
111 
112                     if(readSingleNumber(aContent, aNum))
113                     {
114                         if(aNum.isPositive())
115                         {
116                             setWidth(aNum);
117                         }
118                     }
119                     break;
120                 }
121                 case SVGTokenHeight:
122                 {
123                     SvgNumber aNum;
124 
125                     if(readSingleNumber(aContent, aNum))
126                     {
127                         if(aNum.isPositive())
128                         {
129                             setHeight(aNum);
130                         }
131                     }
132                 }
133                 case SVGTokenXlinkHref:
134                 {
135                     const sal_Int32 nLen(aContent.getLength());
136 
137                     if(nLen && sal_Unicode('#') == aContent[0])
138                     {
139                         maXLink = aContent.copy(1);
140                     }
141                     break;
142                 }
143                 default:
144                 {
145                     break;
146                 }
147             }
148         }
149 
150         void SvgUseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
151         {
152             // try to access link to content
153             const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink);
154 
155             if(mpXLink)
156             {
157                 // decompose childs
158                 drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
159 
160                 // todo: in case mpXLink is a SVGTokenSvg or SVGTokenSymbol the
161                 // SVG docs want the getWidth() and getHeight() from this node
162                 // to be valid for the subtree.
163                 const_cast< SvgNode* >(mpXLink)->setAlternativeParent(this);
164                 mpXLink->decomposeSvgNode(aNewTarget, true);
165                 const_cast< SvgNode* >(mpXLink)->setAlternativeParent(0);
166 
167                 if(aNewTarget.hasElements())
168                 {
169                     basegfx::B2DHomMatrix aTransform;
170 
171                     if(getX().isSet() || getY().isSet())
172                     {
173                         aTransform.translate(
174                             getX().solve(*this, xcoordinate),
175                             getY().solve(*this, ycoordinate));
176                     }
177 
178                     if(getTransform())
179                     {
180                         aTransform = *getTransform() * aTransform;
181                     }
182 
183                     if(!aTransform.isIdentity())
184                     {
185                         const drawinglayer::primitive2d::Primitive2DReference xRef(
186                             new drawinglayer::primitive2d::TransformPrimitive2D(
187                                 aTransform,
188                                 aNewTarget));
189 
190                         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
191                     }
192                     else
193                     {
194                         drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
195                     }
196                 }
197             }
198         }
199 
200     } // end of namespace svgreader
201 } // end of namespace svgio
202 
203 //////////////////////////////////////////////////////////////////////////////
204 // eof
205