1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svggradientnode.hxx>
21 #include <svgdocument.hxx>
22 #include <svggradientstopnode.hxx>
24 namespace svgio::svgreader
26 void SvgGradientNode::tryToFindLink()
28 if(!mpXLink
&& !maXLink
.isEmpty())
30 mpXLink
= dynamic_cast< const SvgGradientNode
* >(getDocument().findSvgNodeById(maXLink
));
34 SvgGradientNode::SvgGradientNode(
36 SvgDocument
& rDocument
,
38 : SvgNode(aType
, rDocument
, pParent
),
39 maSvgStyleAttributes(*this),
49 maGradientUnits(SvgUnits::objectBoundingBox
),
50 maSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad
),
51 mbResolvingLink(false),
55 OSL_ENSURE(aType
== SVGToken::LinearGradient
|| aType
== SVGToken::RadialGradient
, "SvgGradientNode should only be used for Linear and Radial gradient (!)");
58 SvgGradientNode::~SvgGradientNode()
60 // do NOT delete mpXLink, it's only referenced, not owned
63 const SvgStyleAttributes
* SvgGradientNode::getSvgStyleAttributes() const
65 return checkForCssStyle(
66 SVGToken::LinearGradient
== getType() ? OUString("linearGradient") : OUString("radialGradient"),
67 maSvgStyleAttributes
);
70 void SvgGradientNode::parseAttribute(const OUString
& rTokenName
, SVGToken aSVGToken
, const OUString
& aContent
)
73 SvgNode::parseAttribute(rTokenName
, aSVGToken
, aContent
);
75 // read style attributes
76 maSvgStyleAttributes
.parseStyleAttribute(aSVGToken
, aContent
, false);
83 readLocalCssStyle(aContent
);
90 if(readSingleNumber(aContent
, aNum
))
100 if(readSingleNumber(aContent
, aNum
))
110 if(readSingleNumber(aContent
, aNum
))
120 if(readSingleNumber(aContent
, aNum
))
130 if(readSingleNumber(aContent
, aNum
))
140 if(readSingleNumber(aContent
, aNum
))
150 if(readSingleNumber(aContent
, aNum
))
160 if(readSingleNumber(aContent
, aNum
))
170 if(readSingleNumber(aContent
, aNum
))
172 if(aNum
.isPositive())
179 case SVGToken::GradientUnits
:
181 if(!aContent
.isEmpty())
183 if(aContent
.match(commonStrings::aStrUserSpaceOnUse
))
185 setGradientUnits(SvgUnits::userSpaceOnUse
);
187 else if(aContent
.match(commonStrings::aStrObjectBoundingBox
))
189 setGradientUnits(SvgUnits::objectBoundingBox
);
194 case SVGToken::SpreadMethod
:
196 if(!aContent
.isEmpty())
198 if(aContent
.startsWith("pad"))
200 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad
);
202 else if(aContent
.startsWith("reflect"))
204 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Reflect
);
206 else if(aContent
.startsWith("repeat"))
208 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Repeat
);
213 case SVGToken::GradientTransform
:
215 const basegfx::B2DHomMatrix
aMatrix(readTransform(aContent
, *this));
217 if(!aMatrix
.isIdentity())
219 setGradientTransform(&aMatrix
);
223 case SVGToken::XlinkHref
:
225 const sal_Int32
nLen(aContent
.getLength());
227 if(nLen
&& '#' == aContent
[0])
229 maXLink
= aContent
.copy(1);
241 void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector
& aVector
) const
243 if(getChildren().empty())
245 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
247 if (mpXLink
&& !mbResolvingLink
)
249 mbResolvingLink
= true;
250 mpXLink
->collectGradientEntries(aVector
);
251 mbResolvingLink
= false;
256 const sal_uInt32
nCount(getChildren().size());
258 for(sal_uInt32
a(0); a
< nCount
; a
++)
260 const SvgGradientStopNode
* pCandidate
= dynamic_cast< const SvgGradientStopNode
* >(getChildren()[a
].get());
264 const SvgStyleAttributes
* pStyle
= pCandidate
->getSvgStyleAttributes();
268 const SvgNumber
aOffset(pCandidate
->getOffset());
271 if(SvgUnit::percent
== aOffset
.getUnit())
273 // percent is not relative to distances in ColorStop context, solve locally
274 fOffset
= aOffset
.getNumber() * 0.01;
278 fOffset
= aOffset
.solve(*this);
283 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
286 else if(fOffset
> 1.0)
288 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
292 aVector
.emplace_back(
294 pStyle
->getStopColor(),
295 pStyle
->getStopOpacity().solve(*this));
299 OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
306 SvgNumber
SvgGradientNode::getX1() const
313 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
315 if (mpXLink
&& !mbResolvingLink
)
317 mbResolvingLink
= true;
318 auto ret
= mpXLink
->getX1();
319 mbResolvingLink
= false;
324 return SvgNumber(0.0, SvgUnit::percent
);
327 SvgNumber
SvgGradientNode::getY1() const
334 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
336 if (mpXLink
&& !mbResolvingLink
)
338 mbResolvingLink
= true;
339 auto ret
= mpXLink
->getY1();
340 mbResolvingLink
= false;
345 return SvgNumber(0.0, SvgUnit::percent
);
348 SvgNumber
SvgGradientNode::getX2() const
355 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
357 if (mpXLink
&& !mbResolvingLink
)
359 mbResolvingLink
= true;
360 auto ret
= mpXLink
->getX2();
361 mbResolvingLink
= false;
366 return SvgNumber(100.0, SvgUnit::percent
);
369 SvgNumber
SvgGradientNode::getY2() const
376 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
378 if (mpXLink
&& !mbResolvingLink
)
380 mbResolvingLink
= true;
381 auto ret
= mpXLink
->getY2();
382 mbResolvingLink
= false;
387 return SvgNumber(0.0, SvgUnit::percent
);
390 SvgNumber
SvgGradientNode::getCx() const
397 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
399 if (mpXLink
&& !mbResolvingLink
)
401 mbResolvingLink
= true;
402 auto ret
= mpXLink
->getCx();
403 mbResolvingLink
= false;
408 return SvgNumber(50.0, SvgUnit::percent
);
411 SvgNumber
SvgGradientNode::getCy() const
418 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
420 if (mpXLink
&& !mbResolvingLink
)
422 mbResolvingLink
= true;
423 auto ret
= mpXLink
->getCy();
424 mbResolvingLink
= false;
429 return SvgNumber(50.0, SvgUnit::percent
);
432 SvgNumber
SvgGradientNode::getR() const
439 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
441 if (mpXLink
&& !mbResolvingLink
)
443 mbResolvingLink
= true;
444 auto ret
= mpXLink
->getR();
445 mbResolvingLink
= false;
450 return SvgNumber(50.0, SvgUnit::percent
);
453 const SvgNumber
* SvgGradientNode::getFx() const
460 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
462 if (mpXLink
&& !mbResolvingLink
)
464 mbResolvingLink
= true;
465 auto ret
= mpXLink
->getFx();
466 mbResolvingLink
= false;
473 const SvgNumber
* SvgGradientNode::getFy() const
480 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
482 if (mpXLink
&& !mbResolvingLink
)
484 mbResolvingLink
= true;
485 auto ret
= mpXLink
->getFy();
486 mbResolvingLink
= false;
493 const basegfx::B2DHomMatrix
* SvgGradientNode::getGradientTransform() const
495 if(mpaGradientTransform
)
497 return mpaGradientTransform
.get();
500 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
502 if (mpXLink
&& !mbResolvingLink
)
504 mbResolvingLink
= true;
505 auto ret
= mpXLink
->getGradientTransform();
506 mbResolvingLink
= false;
513 void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix
* pMatrix
)
515 mpaGradientTransform
.reset();
519 mpaGradientTransform
.reset(new basegfx::B2DHomMatrix(*pMatrix
) );
523 } // end of namespace svgio::svgreader
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */