LibreOffice Module svgio (master) 1
svgmasknode.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 <svgmasknode.hxx>
29#include <o3tl/string_view.hxx>
30
31namespace svgio::svgreader
32{
34 SvgDocument& rDocument,
35 SvgNode* pParent)
36 : SvgNode(SVGToken::Mask, rDocument, pParent),
37 maSvgStyleAttributes(*this),
38 maX(SvgNumber(-10.0, SvgUnit::percent, true)),
39 maY(SvgNumber(-10.0, SvgUnit::percent, true)),
40 maWidth(SvgNumber(120.0, SvgUnit::percent, true)),
41 maHeight(SvgNumber(120.0, SvgUnit::percent, true)),
42 maMaskUnits(SvgUnits::objectBoundingBox),
43 maMaskContentUnits(SvgUnits::userSpaceOnUse)
44 {
45 }
46
48 {
49 }
50
52 {
54 }
55
56 void SvgMaskNode::parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent)
57 {
58 // call parent
59 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
60
61 // read style attributes
62 maSvgStyleAttributes.parseStyleAttribute(aSVGToken, aContent);
63
64 // parse own
65 switch(aSVGToken)
66 {
67 case SVGToken::Style:
68 {
69 readLocalCssStyle(aContent);
70 break;
71 }
72 case SVGToken::X:
73 {
74 SvgNumber aNum;
75
76 if(readSingleNumber(aContent, aNum))
77 {
78 maX = aNum;
79 }
80 break;
81 }
82 case SVGToken::Y:
83 {
84 SvgNumber aNum;
85
86 if(readSingleNumber(aContent, aNum))
87 {
88 maY = aNum;
89 }
90 break;
91 }
92 case SVGToken::Width:
93 {
94 SvgNumber aNum;
95
96 if(readSingleNumber(aContent, aNum))
97 {
98 if(aNum.isPositive())
99 {
100 maWidth = aNum;
101 }
102 }
103 break;
104 }
105 case SVGToken::Height:
106 {
107 SvgNumber aNum;
108
109 if(readSingleNumber(aContent, aNum))
110 {
111 if(aNum.isPositive())
112 {
113 maHeight = aNum;
114 }
115 }
116 break;
117 }
119 {
120 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
121
122 if(!aMatrix.isIdentity())
123 {
124 setTransform(aMatrix);
125 }
126 break;
127 }
129 {
130 if(!aContent.isEmpty())
131 {
133 {
135 }
137 {
139 }
140 }
141 break;
142 }
144 {
145 if(!aContent.isEmpty())
146 {
148 {
150 }
152 {
154 }
155 }
156 break;
157 }
158 default:
159 {
160 break;
161 }
162 }
163 }
164
166 {
168
169 // decompose children
170 SvgNode::decomposeSvgNode(aNewTarget, bReferenced);
171
172 if(aNewTarget.empty())
173 return;
174
175 if(getTransform())
176 {
177 // create embedding group element with transformation
180 *getTransform(),
181 std::move(aNewTarget)));
182
184 }
185
186 // append to current target
187 rTarget.append(aNewTarget);
188 }
189
192 const std::optional<basegfx::B2DHomMatrix>& pTransform) const
193 {
194 if(rTarget.empty() || Display::None == getDisplay())
195 return;
196
198
199 // get mask definition as primitives
200 decomposeSvgNode(aMaskTarget, true);
201
202 if(!aMaskTarget.empty())
203 {
204 // get range of content to be masked
205 const basegfx::B2DRange aContentRange(
206 rTarget.getB2DRange(
208 const double fContentWidth(aContentRange.getWidth());
209 const double fContentHeight(aContentRange.getHeight());
210
211 if(fContentWidth > 0.0 && fContentHeight > 0.0)
212 {
213 // create OffscreenBufferRange
214 basegfx::B2DRange aOffscreenBufferRange;
215
217 {
218 // fractions or percentages of the bounding box of the element to which the mask is applied
219 const double fX(SvgUnit::percent == getX().getUnit() ? getX().getNumber() * 0.01 : getX().getNumber());
220 const double fY(SvgUnit::percent == getY().getUnit() ? getY().getNumber() * 0.01 : getY().getNumber());
221 const double fW(SvgUnit::percent == getWidth().getUnit() ? getWidth().getNumber() * 0.01 : getWidth().getNumber());
222 const double fH(SvgUnit::percent == getHeight().getUnit() ? getHeight().getNumber() * 0.01 : getHeight().getNumber());
223
224 aOffscreenBufferRange = basegfx::B2DRange(
225 aContentRange.getMinX() + (fX * fContentWidth),
226 aContentRange.getMinY() + (fY * fContentHeight),
227 aContentRange.getMinX() + ((fX + fW) * fContentWidth),
228 aContentRange.getMinY() + ((fY + fH) * fContentHeight));
229 }
230 else
231 {
232 const double fX(getX().isSet() ? getX().solve(*this, NumberType::xcoordinate) : 0.0);
233 const double fY(getY().isSet() ? getY().solve(*this, NumberType::ycoordinate) : 0.0);
234
235 aOffscreenBufferRange = basegfx::B2DRange(
236 fX,
237 fY,
238 fX + (getWidth().isSet() ? getWidth().solve(*this, NumberType::xcoordinate) : 0.0),
239 fY + (getHeight().isSet() ? getHeight().solve(*this, NumberType::ycoordinate) : 0.0));
240 }
241
243 {
244 // mask is object-relative, embed in content transformation
248 aContentRange.getRange(),
249 aContentRange.getMinimum()),
250 std::move(aMaskTarget)));
251
252 aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xTransform };
253 }
254 else // userSpaceOnUse
255 {
256 // #i124852#
257 if(pTransform)
258 {
261 *pTransform,
262 std::move(aMaskTarget)));
263
264 aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xTransform };
265 }
266 }
267
268 // embed content to a ModifiedColorPrimitive2D since the definitions
269 // how content is used as alpha is special for Svg
270 {
273 std::move(aMaskTarget),
274 std::make_shared<basegfx::BColorModifier_luminance_to_alpha>()));
275
276 aMaskTarget = drawinglayer::primitive2d::Primitive2DContainer { xInverseMask };
277 }
278
279 // prepare new content
282 std::move(rTarget),
283 std::move(aMaskTarget)));
284
285 // output up to now is defined by aContentRange and mask is oriented
286 // relative to it. It is possible that aOffscreenBufferRange defines
287 // a smaller area. In that case, embed to a mask primitive
288 if(!aOffscreenBufferRange.isInside(aContentRange))
289 {
293 aOffscreenBufferRange)),
295 }
296
297 // redefine target. Use TransparencePrimitive2D with created mask
298 // geometry
300 }
301 else
302 {
303 // content is geometrically empty
304 rTarget.clear();
305 }
306 }
307 else
308 {
309 // An empty clipping path will completely clip away the element that had
310 // the clip-path property applied. (Svg spec)
311 rTarget.clear();
312 }
313 }
314
315} // end of namespace svgio::svgreader
316
317/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool isIdentity() const
B2DVector getRange() const
B2DPoint getMinimum() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
bool isInside(const Tuple2D< TYPE > &rTuple) const
TYPE getHeight() const
SvgMaskNode(SvgDocument &rDocument, SvgNode *pParent)
Definition: svgmasknode.cxx:33
void setMaskContentUnits(const SvgUnits aMaskContentUnits)
MaskContentUnits content.
Definition: svgmasknode.hxx:79
virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer &rTarget, bool bReferenced) const override
void apply(drawinglayer::primitive2d::Primitive2DContainer &rTarget, const std::optional< basegfx::B2DHomMatrix > &pTransform) const
apply contained clipPath to given geometry #i124852# transform may be needed
const std::optional< basegfx::B2DHomMatrix > & getTransform() const
transform content
Definition: svgmasknode.hxx:72
const SvgNumber & getHeight() const
height content, set if found in current context
Definition: svgmasknode.hxx:69
void setMaskUnits(const SvgUnits aMaskUnits)
MaskUnits content.
Definition: svgmasknode.hxx:76
virtual ~SvgMaskNode() override
Definition: svgmasknode.cxx:47
SvgNumber maX
variable scan values, dependent of given XAttributeList
Definition: svgmasknode.hxx:35
const SvgNumber & getY() const
y content, set if found in current context
Definition: svgmasknode.hxx:63
void setTransform(const std::optional< basegfx::B2DHomMatrix > &pMatrix)
Definition: svgmasknode.hxx:73
SvgStyleAttributes maSvgStyleAttributes
use styles
Definition: svgmasknode.hxx:32
virtual const SvgStyleAttributes * getSvgStyleAttributes() const override
Definition: svgmasknode.cxx:51
const SvgNumber & getX() const
x content, set if found in current context
Definition: svgmasknode.hxx:60
virtual void parseAttribute(const OUString &rTokenName, SVGToken aSVGToken, const OUString &aContent) override
Definition: svgmasknode.cxx:56
const SvgNumber & getWidth() const
width content, set if found in current context
Definition: svgmasknode.hxx:66
Display getDisplay() const
Display access #i121656#.
Definition: svgnode.hxx:182
virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer &rTarget, bool bReferenced) const
Definition: svgnode.cxx:584
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
void parseStyleAttribute(SVGToken aSVGToken, const OUString &rContent)
local attribute scanner
FilterGroup & rTarget
bool solve(Matrix &matrix, int rows, int cols, Vector &result, BaseType minPivot)
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
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 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