calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / svgio / source / svgreader / svggradientnode.cxx
blob02e1b85bf17ff164c2167600e8857ba5d5451f3a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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(
37 SVGToken aType,
38 SvgDocument& rDocument,
39 SvgNode* pParent)
40 : SvgNode(aType, rDocument, pParent),
41 maSvgStyleAttributes(*this),
42 maGradientUnits(SvgUnits::objectBoundingBox),
43 maSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad),
44 mbResolvingLink(false),
45 mpXLink(nullptr)
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)
64 // call parent
65 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
67 // read style attributes
68 maSvgStyleAttributes.parseStyleAttribute(aSVGToken, aContent);
70 // parse own
71 switch(aSVGToken)
73 case SVGToken::Style:
75 readLocalCssStyle(aContent);
76 break;
78 case SVGToken::X1:
80 SvgNumber aNum;
82 if(readSingleNumber(aContent, aNum))
84 maX1 = aNum;
86 break;
88 case SVGToken::Y1:
90 SvgNumber aNum;
92 if(readSingleNumber(aContent, aNum))
94 maY1 = aNum;
96 break;
98 case SVGToken::X2:
100 SvgNumber aNum;
102 if(readSingleNumber(aContent, aNum))
104 maX2 = aNum;
106 break;
108 case SVGToken::Y2:
110 SvgNumber aNum;
112 if(readSingleNumber(aContent, aNum))
114 maY2 = aNum;
116 break;
118 case SVGToken::Cx:
120 SvgNumber aNum;
122 if(readSingleNumber(aContent, aNum))
124 maCx = aNum;
126 break;
128 case SVGToken::Cy:
130 SvgNumber aNum;
132 if(readSingleNumber(aContent, aNum))
134 maCy = aNum;
136 break;
138 case SVGToken::Fx:
140 SvgNumber aNum;
142 if(readSingleNumber(aContent, aNum))
144 maFx = aNum;
146 break;
148 case SVGToken::Fy:
150 SvgNumber aNum;
152 if(readSingleNumber(aContent, aNum))
154 maFy = aNum;
156 break;
158 case SVGToken::R:
160 SvgNumber aNum;
162 if(readSingleNumber(aContent, aNum))
164 if(aNum.isPositive())
166 maR = aNum;
169 break;
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);
184 break;
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);
203 break;
205 case SVGToken::GradientTransform:
207 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
209 if(!aMatrix.isIdentity())
211 setGradientTransform(aMatrix);
213 break;
215 case SVGToken::Href:
216 case SVGToken::XlinkHref:
218 readLocalLink(aContent, maXLink);
219 tryToFindLink();
220 break;
222 default:
224 break;
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;
242 else
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());
250 if(pCandidate)
252 const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes();
254 if(pStyle)
256 const SvgNumber aOffset(pCandidate->getOffset());
257 double fOffset(0.0);
259 if(SvgUnit::percent == aOffset.getUnit())
261 // percent is not relative to distances in ColorStop context, solve locally
262 fOffset = aOffset.getNumber() * 0.01;
264 else
266 fOffset = aOffset.solve(*this);
269 if(fOffset < 0.0)
271 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
272 fOffset = 0.0;
274 else if(fOffset > 1.0)
276 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
277 fOffset = 1.0;
280 aVector.emplace_back(
281 fOffset,
282 pStyle->getStopColor(),
283 pStyle->getStopOpacity().solve(*this));
285 else
287 OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
294 SvgNumber SvgGradientNode::getX1() const
296 if(maX1.isSet())
298 return maX1;
301 const_cast< SvgGradientNode* >(this)->tryToFindLink();
303 if (mpXLink && !mbResolvingLink)
305 mbResolvingLink = true;
306 auto ret = mpXLink->getX1();
307 mbResolvingLink = false;
308 return ret;
311 // default is 0%
312 return SvgNumber(0.0, SvgUnit::percent);
315 SvgNumber SvgGradientNode::getY1() const
317 if(maY1.isSet())
319 return maY1;
322 const_cast< SvgGradientNode* >(this)->tryToFindLink();
324 if (mpXLink && !mbResolvingLink)
326 mbResolvingLink = true;
327 auto ret = mpXLink->getY1();
328 mbResolvingLink = false;
329 return ret;
332 // default is 0%
333 return SvgNumber(0.0, SvgUnit::percent);
336 SvgNumber SvgGradientNode::getX2() const
338 if(maX2.isSet())
340 return maX2;
343 const_cast< SvgGradientNode* >(this)->tryToFindLink();
345 if (mpXLink && !mbResolvingLink)
347 mbResolvingLink = true;
348 auto ret = mpXLink->getX2();
349 mbResolvingLink = false;
350 return ret;
353 // default is 100%
354 return SvgNumber(100.0, SvgUnit::percent);
357 SvgNumber SvgGradientNode::getY2() const
359 if(maY2.isSet())
361 return maY2;
364 const_cast< SvgGradientNode* >(this)->tryToFindLink();
366 if (mpXLink && !mbResolvingLink)
368 mbResolvingLink = true;
369 auto ret = mpXLink->getY2();
370 mbResolvingLink = false;
371 return ret;
374 // default is 0%
375 return SvgNumber(0.0, SvgUnit::percent);
378 SvgNumber SvgGradientNode::getCx() const
380 if(maCx.isSet())
382 return maCx;
385 const_cast< SvgGradientNode* >(this)->tryToFindLink();
387 if (mpXLink && !mbResolvingLink)
389 mbResolvingLink = true;
390 auto ret = mpXLink->getCx();
391 mbResolvingLink = false;
392 return ret;
395 // default is 50%
396 return SvgNumber(50.0, SvgUnit::percent);
399 SvgNumber SvgGradientNode::getCy() const
401 if(maCy.isSet())
403 return maCy;
406 const_cast< SvgGradientNode* >(this)->tryToFindLink();
408 if (mpXLink && !mbResolvingLink)
410 mbResolvingLink = true;
411 auto ret = mpXLink->getCy();
412 mbResolvingLink = false;
413 return ret;
416 // default is 50%
417 return SvgNumber(50.0, SvgUnit::percent);
420 SvgNumber SvgGradientNode::getR() const
422 if(maR.isSet())
424 return maR;
427 const_cast< SvgGradientNode* >(this)->tryToFindLink();
429 if (mpXLink && !mbResolvingLink)
431 mbResolvingLink = true;
432 auto ret = mpXLink->getR();
433 mbResolvingLink = false;
434 return ret;
437 // default is 50%
438 return SvgNumber(50.0, SvgUnit::percent);
441 const SvgNumber* SvgGradientNode::getFx() const
443 if(maFx.isSet())
445 return &maFx;
448 const_cast< SvgGradientNode* >(this)->tryToFindLink();
450 if (mpXLink && !mbResolvingLink)
452 mbResolvingLink = true;
453 auto ret = mpXLink->getFx();
454 mbResolvingLink = false;
455 return ret;
458 return nullptr;
461 const SvgNumber* SvgGradientNode::getFy() const
463 if(maFy.isSet())
465 return &maFy;
468 const_cast< SvgGradientNode* >(this)->tryToFindLink();
470 if (mpXLink && !mbResolvingLink)
472 mbResolvingLink = true;
473 auto ret = mpXLink->getFy();
474 mbResolvingLink = false;
475 return ret;
478 return nullptr;
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;
495 return ret;
498 return std::nullopt;
501 } // end of namespace svgio::svgreader
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */