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