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                 default:
246                 {
247                     break;
248                 }
249             }
250         }
251 
252         void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const
253         {
254             if(getChildren().empty())
255             {
256                 const_cast< SvgGradientNode* >(this)->tryToFindLink();
257 
258                 if(mpXLink)
259                 {
260                     mpXLink->collectGradientEntries(aVector);
261                 }
262             }
263             else
264             {
265                 const sal_uInt32 nCount(getChildren().size());
266 
267                 for(sal_uInt32 a(0); a < nCount; a++)
268                 {
269                     const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a]);
270 
271                     if(pCandidate)
272                     {
273                         const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes();
274 
275                         if(pStyle)
276                         {
277                             const SvgNumber aOffset(pCandidate->getOffset());
278                             double fOffset(0.0);
279 
280                             if(Unit_percent == aOffset.getUnit())
281                             {
282                                 // percent is not relative to distances in ColorStop context, solve locally
283                                 fOffset = aOffset.getNumber() * 0.01;
284                             }
285                             else
286                             {
287                                 fOffset = aOffset.solve(*this);
288                             }
289 
290                             if(fOffset < 0.0)
291                             {
292                                 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
293                                 fOffset = 0.0;
294                             }
295                             else if(fOffset > 1.0)
296                             {
297                                 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
298                                 fOffset = 1.0;
299                             }
300 
301                             aVector.push_back(
302                                 drawinglayer::primitive2d::SvgGradientEntry(
303                                     fOffset,
304                                     pStyle->getStopColor(),
305                                     pStyle->getStopOpacity().solve(*this)));
306                         }
307                         else
308                         {
309                             OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
310                         }
311                     }
312                 }
313             }
314         }
315 
316         const SvgNumber SvgGradientNode::getX1() const
317         {
318             if(maX1.isSet())
319             {
320                 return maX1;
321             }
322 
323             const_cast< SvgGradientNode* >(this)->tryToFindLink();
324 
325             if(mpXLink)
326             {
327                 return mpXLink->getX1();
328             }
329 
330             // default is 0%
331             return SvgNumber(0.0, Unit_percent);
332         }
333 
334         const SvgNumber SvgGradientNode::getY1() const
335         {
336             if(maY1.isSet())
337             {
338                 return maY1;
339             }
340 
341             const_cast< SvgGradientNode* >(this)->tryToFindLink();
342 
343             if(mpXLink)
344             {
345                 return mpXLink->getY1();
346             }
347 
348             // default is 0%
349             return SvgNumber(0.0, Unit_percent);
350         }
351 
352         const SvgNumber SvgGradientNode::getX2() const
353         {
354             if(maX2.isSet())
355             {
356                 return maX2;
357             }
358 
359             const_cast< SvgGradientNode* >(this)->tryToFindLink();
360 
361             if(mpXLink)
362             {
363                 return mpXLink->getX2();
364             }
365 
366             // default is 100%
367             return SvgNumber(100.0, Unit_percent);
368         }
369 
370         const SvgNumber SvgGradientNode::getY2() const
371         {
372             if(maY2.isSet())
373             {
374                 return maY2;
375             }
376 
377             const_cast< SvgGradientNode* >(this)->tryToFindLink();
378 
379             if(mpXLink)
380             {
381                 return mpXLink->getY2();
382             }
383 
384             // default is 0%
385             return SvgNumber(0.0, Unit_percent);
386         }
387 
388         const SvgNumber SvgGradientNode::getCx() const
389         {
390             if(maCx.isSet())
391             {
392                 return maCx;
393             }
394 
395             const_cast< SvgGradientNode* >(this)->tryToFindLink();
396 
397             if(mpXLink)
398             {
399                 return mpXLink->getCx();
400             }
401 
402             // default is 50%
403             return SvgNumber(50.0, Unit_percent);
404         }
405 
406         const SvgNumber SvgGradientNode::getCy() const
407         {
408             if(maCy.isSet())
409             {
410                 return maCy;
411             }
412 
413             const_cast< SvgGradientNode* >(this)->tryToFindLink();
414 
415             if(mpXLink)
416             {
417                 return mpXLink->getCy();
418             }
419 
420             // default is 50%
421             return SvgNumber(50.0, Unit_percent);
422         }
423 
424         const SvgNumber SvgGradientNode::getR() const
425         {
426             if(maR.isSet())
427             {
428                 return maR;
429             }
430 
431             const_cast< SvgGradientNode* >(this)->tryToFindLink();
432 
433             if(mpXLink)
434             {
435                 return mpXLink->getR();
436             }
437 
438             // default is 50%
439             return SvgNumber(50.0, Unit_percent);
440         }
441 
442         const SvgNumber* SvgGradientNode::getFx() const
443         {
444             if(maFx.isSet())
445             {
446                 return &maFx;
447             }
448 
449             const_cast< SvgGradientNode* >(this)->tryToFindLink();
450 
451             if(mpXLink)
452             {
453                 return mpXLink->getFx();
454             }
455 
456             return 0;
457         }
458 
459         const SvgNumber* SvgGradientNode::getFy() const
460         {
461             if(maFy.isSet())
462             {
463                 return &maFy;
464             }
465 
466             const_cast< SvgGradientNode* >(this)->tryToFindLink();
467 
468             if(mpXLink)
469             {
470                 return mpXLink->getFy();
471             }
472 
473             return 0;
474         }
475 
476         const basegfx::B2DHomMatrix* SvgGradientNode::getGradientTransform() const
477         {
478             if(mpaGradientTransform)
479             {
480                 return mpaGradientTransform;
481             }
482 
483             const_cast< SvgGradientNode* >(this)->tryToFindLink();
484 
485             if(mpXLink)
486             {
487                 return mpXLink->getGradientTransform();
488             }
489 
490             return 0;
491         }
492 
493         void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix* pMatrix)
494         {
495             if(mpaGradientTransform)
496             {
497                 delete mpaGradientTransform;
498                 mpaGradientTransform = 0;
499             }
500 
501             if(pMatrix)
502             {
503                 mpaGradientTransform = new basegfx::B2DHomMatrix(*pMatrix);
504             }
505         }
506 
507     } // end of namespace svgreader
508 } // end of namespace svgio
509 
510 //////////////////////////////////////////////////////////////////////////////
511 // eof
512