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 <svgpatternnode.hxx>
21 #include <svgdocument.hxx>
23 namespace svgio::svgreader
25 void SvgPatternNode::tryToFindLink()
27 if(!mpXLink
&& !maXLink
.isEmpty())
29 mpXLink
= dynamic_cast< const SvgPatternNode
* >(getDocument().findSvgNodeById(maXLink
));
33 SvgPatternNode::SvgPatternNode(
34 SvgDocument
& rDocument
,
36 : SvgNode(SVGToken::Pattern
, rDocument
, pParent
),
38 maSvgStyleAttributes(*this),
44 mbResolvingLink(false),
50 SvgPatternNode::~SvgPatternNode()
54 const SvgStyleAttributes
* SvgPatternNode::getSvgStyleAttributes() const
56 return checkForCssStyle("pattern", maSvgStyleAttributes
);
59 void SvgPatternNode::parseAttribute(const OUString
& rTokenName
, SVGToken aSVGToken
, const OUString
& aContent
)
62 SvgNode::parseAttribute(rTokenName
, aSVGToken
, aContent
);
64 // read style attributes
65 maSvgStyleAttributes
.parseStyleAttribute(aSVGToken
, aContent
, false);
72 readLocalCssStyle(aContent
);
75 case SVGToken::ViewBox
:
77 const basegfx::B2DRange
aRange(readViewBox(aContent
, *this));
85 case SVGToken::PreserveAspectRatio
:
87 maSvgAspectRatio
= readSvgAspectRatio(aContent
);
94 if(readSingleNumber(aContent
, aNum
))
104 if(readSingleNumber(aContent
, aNum
))
110 case SVGToken::Width
:
114 if(readSingleNumber(aContent
, aNum
))
116 if(aNum
.isPositive())
123 case SVGToken::Height
:
127 if(readSingleNumber(aContent
, aNum
))
129 if(aNum
.isPositive())
136 case SVGToken::PatternUnits
:
138 if(!aContent
.isEmpty())
140 if(aContent
.match(commonStrings::aStrUserSpaceOnUse
))
142 setPatternUnits(SvgUnits::userSpaceOnUse
);
144 else if(aContent
.match(commonStrings::aStrObjectBoundingBox
))
146 setPatternUnits(SvgUnits::objectBoundingBox
);
151 case SVGToken::PatternContentUnits
:
153 if(!aContent
.isEmpty())
155 if(aContent
.match(commonStrings::aStrUserSpaceOnUse
))
157 setPatternContentUnits(SvgUnits::userSpaceOnUse
);
159 else if(aContent
.match(commonStrings::aStrObjectBoundingBox
))
161 setPatternContentUnits(SvgUnits::objectBoundingBox
);
166 case SVGToken::PatternTransform
:
168 const basegfx::B2DHomMatrix
aMatrix(readTransform(aContent
, *this));
170 if(!aMatrix
.isIdentity())
172 setPatternTransform(&aMatrix
);
176 case SVGToken::XlinkHref
:
178 const sal_Int32
nLen(aContent
.getLength());
180 if(nLen
&& '#' == aContent
[0])
182 maXLink
= aContent
.copy(1);
194 void SvgPatternNode::getValuesRelative(double& rfX
, double& rfY
, double& rfW
, double& rfH
, const basegfx::B2DRange
& rGeoRange
, SvgNode
const & rUser
) const
196 double fTargetWidth(rGeoRange
.getWidth());
197 double fTargetHeight(rGeoRange
.getHeight());
199 if(fTargetWidth
<= 0.0 || fTargetHeight
<= 0.0)
202 const SvgUnits
aPatternUnits(getPatternUnits() ? *getPatternUnits() : SvgUnits::objectBoundingBox
);
204 if (SvgUnits::objectBoundingBox
== aPatternUnits
)
206 rfW
= (getWidth().isSet()) ? getWidth().getNumber() : 0.0;
207 rfH
= (getHeight().isSet()) ? getHeight().getNumber() : 0.0;
209 if(SvgUnit::percent
== getWidth().getUnit())
214 if(SvgUnit::percent
== getHeight().getUnit())
221 rfW
= (getWidth().isSet()) ? getWidth().solve(rUser
, NumberType::xcoordinate
) : 0.0;
222 rfH
= (getHeight().isSet()) ? getHeight().solve(rUser
, NumberType::ycoordinate
) : 0.0;
224 // make relative to rGeoRange
226 rfH
/= fTargetHeight
;
229 if(rfW
<= 0.0 || rfH
<= 0.0)
232 if (SvgUnits::objectBoundingBox
== aPatternUnits
)
234 rfX
= (getX().isSet()) ? getX().getNumber() : 0.0;
235 rfY
= (getY().isSet()) ? getY().getNumber() : 0.0;
237 if(SvgUnit::percent
== getX().getUnit())
242 if(SvgUnit::percent
== getY().getUnit())
249 rfX
= (getX().isSet()) ? getX().solve(rUser
, NumberType::xcoordinate
) : 0.0;
250 rfY
= (getY().isSet()) ? getY().solve(rUser
, NumberType::ycoordinate
) : 0.0;
252 // make relative to rGeoRange
253 rfX
= (rfX
- rGeoRange
.getMinX()) / fTargetWidth
;
254 rfY
= (rfY
- rGeoRange
.getMinY()) / fTargetHeight
;
258 const drawinglayer::primitive2d::Primitive2DContainer
& SvgPatternNode::getPatternPrimitives() const
260 if(aPrimitives
.empty() && Display::None
!= getDisplay())
262 decomposeSvgNode(const_cast< SvgPatternNode
* >(this)->aPrimitives
, true);
265 if(aPrimitives
.empty() && !maXLink
.isEmpty())
267 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
269 if (mpXLink
&& !mbResolvingLink
)
271 mbResolvingLink
= true;
272 const drawinglayer::primitive2d::Primitive2DContainer
& ret
= mpXLink
->getPatternPrimitives();
273 mbResolvingLink
= false;
281 basegfx::B2DRange
SvgPatternNode::getCurrentViewPort() const
285 return *(getViewBox());
289 return SvgNode::getCurrentViewPort();
293 const basegfx::B2DRange
* SvgPatternNode::getViewBox() const
297 return mpViewBox
.get();
300 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
302 if (mpXLink
&& !mbResolvingLink
)
304 mbResolvingLink
= true;
305 auto ret
= mpXLink
->getViewBox();
306 mbResolvingLink
= false;
313 const SvgAspectRatio
& SvgPatternNode::getSvgAspectRatio() const
315 if(maSvgAspectRatio
.isSet())
317 return maSvgAspectRatio
;
320 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
322 if (mpXLink
&& !mbResolvingLink
)
324 mbResolvingLink
= true;
325 const SvgAspectRatio
& ret
= mpXLink
->getSvgAspectRatio();
326 mbResolvingLink
= false;
330 return maSvgAspectRatio
;
333 const SvgNumber
& SvgPatternNode::getX() const
340 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
342 if (mpXLink
&& !mbResolvingLink
)
344 mbResolvingLink
= true;
345 const SvgNumber
& ret
= mpXLink
->getX();
346 mbResolvingLink
= false;
353 const SvgNumber
& SvgPatternNode::getY() const
360 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
362 if (mpXLink
&& !mbResolvingLink
)
364 mbResolvingLink
= true;
365 const SvgNumber
& ret
= mpXLink
->getY();
366 mbResolvingLink
= false;
373 const SvgNumber
& SvgPatternNode::getWidth() const
380 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
382 if (mpXLink
&& !mbResolvingLink
)
384 mbResolvingLink
= true;
385 const SvgNumber
& ret
= mpXLink
->getWidth();
386 mbResolvingLink
= false;
393 const SvgNumber
& SvgPatternNode::getHeight() const
400 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
402 if (mpXLink
&& !mbResolvingLink
)
404 mbResolvingLink
= true;
405 const SvgNumber
& ret
= mpXLink
->getHeight();
406 mbResolvingLink
= false;
413 const SvgUnits
* SvgPatternNode::getPatternUnits() const
417 return mpPatternUnits
.get();
420 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
422 if (mpXLink
&& !mbResolvingLink
)
424 mbResolvingLink
= true;
425 auto ret
= mpXLink
->getPatternUnits();
426 mbResolvingLink
= false;
433 const SvgUnits
* SvgPatternNode::getPatternContentUnits() const
435 if(mpPatternContentUnits
)
437 return mpPatternContentUnits
.get();
440 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
442 if (mpXLink
&& !mbResolvingLink
)
444 mbResolvingLink
= true;
445 auto ret
= mpXLink
->getPatternContentUnits();
446 mbResolvingLink
= false;
453 const basegfx::B2DHomMatrix
* SvgPatternNode::getPatternTransform() const
455 if(mpaPatternTransform
)
457 return mpaPatternTransform
.get();
460 const_cast< SvgPatternNode
* >(this)->tryToFindLink();
462 if (mpXLink
&& !mbResolvingLink
)
464 mbResolvingLink
= true;
465 auto ret
= mpXLink
->getPatternTransform();
466 mbResolvingLink
= false;
473 } // end of namespace svgio::svgreader
475 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */