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>
23 #include <o3tl/string_view.hxx>
24 #include <osl/diagnose.h>
26 namespace svgio::svgreader
28 void SvgGradientNode::tryToFindLink()
30 if(!mpXLink
&& !maXLink
.isEmpty())
32 mpXLink
= dynamic_cast< const SvgGradientNode
* >(getDocument().findSvgNodeById(maXLink
));
36 SvgGradientNode::SvgGradientNode(
38 SvgDocument
& rDocument
,
40 : SvgNode(aType
, rDocument
, pParent
),
41 maSvgStyleAttributes(*this),
42 maGradientUnits(SvgUnits::objectBoundingBox
),
43 maSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad
),
44 mbResolvingLink(false),
47 OSL_ENSURE(aType
== SVGToken::LinearGradient
|| aType
== SVGToken::RadialGradient
, "SvgGradientNode should only be used for Linear and Radial gradient (!)");
50 SvgGradientNode::~SvgGradientNode()
52 // do NOT delete mpXLink, it's only referenced, not owned
55 const SvgStyleAttributes
* SvgGradientNode::getSvgStyleAttributes() const
57 return checkForCssStyle(
58 SVGToken::LinearGradient
== getType() ? OUString("linearGradient") : OUString("radialGradient"),
59 maSvgStyleAttributes
);
62 void SvgGradientNode::parseAttribute(const OUString
& rTokenName
, SVGToken aSVGToken
, const OUString
& aContent
)
65 SvgNode::parseAttribute(rTokenName
, aSVGToken
, aContent
);
67 // read style attributes
68 maSvgStyleAttributes
.parseStyleAttribute(aSVGToken
, aContent
);
75 readLocalCssStyle(aContent
);
82 if(readSingleNumber(aContent
, aNum
))
92 if(readSingleNumber(aContent
, aNum
))
102 if(readSingleNumber(aContent
, aNum
))
112 if(readSingleNumber(aContent
, aNum
))
122 if(readSingleNumber(aContent
, aNum
))
132 if(readSingleNumber(aContent
, aNum
))
142 if(readSingleNumber(aContent
, aNum
))
152 if(readSingleNumber(aContent
, aNum
))
162 if(readSingleNumber(aContent
, aNum
))
164 if(aNum
.isPositive())
171 case SVGToken::GradientUnits
:
173 if(!aContent
.isEmpty())
175 if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent
), commonStrings::aStrUserSpaceOnUse
))
177 setGradientUnits(SvgUnits::userSpaceOnUse
);
179 else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent
), commonStrings::aStrObjectBoundingBox
))
181 setGradientUnits(SvgUnits::objectBoundingBox
);
186 case SVGToken::SpreadMethod
:
188 if(!aContent
.isEmpty())
190 if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent
), u
"pad"))
192 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad
);
194 else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent
), u
"reflect"))
196 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Reflect
);
198 else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent
), u
"repeat"))
200 setSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Repeat
);
205 case SVGToken::GradientTransform
:
207 const basegfx::B2DHomMatrix
aMatrix(readTransform(aContent
, *this));
209 if(!aMatrix
.isIdentity())
211 setGradientTransform(aMatrix
);
216 case SVGToken::XlinkHref
:
218 readLocalLink(aContent
, maXLink
);
229 void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector
& aVector
) const
231 if(getChildren().empty())
233 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
235 if (mpXLink
&& !mbResolvingLink
)
237 mbResolvingLink
= true;
238 mpXLink
->collectGradientEntries(aVector
);
239 mbResolvingLink
= false;
244 const sal_uInt32
nCount(getChildren().size());
246 for(sal_uInt32
a(0); a
< nCount
; a
++)
248 const SvgGradientStopNode
* pCandidate
= dynamic_cast< const SvgGradientStopNode
* >(getChildren()[a
].get());
252 const SvgStyleAttributes
* pStyle
= pCandidate
->getSvgStyleAttributes();
256 const SvgNumber
aOffset(pCandidate
->getOffset());
259 if(SvgUnit::percent
== aOffset
.getUnit())
261 // percent is not relative to distances in ColorStop context, solve locally
262 fOffset
= aOffset
.getNumber() * 0.01;
266 fOffset
= aOffset
.solve(*this);
271 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
274 else if(fOffset
> 1.0)
276 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
280 aVector
.emplace_back(
282 pStyle
->getStopColor(),
283 pStyle
->getStopOpacity().solve(*this));
287 OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
294 SvgNumber
SvgGradientNode::getX1() const
301 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
303 if (mpXLink
&& !mbResolvingLink
)
305 mbResolvingLink
= true;
306 auto ret
= mpXLink
->getX1();
307 mbResolvingLink
= false;
312 return SvgNumber(0.0, SvgUnit::percent
);
315 SvgNumber
SvgGradientNode::getY1() const
322 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
324 if (mpXLink
&& !mbResolvingLink
)
326 mbResolvingLink
= true;
327 auto ret
= mpXLink
->getY1();
328 mbResolvingLink
= false;
333 return SvgNumber(0.0, SvgUnit::percent
);
336 SvgNumber
SvgGradientNode::getX2() const
343 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
345 if (mpXLink
&& !mbResolvingLink
)
347 mbResolvingLink
= true;
348 auto ret
= mpXLink
->getX2();
349 mbResolvingLink
= false;
354 return SvgNumber(100.0, SvgUnit::percent
);
357 SvgNumber
SvgGradientNode::getY2() const
364 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
366 if (mpXLink
&& !mbResolvingLink
)
368 mbResolvingLink
= true;
369 auto ret
= mpXLink
->getY2();
370 mbResolvingLink
= false;
375 return SvgNumber(0.0, SvgUnit::percent
);
378 SvgNumber
SvgGradientNode::getCx() const
385 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
387 if (mpXLink
&& !mbResolvingLink
)
389 mbResolvingLink
= true;
390 auto ret
= mpXLink
->getCx();
391 mbResolvingLink
= false;
396 return SvgNumber(50.0, SvgUnit::percent
);
399 SvgNumber
SvgGradientNode::getCy() const
406 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
408 if (mpXLink
&& !mbResolvingLink
)
410 mbResolvingLink
= true;
411 auto ret
= mpXLink
->getCy();
412 mbResolvingLink
= false;
417 return SvgNumber(50.0, SvgUnit::percent
);
420 SvgNumber
SvgGradientNode::getR() const
427 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
429 if (mpXLink
&& !mbResolvingLink
)
431 mbResolvingLink
= true;
432 auto ret
= mpXLink
->getR();
433 mbResolvingLink
= false;
438 return SvgNumber(50.0, SvgUnit::percent
);
441 const SvgNumber
* SvgGradientNode::getFx() const
448 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
450 if (mpXLink
&& !mbResolvingLink
)
452 mbResolvingLink
= true;
453 auto ret
= mpXLink
->getFx();
454 mbResolvingLink
= false;
461 const SvgNumber
* SvgGradientNode::getFy() const
468 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
470 if (mpXLink
&& !mbResolvingLink
)
472 mbResolvingLink
= true;
473 auto ret
= mpXLink
->getFy();
474 mbResolvingLink
= false;
481 std::optional
<basegfx::B2DHomMatrix
> SvgGradientNode::getGradientTransform() const
483 if(mpaGradientTransform
)
485 return mpaGradientTransform
;
488 const_cast< SvgGradientNode
* >(this)->tryToFindLink();
490 if (mpXLink
&& !mbResolvingLink
)
492 mbResolvingLink
= true;
493 auto ret
= mpXLink
->getGradientTransform();
494 mbResolvingLink
= false;
501 } // end of namespace svgio::svgreader
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */