1/*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5 * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
6 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "SVGPatternElement.h"
26
27#include "AffineTransform.h"
28#include "Document.h"
29#include "FloatConversion.h"
30#include "GraphicsContext.h"
31#include "ImageBuffer.h"
32#include "PatternAttributes.h"
33#include "RenderSVGContainer.h"
34#include "RenderSVGResourcePattern.h"
35#include "SVGFitToViewBox.h"
36#include "SVGGraphicsElement.h"
37#include "SVGNames.h"
38#include "SVGRenderSupport.h"
39#include "SVGStringList.h"
40#include "SVGTransformable.h"
41#include <wtf/IsoMallocInlines.h>
42#include <wtf/NeverDestroyed.h>
43
44namespace WebCore {
45
46WTF_MAKE_ISO_ALLOCATED_IMPL(SVGPatternElement);
47
48inline SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document& document)
49 : SVGElement(tagName, document)
50 , SVGExternalResourcesRequired(this)
51 , SVGFitToViewBox(this)
52 , SVGTests(this)
53 , SVGURIReference(this)
54{
55 ASSERT(hasTagName(SVGNames::patternTag));
56
57 static std::once_flag onceFlag;
58 std::call_once(onceFlag, [] {
59 PropertyRegistry::registerProperty<SVGNames::xAttr, &SVGPatternElement::m_x>();
60 PropertyRegistry::registerProperty<SVGNames::yAttr, &SVGPatternElement::m_y>();
61 PropertyRegistry::registerProperty<SVGNames::widthAttr, &SVGPatternElement::m_width>();
62 PropertyRegistry::registerProperty<SVGNames::heightAttr, &SVGPatternElement::m_height>();
63 PropertyRegistry::registerProperty<SVGNames::patternUnitsAttr, SVGUnitTypes::SVGUnitType, &SVGPatternElement::m_patternUnits>();
64 PropertyRegistry::registerProperty<SVGNames::patternContentUnitsAttr, SVGUnitTypes::SVGUnitType, &SVGPatternElement::m_patternContentUnits>();
65 PropertyRegistry::registerProperty<SVGNames::patternTransformAttr, &SVGPatternElement::m_patternTransform>();
66 });
67}
68
69Ref<SVGPatternElement> SVGPatternElement::create(const QualifiedName& tagName, Document& document)
70{
71 return adoptRef(*new SVGPatternElement(tagName, document));
72}
73
74void SVGPatternElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
75{
76 if (name == SVGNames::patternUnitsAttr) {
77 auto propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
78 if (propertyValue > 0)
79 m_patternUnits->setBaseValInternal<SVGUnitTypes::SVGUnitType>(propertyValue);
80 return;
81 }
82 if (name == SVGNames::patternContentUnitsAttr) {
83 auto propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
84 if (propertyValue > 0)
85 m_patternContentUnits->setBaseValInternal<SVGUnitTypes::SVGUnitType>(propertyValue);
86 return;
87 }
88 if (name == SVGNames::patternTransformAttr) {
89 m_patternTransform->baseVal()->parse(value);
90 return;
91 }
92
93 SVGParsingError parseError = NoError;
94
95 if (name == SVGNames::xAttr)
96 m_x->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError));
97 else if (name == SVGNames::yAttr)
98 m_y->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError));
99 else if (name == SVGNames::widthAttr)
100 m_width->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
101 else if (name == SVGNames::heightAttr)
102 m_height->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
103
104 reportAttributeParsingError(parseError, name, value);
105
106 SVGElement::parseAttribute(name, value);
107 SVGURIReference::parseAttribute(name, value);
108 SVGTests::parseAttribute(name, value);
109 SVGExternalResourcesRequired::parseAttribute(name, value);
110 SVGFitToViewBox::parseAttribute(name, value);
111}
112
113void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
114{
115 if (PropertyRegistry::isAnimatedLengthAttribute(attrName)) {
116 InstanceInvalidationGuard guard(*this);
117 invalidateSVGPresentationAttributeStyle();
118 return;
119 }
120
121 if (PropertyRegistry::isKnownAttribute(attrName) || SVGFitToViewBox::isKnownAttribute(attrName) || SVGURIReference::isKnownAttribute(attrName)) {
122 if (RenderObject* object = renderer())
123 object->setNeedsLayout();
124 return;
125 }
126
127 SVGElement::svgAttributeChanged(attrName);
128 SVGExternalResourcesRequired::svgAttributeChanged(attrName);
129}
130
131void SVGPatternElement::childrenChanged(const ChildChange& change)
132{
133 SVGElement::childrenChanged(change);
134
135 if (change.source == ChildChangeSource::Parser)
136 return;
137
138 if (RenderObject* object = renderer())
139 object->setNeedsLayout();
140}
141
142RenderPtr<RenderElement> SVGPatternElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
143{
144 return createRenderer<RenderSVGResourcePattern>(*this, WTFMove(style));
145}
146
147void SVGPatternElement::collectPatternAttributes(PatternAttributes& attributes) const
148{
149 if (!attributes.hasX() && hasAttribute(SVGNames::xAttr))
150 attributes.setX(x());
151
152 if (!attributes.hasY() && hasAttribute(SVGNames::yAttr))
153 attributes.setY(y());
154
155 if (!attributes.hasWidth() && hasAttribute(SVGNames::widthAttr))
156 attributes.setWidth(width());
157
158 if (!attributes.hasHeight() && hasAttribute(SVGNames::heightAttr))
159 attributes.setHeight(height());
160
161 if (!attributes.hasViewBox() && hasAttribute(SVGNames::viewBoxAttr) && hasValidViewBox())
162 attributes.setViewBox(viewBox());
163
164 if (!attributes.hasPreserveAspectRatio() && hasAttribute(SVGNames::preserveAspectRatioAttr))
165 attributes.setPreserveAspectRatio(preserveAspectRatio());
166
167 if (!attributes.hasPatternUnits() && hasAttribute(SVGNames::patternUnitsAttr))
168 attributes.setPatternUnits(patternUnits());
169
170 if (!attributes.hasPatternContentUnits() && hasAttribute(SVGNames::patternContentUnitsAttr))
171 attributes.setPatternContentUnits(patternContentUnits());
172
173 if (!attributes.hasPatternTransform() && hasAttribute(SVGNames::patternTransformAttr))
174 attributes.setPatternTransform(patternTransform().concatenate());
175
176 if (!attributes.hasPatternContentElement() && childElementCount())
177 attributes.setPatternContentElement(this);
178}
179
180AffineTransform SVGPatternElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
181{
182 return patternTransform().concatenate();
183}
184
185}
186