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                 default:
207                 {
208                     break;
209                 }
210             }
211         }
212 
213         void SvgPatternNode::getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const
214         {
215             double fTargetWidth(rGeoRange.getWidth());
216             double fTargetHeight(rGeoRange.getHeight());
217 
218             if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
219             {
220                 const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox);
221 
222                 if(objectBoundingBox == aPatternUnits)
223                 {
224                     rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0;
225                     rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0;
226 
227                     if(Unit_percent == getWidth().getUnit())
228                     {
229                         rfW *= 0.01;
230                     }
231 
232                     if(Unit_percent == getHeight().getUnit())
233                     {
234                         rfH *= 0.01;
235                     }
236                 }
237                 else
238                 {
239                     rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0;
240                     rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0;
241 
242                     // make relative to rGeoRange
243                     rfW /= fTargetWidth;
244                     rfH /= fTargetHeight;
245                 }
246 
247                 if(rfW > 0.0 && rfH > 0.0)
248                 {
249                     if(objectBoundingBox == aPatternUnits)
250                     {
251                         rfX = (getX().isSet()) ? getX().getNumber() : 0.0;
252                         rfY = (getY().isSet()) ? getY().getNumber() : 0.0;
253 
254                         if(Unit_percent == getX().getUnit())
255                         {
256                             rfX *= 0.01;
257                         }
258 
259                         if(Unit_percent == getY().getUnit())
260                         {
261                             rfY *= 0.01;
262                         }
263                     }
264                     else
265                     {
266                         rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0;
267                         rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0;
268 
269                         // make relative to rGeoRange
270                         rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth;
271                         rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight;
272                     }
273                 }
274             }
275         }
276 
277         const drawinglayer::primitive2d::Primitive2DSequence& SvgPatternNode::getPatternPrimitives() const
278         {
279             if(!aPrimitives.hasElements())
280             {
281                 decomposeSvgNode(const_cast< SvgPatternNode* >(this)->aPrimitives, true);
282             }
283 
284             if(!aPrimitives.hasElements() && maXLink.getLength())
285             {
286                 const_cast< SvgPatternNode* >(this)->tryToFindLink();
287 
288                 if(mpXLink)
289                 {
290                     return mpXLink->getPatternPrimitives();
291                 }
292             }
293 
294             return aPrimitives;
295         }
296 
297         const basegfx::B2DRange* SvgPatternNode::getCurrentViewPort() const
298         {
299             if(getViewBox())
300             {
301                 return getViewBox();
302             }
303             else
304             {
305                 return SvgNode::getCurrentViewPort();
306             }
307         }
308 
309         const basegfx::B2DRange* SvgPatternNode::getViewBox() const
310         {
311             if(mpViewBox)
312             {
313                 return mpViewBox;
314             }
315 
316             const_cast< SvgPatternNode* >(this)->tryToFindLink();
317 
318             if(mpXLink)
319             {
320                 return mpXLink->getViewBox();
321             }
322 
323             return 0;
324         }
325 
326         const SvgAspectRatio& SvgPatternNode::getSvgAspectRatio() const
327         {
328             if(maSvgAspectRatio.isSet())
329             {
330                 return maSvgAspectRatio;
331             }
332 
333             const_cast< SvgPatternNode* >(this)->tryToFindLink();
334 
335             if(mpXLink)
336             {
337                 return mpXLink->getSvgAspectRatio();
338             }
339 
340             return maSvgAspectRatio;
341         }
342 
343         const SvgNumber& SvgPatternNode::getX() const
344         {
345             if(maX.isSet())
346             {
347                 return maX;
348             }
349 
350             const_cast< SvgPatternNode* >(this)->tryToFindLink();
351 
352             if(mpXLink)
353             {
354                 return mpXLink->getX();
355             }
356 
357             return maX;
358         }
359 
360         const SvgNumber& SvgPatternNode::getY() const
361         {
362             if(maY.isSet())
363             {
364                 return maY;
365             }
366 
367             const_cast< SvgPatternNode* >(this)->tryToFindLink();
368 
369             if(mpXLink)
370             {
371                 return mpXLink->getY();
372             }
373 
374             return maY;
375         }
376 
377         const SvgNumber& SvgPatternNode::getWidth() const
378         {
379             if(maWidth.isSet())
380             {
381                 return maWidth;
382             }
383 
384             const_cast< SvgPatternNode* >(this)->tryToFindLink();
385 
386             if(mpXLink)
387             {
388                 return mpXLink->getWidth();
389             }
390 
391             return maWidth;
392         }
393 
394         const SvgNumber& SvgPatternNode::getHeight() const
395         {
396             if(maHeight.isSet())
397             {
398                 return maHeight;
399             }
400 
401             const_cast< SvgPatternNode* >(this)->tryToFindLink();
402 
403             if(mpXLink)
404             {
405                 return mpXLink->getHeight();
406             }
407 
408             return maHeight;
409         }
410 
411         const SvgUnits* SvgPatternNode::getPatternUnits() const
412         {
413             if(mpPatternUnits)
414             {
415                 return mpPatternUnits;
416             }
417 
418             const_cast< SvgPatternNode* >(this)->tryToFindLink();
419 
420             if(mpXLink)
421             {
422                 return mpXLink->getPatternUnits();
423             }
424 
425             return 0;
426         }
427 
428         const SvgUnits* SvgPatternNode::getPatternContentUnits() const
429         {
430             if(mpPatternContentUnits)
431             {
432                 return mpPatternContentUnits;
433             }
434 
435             const_cast< SvgPatternNode* >(this)->tryToFindLink();
436 
437             if(mpXLink)
438             {
439                 return mpXLink->getPatternContentUnits();
440             }
441 
442             return 0;
443         }
444 
445         const basegfx::B2DHomMatrix* SvgPatternNode::getPatternTransform() const
446         {
447             if(mpaPatternTransform)
448             {
449                 return mpaPatternTransform;
450             }
451 
452             const_cast< SvgPatternNode* >(this)->tryToFindLink();
453 
454             if(mpXLink)
455             {
456                 return mpXLink->getPatternTransform();
457             }
458 
459             return 0;
460         }
461 
462     } // end of namespace svgreader
463 } // end of namespace svgio
464 
465 //////////////////////////////////////////////////////////////////////////////
466 // eof
467