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