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