LibreOffice Module svgio (master) 1
svggradientnode.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <svggradientnode.hxx>
21#include <svgdocument.hxx>
23#include <o3tl/string_view.hxx>
24#include <osl/diagnose.h>
25
26namespace svgio::svgreader
27{
29 {
30 if(!mpXLink && !maXLink.isEmpty())
31 {
32 mpXLink = dynamic_cast< const SvgGradientNode* >(getDocument().findSvgNodeById(maXLink));
33 }
34 }
35
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)
46 {
47 OSL_ENSURE(aType == SVGToken::LinearGradient || aType == SVGToken::RadialGradient, "SvgGradientNode should only be used for Linear and Radial gradient (!)");
48 }
49
51 {
52 // do NOT delete mpXLink, it's only referenced, not owned
53 }
54
56 {
58 }
59
60 void SvgGradientNode::parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent)
61 {
62 // call parent
63 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
64
65 // read style attributes
66 maSvgStyleAttributes.parseStyleAttribute(aSVGToken, aContent);
67
68 // parse own
69 switch(aSVGToken)
70 {
71 case SVGToken::Style:
72 {
73 readLocalCssStyle(aContent);
74 break;
75 }
76 case SVGToken::X1:
77 {
78 SvgNumber aNum;
79
80 if(readSingleNumber(aContent, aNum))
81 {
82 maX1 = aNum;
83 }
84 break;
85 }
86 case SVGToken::Y1:
87 {
88 SvgNumber aNum;
89
90 if(readSingleNumber(aContent, aNum))
91 {
92 maY1 = aNum;
93 }
94 break;
95 }
96 case SVGToken::X2:
97 {
98 SvgNumber aNum;
99
100 if(readSingleNumber(aContent, aNum))
101 {
102 maX2 = aNum;
103 }
104 break;
105 }
106 case SVGToken::Y2:
107 {
108 SvgNumber aNum;
109
110 if(readSingleNumber(aContent, aNum))
111 {
112 maY2 = aNum;
113 }
114 break;
115 }
116 case SVGToken::Cx:
117 {
118 SvgNumber aNum;
119
120 if(readSingleNumber(aContent, aNum))
121 {
122 maCx = aNum;
123 }
124 break;
125 }
126 case SVGToken::Cy:
127 {
128 SvgNumber aNum;
129
130 if(readSingleNumber(aContent, aNum))
131 {
132 maCy = aNum;
133 }
134 break;
135 }
136 case SVGToken::Fx:
137 {
138 SvgNumber aNum;
139
140 if(readSingleNumber(aContent, aNum))
141 {
142 maFx = aNum;
143 }
144 break;
145 }
146 case SVGToken::Fy:
147 {
148 SvgNumber aNum;
149
150 if(readSingleNumber(aContent, aNum))
151 {
152 maFy = aNum;
153 }
154 break;
155 }
156 case SVGToken::R:
157 {
158 SvgNumber aNum;
159
160 if(readSingleNumber(aContent, aNum))
161 {
162 if(aNum.isPositive())
163 {
164 maR = aNum;
165 }
166 }
167 break;
168 }
170 {
171 if(!aContent.isEmpty())
172 {
174 {
176 }
178 {
180 }
181 }
182 break;
183 }
185 {
186 if(!aContent.isEmpty())
187 {
188 if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"pad"))
189 {
191 }
192 else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"reflect"))
193 {
195 }
196 else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"repeat"))
197 {
199 }
200 }
201 break;
202 }
204 {
205 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
206
207 if(!aMatrix.isIdentity())
208 {
209 setGradientTransform(aMatrix);
210 }
211 break;
212 }
213 case SVGToken::Href:
215 {
216 readLocalLink(aContent, maXLink);
218 break;
219 }
220 default:
221 {
222 break;
223 }
224 }
225 }
226
228 {
229 if(getChildren().empty())
230 {
231 const_cast< SvgGradientNode* >(this)->tryToFindLink();
232
233 if (mpXLink && !mbResolvingLink)
234 {
235 mbResolvingLink = true;
237 mbResolvingLink = false;
238 }
239 }
240 else
241 {
242 const sal_uInt32 nCount(getChildren().size());
243
244 for(sal_uInt32 a(0); a < nCount; a++)
245 {
246 const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a].get());
247
248 if(pCandidate)
249 {
250 const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes();
251
252 if(pStyle)
253 {
254 const SvgNumber aOffset(pCandidate->getOffset());
255 double fOffset(0.0);
256
257 if(SvgUnit::percent == aOffset.getUnit())
258 {
259 // percent is not relative to distances in ColorStop context, solve locally
260 fOffset = aOffset.getNumber() * 0.01;
261 }
262 else
263 {
264 fOffset = aOffset.solve(*this);
265 }
266
267 if(fOffset < 0.0)
268 {
269 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
270 fOffset = 0.0;
271 }
272 else if(fOffset > 1.0)
273 {
274 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
275 fOffset = 1.0;
276 }
277
278 aVector.emplace_back(
279 fOffset,
280 pStyle->getStopColor(),
281 pStyle->getStopOpacity().solve(*this));
282 }
283 else
284 {
285 OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
286 }
287 }
288 }
289 }
290 }
291
293 {
294 if(maX1.isSet())
295 {
296 return maX1;
297 }
298
299 const_cast< SvgGradientNode* >(this)->tryToFindLink();
300
301 if (mpXLink && !mbResolvingLink)
302 {
303 mbResolvingLink = true;
304 auto ret = mpXLink->getX1();
305 mbResolvingLink = false;
306 return ret;
307 }
308
309 // default is 0%
310 return SvgNumber(0.0, SvgUnit::percent);
311 }
312
314 {
315 if(maY1.isSet())
316 {
317 return maY1;
318 }
319
320 const_cast< SvgGradientNode* >(this)->tryToFindLink();
321
322 if (mpXLink && !mbResolvingLink)
323 {
324 mbResolvingLink = true;
325 auto ret = mpXLink->getY1();
326 mbResolvingLink = false;
327 return ret;
328 }
329
330 // default is 0%
331 return SvgNumber(0.0, SvgUnit::percent);
332 }
333
335 {
336 if(maX2.isSet())
337 {
338 return maX2;
339 }
340
341 const_cast< SvgGradientNode* >(this)->tryToFindLink();
342
343 if (mpXLink && !mbResolvingLink)
344 {
345 mbResolvingLink = true;
346 auto ret = mpXLink->getX2();
347 mbResolvingLink = false;
348 return ret;
349 }
350
351 // default is 100%
352 return SvgNumber(100.0, SvgUnit::percent);
353 }
354
356 {
357 if(maY2.isSet())
358 {
359 return maY2;
360 }
361
362 const_cast< SvgGradientNode* >(this)->tryToFindLink();
363
364 if (mpXLink && !mbResolvingLink)
365 {
366 mbResolvingLink = true;
367 auto ret = mpXLink->getY2();
368 mbResolvingLink = false;
369 return ret;
370 }
371
372 // default is 0%
373 return SvgNumber(0.0, SvgUnit::percent);
374 }
375
377 {
378 if(maCx.isSet())
379 {
380 return maCx;
381 }
382
383 const_cast< SvgGradientNode* >(this)->tryToFindLink();
384
385 if (mpXLink && !mbResolvingLink)
386 {
387 mbResolvingLink = true;
388 auto ret = mpXLink->getCx();
389 mbResolvingLink = false;
390 return ret;
391 }
392
393 // default is 50%
394 return SvgNumber(50.0, SvgUnit::percent);
395 }
396
398 {
399 if(maCy.isSet())
400 {
401 return maCy;
402 }
403
404 const_cast< SvgGradientNode* >(this)->tryToFindLink();
405
406 if (mpXLink && !mbResolvingLink)
407 {
408 mbResolvingLink = true;
409 auto ret = mpXLink->getCy();
410 mbResolvingLink = false;
411 return ret;
412 }
413
414 // default is 50%
415 return SvgNumber(50.0, SvgUnit::percent);
416 }
417
419 {
420 if(maR.isSet())
421 {
422 return maR;
423 }
424
425 const_cast< SvgGradientNode* >(this)->tryToFindLink();
426
427 if (mpXLink && !mbResolvingLink)
428 {
429 mbResolvingLink = true;
430 auto ret = mpXLink->getR();
431 mbResolvingLink = false;
432 return ret;
433 }
434
435 // default is 50%
436 return SvgNumber(50.0, SvgUnit::percent);
437 }
438
440 {
441 if(maFx.isSet())
442 {
443 return &maFx;
444 }
445
446 const_cast< SvgGradientNode* >(this)->tryToFindLink();
447
448 if (mpXLink && !mbResolvingLink)
449 {
450 mbResolvingLink = true;
451 auto ret = mpXLink->getFx();
452 mbResolvingLink = false;
453 return ret;
454 }
455
456 return nullptr;
457 }
458
460 {
461 if(maFy.isSet())
462 {
463 return &maFy;
464 }
465
466 const_cast< SvgGradientNode* >(this)->tryToFindLink();
467
468 if (mpXLink && !mbResolvingLink)
469 {
470 mbResolvingLink = true;
471 auto ret = mpXLink->getFy();
472 mbResolvingLink = false;
473 return ret;
474 }
475
476 return nullptr;
477 }
478
479 std::optional<basegfx::B2DHomMatrix> SvgGradientNode::getGradientTransform() const
480 {
482 {
484 }
485
486 const_cast< SvgGradientNode* >(this)->tryToFindLink();
487
488 if (mpXLink && !mbResolvingLink)
489 {
490 mbResolvingLink = true;
491 auto ret = mpXLink->getGradientTransform();
492 mbResolvingLink = false;
493 return ret;
494 }
495
496 return std::nullopt;
497 }
498
499} // end of namespace svgio::svgreader
500
501/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool isIdentity() const
const SvgNode * findSvgNodeById(const OUString &rStr) const
find a node by its Id
Definition: svgdocument.cxx:56
SvgNumber getY2() const
y2 content
SvgNumber getX1() const
x1 content
SvgNumber maCx
radial gradient values
void setGradientTransform(const std::optional< basegfx::B2DHomMatrix > &pMatrix)
const SvgGradientNode * mpXLink
SvgGradientNode(SVGToken aType, SvgDocument &rDocument, SvgNode *pParent)
SvgNumber getCy() const
Cy content.
bool mbResolvingLink
link to another gradient used as style.
void collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector &aVector) const
collect gradient stop entries
const SvgNumber * getFy() const
Fy content.
std::optional< basegfx::B2DHomMatrix > mpaGradientTransform
SvgNumber getCx() const
Cx content.
SvgStyleAttributes maSvgStyleAttributes
use styles
virtual void parseAttribute(const OUString &rTokenName, SVGToken aSVGToken, const OUString &aContent) override
SvgNumber getX2() const
x2 content
SvgNumber getY1() const
y1 content
virtual const SvgStyleAttributes * getSvgStyleAttributes() const override
std::optional< basegfx::B2DHomMatrix > getGradientTransform() const
transform content, set if found in current context
const SvgNumber * getFx() const
Fx content.
void setGradientUnits(const SvgUnits aGradientUnits)
SvgNumber maX1
linear gradient values
SvgNumber getR() const
R content.
void setSpreadMethod(const drawinglayer::primitive2d::SpreadMethod aSpreadMethod)
const SvgNumber & getOffset() const
offset content
virtual const SvgStyleAttributes * getSvgStyleAttributes() const override
const std::vector< std::unique_ptr< SvgNode > > & getChildren() const
Definition: svgnode.hxx:159
const SvgStyleAttributes * checkForCssStyle(const SvgStyleAttributes &rOriginal) const
helper to evtl. link to css style
Definition: svgnode.cxx:335
virtual void parseAttribute(const OUString &rTokenName, SVGToken aSVGToken, const OUString &aContent)
Definition: svgnode.cxx:534
void readLocalCssStyle(std::u16string_view aContent)
scan helper to read and interpret a local CssStyle to mpLocalCssStyle
Definition: svgnode.cxx:412
const SvgDocument & getDocument() const
Definition: svgnode.hxx:157
SvgUnit getUnit() const
Definition: SvgNumber.hxx:90
double solve(const InfoProvider &rInfoProvider, NumberType aNumberType=NumberType::length) const
Definition: SvgNumber.cxx:69
double getNumber() const
Definition: SvgNumber.hxx:85
SvgNumber getStopOpacity() const
stop opacity content
const basegfx::BColor & getStopColor() const
stop color content
void parseStyleAttribute(SVGToken aSVGToken, const OUString &rContent)
local attribute scanner
int nCount
float u
uno_Any a
size
SpreadMethod
::std::vector< SvgGradientEntry > SvgGradientEntryVector
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
bool readLocalLink(std::u16string_view rCandidate, OUString &rURL)
Definition: svgtools.cxx:1084
bool readSingleNumber(std::u16string_view rCandidate, SvgNumber &aNum)
Definition: svgtools.cxx:1076
basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, InfoProvider const &rInfoProvider)
Definition: svgtools.cxx:871
static constexpr OUStringLiteral aStrUserSpaceOnUse
Definition: svgtools.hxx:38
static constexpr OUStringLiteral aStrObjectBoundingBox
Definition: svgtools.hxx:39