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/svggradientnode.hxx>
26 #include <svgio/svgreader/svgdocument.hxx>
27 #include <svgio/svgreader/svggradientstopnode.hxx>
28 
29 //////////////////////////////////////////////////////////////////////////////
30 
31 namespace svgio
32 {
33     namespace svgreader
34     {
35         void SvgGradientNode::tryToFindLink()
36         {
37             if(!mpXLink && maXLink.getLength())
38             {
39                 mpXLink = dynamic_cast< const SvgGradientNode* >(getDocument().findSvgNodeById(maXLink));
40             }
41         }
42 
43         SvgGradientNode::SvgGradientNode(
44             SVGToken aType,
45             SvgDocument& rDocument,
46             SvgNode* pParent)
47         :   SvgNode(aType, rDocument, pParent),
48             maSvgStyleAttributes(*this),
49             maX1(),
50             maY1(),
51             maX2(),
52             maY2(),
53             maCx(),
54             maCy(),
55             maR(),
56             maFx(),
57             maFy(),
58             maGradientUnits(objectBoundingBox),
59             maSpreadMethod(drawinglayer::primitive2d::Spread_pad),
60             mpaGradientTransform(0),
61             maXLink(),
62             mpXLink(0)
63         {
64         }
65 
66         SvgGradientNode::~SvgGradientNode()
67         {
68             if(mpaGradientTransform) delete mpaGradientTransform;
69             // do NOT delete mpXLink, it's only referenced, not owned
70         }
71 
72         const SvgStyleAttributes* SvgGradientNode::getSvgStyleAttributes() const
73         {
74             return &maSvgStyleAttributes;
75         }
76 
77         void SvgGradientNode::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 SVGTokenX1:
94                 {
95                     SvgNumber aNum;
96 
97                     if(readSingleNumber(aContent, aNum))
98                     {
99                         setX1(aNum);
100                     }
101                     break;
102                 }
103                 case SVGTokenY1:
104                 {
105                     SvgNumber aNum;
106 
107                     if(readSingleNumber(aContent, aNum))
108                     {
109                         setY1(aNum);
110                     }
111                     break;
112                 }
113                 case SVGTokenX2:
114                 {
115                     SvgNumber aNum;
116 
117                     if(readSingleNumber(aContent, aNum))
118                     {
119                         setX2(aNum);
120                     }
121                     break;
122                 }
123                 case SVGTokenY2:
124                 {
125                     SvgNumber aNum;
126 
127                     if(readSingleNumber(aContent, aNum))
128                     {
129                         setY2(aNum);
130                     }
131                     break;
132                 }
133                 case SVGTokenCx:
134                 {
135                     SvgNumber aNum;
136 
137                     if(readSingleNumber(aContent, aNum))
138                     {
139                         setCx(aNum);
140                     }
141                     break;
142                 }
143                 case SVGTokenCy:
144                 {
145                     SvgNumber aNum;
146 
147                     if(readSingleNumber(aContent, aNum))
148                     {
149                         setCy(aNum);
150                     }
151                     break;
152                 }
153                 case SVGTokenFx:
154                 {
155                     SvgNumber aNum;
156 
157                     if(readSingleNumber(aContent, aNum))
158                     {
159                         setFx(aNum);
160                     }
161                     break;
162                 }
163                 case SVGTokenFy:
164                 {
165                     SvgNumber aNum;
166 
167                     if(readSingleNumber(aContent, aNum))
168                     {
169                         setFy(aNum);
170                     }
171                     break;
172                 }
173                 case SVGTokenR:
174                 {
175                     SvgNumber aNum;
176 
177                     if(readSingleNumber(aContent, aNum))
178                     {
179                         if(aNum.isPositive())
180                         {
181                             setR(aNum);
182                         }
183                     }
184                     break;
185                 }
186                 case SVGTokenGradientUnits:
187                 {
188                     if(aContent.getLength())
189                     {
190                         if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
191                         {
192                             setGradientUnits(userSpaceOnUse);
193                         }
194                         else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
195                         {
196                             setGradientUnits(objectBoundingBox);
197                         }
198                     }
199                     break;
200                 }
201                 case SVGTokenSpreadMethod:
202                 {
203                     if(aContent.getLength())
204                     {
205                         static rtl::OUString aStrPad(rtl::OUString::createFromAscii("pad"));
206                         static rtl::OUString aStrReflect(rtl::OUString::createFromAscii("reflect"));
207                         static rtl::OUString aStrRepeat(rtl::OUString::createFromAscii("repeat"));
208 
209                         if(aContent.match(aStrPad, 0))
210                         {
211                             setSpreadMethod(drawinglayer::primitive2d::Spread_pad);
212                         }
213                         else if(aContent.match(aStrReflect, 0))
214                         {
215                             setSpreadMethod(drawinglayer::primitive2d::Spread_reflect);
216                         }
217                         else if(aContent.match(aStrRepeat, 0))
218                         {
219                             setSpreadMethod(drawinglayer::primitive2d::Spread_repeat);
220                         }
221                     }
222                     break;
223                 }
224                 case SVGTokenGradientTransform:
225                 {
226                     const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
227 
228                     if(!aMatrix.isIdentity())
229                     {
230                         setGradientTransform(&aMatrix);
231                     }
232                     break;
233                 }
234                 case SVGTokenXlinkHref:
235                 {
236                     const sal_Int32 nLen(aContent.getLength());
237 
238                     if(nLen && sal_Unicode('#') == aContent[0])
239                     {
240                         maXLink = aContent.copy(1);
241                         tryToFindLink();
242                     }
243                     break;
244                 }
245             }
246         }
247 
248         void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const
249         {
250             if(getChildren().empty())
251             {
252                 const_cast< SvgGradientNode* >(this)->tryToFindLink();
253 
254                 if(mpXLink)
255                 {
256                     mpXLink->collectGradientEntries(aVector);
257                 }
258             }
259             else
260             {
261                 const sal_uInt32 nCount(getChildren().size());
262 
263                 for(sal_uInt32 a(0); a < nCount; a++)
264                 {
265                     const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a]);
266 
267                     if(pCandidate)
268                     {
269                         const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes();
270 
271                         if(pStyle)
272                         {
273                             const SvgNumber aOffset(pCandidate->getOffset());
274                             double fOffset(0.0);
275 
276                             if(Unit_percent == aOffset.getUnit())
277                             {
278                                 // percent is not relative to distances in ColorStop context, solve locally
279                                 fOffset = aOffset.getNumber() * 0.01;
280                             }
281                             else
282                             {
283                                 fOffset = aOffset.solve(*this);
284                             }
285 
286                             if(fOffset < 0.0)
287                             {
288                                 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
289                                 fOffset = 0.0;
290                             }
291                             else if(fOffset > 1.0)
292                             {
293                                 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
294                                 fOffset = 1.0;
295                             }
296 
297                             aVector.push_back(
298                                 drawinglayer::primitive2d::SvgGradientEntry(
299                                     fOffset,
300                                     pStyle->getStopColor(),
301                                     pStyle->getStopOpacity().solve(*this)));
302                         }
303                         else
304                         {
305                             OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
306                         }
307                     }
308                 }
309             }
310         }
311 
312         const SvgNumber SvgGradientNode::getX1() const
313         {
314             if(maX1.isSet())
315             {
316                 return maX1;
317             }
318 
319             const_cast< SvgGradientNode* >(this)->tryToFindLink();
320 
321             if(mpXLink)
322             {
323                 return mpXLink->getX1();
324             }
325 
326             // default is 0%
327             return SvgNumber(0.0, Unit_percent);
328         }
329 
330         const SvgNumber SvgGradientNode::getY1() const
331         {
332             if(maY1.isSet())
333             {
334                 return maY1;
335             }
336 
337             const_cast< SvgGradientNode* >(this)->tryToFindLink();
338 
339             if(mpXLink)
340             {
341                 return mpXLink->getY1();
342             }
343 
344             // default is 0%
345             return SvgNumber(0.0, Unit_percent);
346         }
347 
348         const SvgNumber SvgGradientNode::getX2() const
349         {
350             if(maX2.isSet())
351             {
352                 return maX2;
353             }
354 
355             const_cast< SvgGradientNode* >(this)->tryToFindLink();
356 
357             if(mpXLink)
358             {
359                 return mpXLink->getX2();
360             }
361 
362             // default is 100%
363             return SvgNumber(100.0, Unit_percent);
364         }
365 
366         const SvgNumber SvgGradientNode::getY2() const
367         {
368             if(maY2.isSet())
369             {
370                 return maY2;
371             }
372 
373             const_cast< SvgGradientNode* >(this)->tryToFindLink();
374 
375             if(mpXLink)
376             {
377                 return mpXLink->getY2();
378             }
379 
380             // default is 0%
381             return SvgNumber(0.0, Unit_percent);
382         }
383 
384         const SvgNumber SvgGradientNode::getCx() const
385         {
386             if(maCx.isSet())
387             {
388                 return maCx;
389             }
390 
391             const_cast< SvgGradientNode* >(this)->tryToFindLink();
392 
393             if(mpXLink)
394             {
395                 return mpXLink->getCx();
396             }
397 
398             // default is 50%
399             return SvgNumber(50.0, Unit_percent);
400         }
401 
402         const SvgNumber SvgGradientNode::getCy() const
403         {
404             if(maCy.isSet())
405             {
406                 return maCy;
407             }
408 
409             const_cast< SvgGradientNode* >(this)->tryToFindLink();
410 
411             if(mpXLink)
412             {
413                 return mpXLink->getCy();
414             }
415 
416             // default is 50%
417             return SvgNumber(50.0, Unit_percent);
418         }
419 
420         const SvgNumber SvgGradientNode::getR() const
421         {
422             if(maR.isSet())
423             {
424                 return maR;
425             }
426 
427             const_cast< SvgGradientNode* >(this)->tryToFindLink();
428 
429             if(mpXLink)
430             {
431                 return mpXLink->getR();
432             }
433 
434             // default is 50%
435             return SvgNumber(50.0, Unit_percent);
436         }
437 
438         const SvgNumber* SvgGradientNode::getFx() const
439         {
440             if(maFx.isSet())
441             {
442                 return &maFx;
443             }
444 
445             const_cast< SvgGradientNode* >(this)->tryToFindLink();
446 
447             if(mpXLink)
448             {
449                 return mpXLink->getFx();
450             }
451 
452             return 0;
453         }
454 
455         const SvgNumber* SvgGradientNode::getFy() const
456         {
457             if(maFy.isSet())
458             {
459                 return &maFy;
460             }
461 
462             const_cast< SvgGradientNode* >(this)->tryToFindLink();
463 
464             if(mpXLink)
465             {
466                 return mpXLink->getFy();
467             }
468 
469             return 0;
470         }
471 
472         const basegfx::B2DHomMatrix* SvgGradientNode::getGradientTransform() const
473         {
474             if(mpaGradientTransform)
475             {
476                 return mpaGradientTransform;
477             }
478 
479             const_cast< SvgGradientNode* >(this)->tryToFindLink();
480 
481             if(mpXLink)
482             {
483                 return mpXLink->getGradientTransform();
484             }
485 
486             return 0;
487         }
488 
489         void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix* pMatrix)
490         {
491             if(mpaGradientTransform)
492             {
493                 delete mpaGradientTransform;
494                 mpaGradientTransform = 0;
495             }
496 
497             if(pMatrix)
498             {
499                 mpaGradientTransform = new basegfx::B2DHomMatrix(*pMatrix);
500             }
501         }
502 
503     } // end of namespace svgreader
504 } // end of namespace svgio
505 
506 //////////////////////////////////////////////////////////////////////////////
507 // eof
508