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/svgpatternnode.hxx>
26 #include <svgio/svgreader/svgdocument.hxx>
27 
28 //////////////////////////////////////////////////////////////////////////////
29 
30 namespace svgio
31 {
32     namespace svgreader
33     {
34         void SvgPatternNode::tryToFindLink()
35         {
36             if(!mpXLink && maXLink.getLength())
37             {
38                 mpXLink = dynamic_cast< const SvgPatternNode* >(getDocument().findSvgNodeById(maXLink));
39             }
40         }
41 
42         SvgPatternNode::SvgPatternNode(
43             SvgDocument& rDocument,
44             SvgNode* pParent)
45         :   SvgNode(SVGTokenPattern, rDocument, pParent),
46             aPrimitives(),
47             maSvgStyleAttributes(*this),
48             mpViewBox(0),
49             maSvgAspectRatio(),
50             maX(),
51             maY(),
52             maWidth(),
53             maHeight(),
54             mpPatternUnits(0),
55             mpPatternContentUnits(0),
56             mpaPatternTransform(0),
57             maXLink(),
58             mpXLink(0)
59         {
60         }
61 
62         SvgPatternNode::~SvgPatternNode()
63         {
64             if(mpViewBox) delete mpViewBox;
65             if(mpaPatternTransform) delete mpaPatternTransform;
66             if(mpPatternUnits) delete mpPatternUnits;
67             if(mpPatternContentUnits) delete mpPatternContentUnits;
68         }
69 
70         const SvgStyleAttributes* SvgPatternNode::getSvgStyleAttributes() const
71         {
72             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("pattern"));
73             maSvgStyleAttributes.checkForCssStyle(aClassStr);
74 
75             return &maSvgStyleAttributes;
76         }
77 
78         void SvgPatternNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
79         {
80             // call parent
81             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
82 
83             // read style attributes
84             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
85 
86             // parse own
87             switch(aSVGToken)
88             {
89                 case SVGTokenStyle:
90                 {
91                     maSvgStyleAttributes.readStyle(aContent);
92                     break;
93                 }
94                 case SVGTokenViewBox:
95                 {
96                     const basegfx::B2DRange aRange(readViewBox(aContent, *this));
97 
98                     if(!aRange.isEmpty())
99                     {
100                         setViewBox(&aRange);
101                     }
102                     break;
103                 }
104                 case SVGTokenPreserveAspectRatio:
105                 {
106                     setSvgAspectRatio(readSvgAspectRatio(aContent));
107                     break;
108                 }
109                 case SVGTokenX:
110                 {
111                     SvgNumber aNum;
112 
113                     if(readSingleNumber(aContent, aNum))
114                     {
115                         setX(aNum);
116                     }
117                     break;
118                 }
119                 case SVGTokenY:
120                 {
121                     SvgNumber aNum;
122 
123                     if(readSingleNumber(aContent, aNum))
124                     {
125                         setY(aNum);
126                     }
127                     break;
128                 }
129                 case SVGTokenWidth:
130                 {
131                     SvgNumber aNum;
132 
133                     if(readSingleNumber(aContent, aNum))
134                     {
135                         if(aNum.isPositive())
136                         {
137                             setWidth(aNum);
138                         }
139                     }
140                     break;
141                 }
142                 case SVGTokenHeight:
143                 {
144                     SvgNumber aNum;
145 
146                     if(readSingleNumber(aContent, aNum))
147                     {
148                         if(aNum.isPositive())
149                         {
150                             setHeight(aNum);
151                         }
152                     }
153                     break;
154                 }
155                 case SVGTokenPatternUnits:
156                 {
157                     if(aContent.getLength())
158                     {
159                         if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
160                         {
161                             setPatternUnits(userSpaceOnUse);
162                         }
163                         else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
164                         {
165                             setPatternUnits(objectBoundingBox);
166                         }
167                     }
168                     break;
169                 }
170                 case SVGTokenPatternContentUnits:
171                 {
172                     if(aContent.getLength())
173                     {
174                         if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
175                         {
176                             setPatternContentUnits(userSpaceOnUse);
177                         }
178                         else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
179                         {
180                             setPatternContentUnits(objectBoundingBox);
181                         }
182                     }
183                     break;
184                 }
185                 case SVGTokenPatternTransform:
186                 {
187                     const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
188 
189                     if(!aMatrix.isIdentity())
190                     {
191                         setPatternTransform(&aMatrix);
192                     }
193                     break;
194                 }
195                 case SVGTokenXlinkHref:
196                 {
197                     const sal_Int32 nLen(aContent.getLength());
198 
199                     if(nLen && sal_Unicode('#') == aContent[0])
200                     {
201                         maXLink = aContent.copy(1);
202                         tryToFindLink();
203                     }
204                     break;
205                 }
206             }
207         }
208 
209         void SvgPatternNode::getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const
210         {
211             double fTargetWidth(rGeoRange.getWidth());
212             double fTargetHeight(rGeoRange.getHeight());
213 
214             if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
215             {
216                 const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox);
217 
218                 if(objectBoundingBox == aPatternUnits)
219                 {
220                     rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0;
221                     rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0;
222 
223                     if(Unit_percent == getWidth().getUnit())
224                     {
225                         rfW *= 0.01;
226                     }
227 
228                     if(Unit_percent == getHeight().getUnit())
229                     {
230                         rfH *= 0.01;
231                     }
232                 }
233                 else
234                 {
235                     rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0;
236                     rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0;
237 
238                     // make relative to rGeoRange
239                     rfW /= fTargetWidth;
240                     rfH /= fTargetHeight;
241                 }
242 
243                 if(rfW > 0.0 && rfH > 0.0)
244                 {
245                     if(objectBoundingBox == aPatternUnits)
246                     {
247                         rfX = (getX().isSet()) ? getX().getNumber() : 0.0;
248                         rfY = (getY().isSet()) ? getY().getNumber() : 0.0;
249 
250                         if(Unit_percent == getX().getUnit())
251                         {
252                             rfX *= 0.01;
253                         }
254 
255                         if(Unit_percent == getY().getUnit())
256                         {
257                             rfY *= 0.01;
258                         }
259                     }
260                     else
261                     {
262                         rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0;
263                         rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0;
264 
265                         // make relative to rGeoRange
266                         rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth;
267                         rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight;
268                     }
269                 }
270             }
271         }
272 
273         const drawinglayer::primitive2d::Primitive2DSequence& SvgPatternNode::getPatternPrimitives() const
274         {
275             if(!aPrimitives.hasElements())
276             {
277                 decomposeSvgNode(const_cast< SvgPatternNode* >(this)->aPrimitives, true);
278             }
279 
280             if(!aPrimitives.hasElements() && maXLink.getLength())
281             {
282                 const_cast< SvgPatternNode* >(this)->tryToFindLink();
283 
284                 if(mpXLink)
285                 {
286                     return mpXLink->getPatternPrimitives();
287                 }
288             }
289 
290             return aPrimitives;
291         }
292 
293         const basegfx::B2DRange* SvgPatternNode::getCurrentViewPort() const
294         {
295             if(getViewBox())
296             {
297                 return getViewBox();
298             }
299             else
300             {
301                 return SvgNode::getCurrentViewPort();
302             }
303         }
304 
305         const basegfx::B2DRange* SvgPatternNode::getViewBox() const
306         {
307             if(mpViewBox)
308             {
309                 return mpViewBox;
310             }
311 
312             const_cast< SvgPatternNode* >(this)->tryToFindLink();
313 
314             if(mpXLink)
315             {
316                 return mpXLink->getViewBox();
317             }
318 
319             return 0;
320         }
321 
322         const SvgAspectRatio& SvgPatternNode::getSvgAspectRatio() const
323         {
324             if(maSvgAspectRatio.isSet())
325             {
326                 return maSvgAspectRatio;
327             }
328 
329             const_cast< SvgPatternNode* >(this)->tryToFindLink();
330 
331             if(mpXLink)
332             {
333                 return mpXLink->getSvgAspectRatio();
334             }
335 
336             return maSvgAspectRatio;
337         }
338 
339         const SvgNumber& SvgPatternNode::getX() const
340         {
341             if(maX.isSet())
342             {
343                 return maX;
344             }
345 
346             const_cast< SvgPatternNode* >(this)->tryToFindLink();
347 
348             if(mpXLink)
349             {
350                 return mpXLink->getX();
351             }
352 
353             return maX;
354         }
355 
356         const SvgNumber& SvgPatternNode::getY() const
357         {
358             if(maY.isSet())
359             {
360                 return maY;
361             }
362 
363             const_cast< SvgPatternNode* >(this)->tryToFindLink();
364 
365             if(mpXLink)
366             {
367                 return mpXLink->getY();
368             }
369 
370             return maY;
371         }
372 
373         const SvgNumber& SvgPatternNode::getWidth() const
374         {
375             if(maWidth.isSet())
376             {
377                 return maWidth;
378             }
379 
380             const_cast< SvgPatternNode* >(this)->tryToFindLink();
381 
382             if(mpXLink)
383             {
384                 return mpXLink->getWidth();
385             }
386 
387             return maWidth;
388         }
389 
390         const SvgNumber& SvgPatternNode::getHeight() const
391         {
392             if(maHeight.isSet())
393             {
394                 return maHeight;
395             }
396 
397             const_cast< SvgPatternNode* >(this)->tryToFindLink();
398 
399             if(mpXLink)
400             {
401                 return mpXLink->getHeight();
402             }
403 
404             return maHeight;
405         }
406 
407         const SvgUnits* SvgPatternNode::getPatternUnits() const
408         {
409             if(mpPatternUnits)
410             {
411                 return mpPatternUnits;
412             }
413 
414             const_cast< SvgPatternNode* >(this)->tryToFindLink();
415 
416             if(mpXLink)
417             {
418                 return mpXLink->getPatternUnits();
419             }
420 
421             return 0;
422         }
423 
424         const SvgUnits* SvgPatternNode::getPatternContentUnits() const
425         {
426             if(mpPatternContentUnits)
427             {
428                 return mpPatternContentUnits;
429             }
430 
431             const_cast< SvgPatternNode* >(this)->tryToFindLink();
432 
433             if(mpXLink)
434             {
435                 return mpXLink->getPatternContentUnits();
436             }
437 
438             return 0;
439         }
440 
441         const basegfx::B2DHomMatrix* SvgPatternNode::getPatternTransform() const
442         {
443             if(mpaPatternTransform)
444             {
445                 return mpaPatternTransform;
446             }
447 
448             const_cast< SvgPatternNode* >(this)->tryToFindLink();
449 
450             if(mpXLink)
451             {
452                 return mpXLink->getPatternTransform();
453             }
454 
455             return 0;
456         }
457 
458     } // end of namespace svgreader
459 } // end of namespace svgio
460 
461 //////////////////////////////////////////////////////////////////////////////
462 // eof
463