1 | /* |
2 | * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2009-2019 Apple Inc. All rights reserved. |
5 | * Copyright (C) 2013 Samsung Electronics. All rights reserved. |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Library General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Library General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Library General Public License |
18 | * along with this library; see the file COPYING.LIB. If not, write to |
19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | * Boston, MA 02110-1301, USA. |
21 | */ |
22 | |
23 | #pragma once |
24 | |
25 | #include "SVGAnimatedPropertyImpl.h" |
26 | #include "SVGLangSpace.h" |
27 | #include "SVGLocatable.h" |
28 | #include "SVGNames.h" |
29 | #include "SVGParsingError.h" |
30 | #include "SVGPropertyOwnerRegistry.h" |
31 | #include "StyledElement.h" |
32 | #include <wtf/HashMap.h> |
33 | #include <wtf/HashSet.h> |
34 | #include <wtf/WeakPtr.h> |
35 | |
36 | namespace WebCore { |
37 | |
38 | class AffineTransform; |
39 | class CSSStyleDeclaration; |
40 | class DeprecatedCSSOMValue; |
41 | class Document; |
42 | class SVGDocumentExtensions; |
43 | class SVGElementRareData; |
44 | class SVGPropertyAnimatorFactory; |
45 | class SVGSVGElement; |
46 | class SVGUseElement; |
47 | |
48 | void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName); |
49 | |
50 | class SVGElement : public StyledElement, public SVGLangSpace, public SVGPropertyOwner { |
51 | WTF_MAKE_ISO_ALLOCATED(SVGElement); |
52 | public: |
53 | bool isOutermostSVGSVGElement() const; |
54 | |
55 | SVGSVGElement* ownerSVGElement() const; |
56 | SVGElement* viewportElement() const; |
57 | |
58 | String title() const override; |
59 | RefPtr<DeprecatedCSSOMValue> getPresentationAttribute(const String& name); |
60 | virtual bool supportsMarkers() const { return false; } |
61 | bool hasRelativeLengths() const { return !m_elementsWithRelativeLengths.isEmpty(); } |
62 | virtual bool needsPendingResourceHandling() const { return true; } |
63 | bool instanceUpdatesBlocked() const; |
64 | void setInstanceUpdatesBlocked(bool); |
65 | virtual AffineTransform localCoordinateSpaceTransform(SVGLocatable::CTMScope) const; |
66 | |
67 | virtual bool isSVGGraphicsElement() const { return false; } |
68 | virtual bool isSVGGeometryElement() const { return false; } |
69 | virtual bool isFilterEffect() const { return false; } |
70 | virtual bool isGradientStop() const { return false; } |
71 | virtual bool isTextContent() const { return false; } |
72 | virtual bool isSMILElement() const { return false; } |
73 | |
74 | // For SVGTests |
75 | virtual bool isValid() const { return true; } |
76 | |
77 | virtual void svgAttributeChanged(const QualifiedName&); |
78 | |
79 | void sendSVGLoadEventIfPossible(bool sendParentLoadEvents = false); |
80 | void sendSVGLoadEventIfPossibleAsynchronously(); |
81 | void svgLoadEventTimerFired(); |
82 | virtual Timer* svgLoadEventTimer(); |
83 | |
84 | virtual AffineTransform* supplementalTransform() { return nullptr; } |
85 | |
86 | void invalidateSVGAttributes() { ensureUniqueElementData().setAnimatedSVGAttributesAreDirty(true); } |
87 | void invalidateSVGPresentationAttributeStyle() |
88 | { |
89 | ensureUniqueElementData().setPresentationAttributeStyleIsDirty(true); |
90 | // Trigger style recalculation for "elements as resource" (e.g. referenced by feImage). |
91 | invalidateStyle(); |
92 | } |
93 | |
94 | // The instances of an element are clones made in shadow trees to implement <use>. |
95 | const HashSet<SVGElement*>& instances() const; |
96 | |
97 | bool getBoundingBox(FloatRect&, SVGLocatable::StyleUpdateStrategy = SVGLocatable::AllowStyleUpdate); |
98 | |
99 | SVGElement* correspondingElement() const; |
100 | RefPtr<SVGUseElement> correspondingUseElement() const; |
101 | |
102 | void setCorrespondingElement(SVGElement*); |
103 | |
104 | Optional<ElementStyle> resolveCustomStyle(const RenderStyle& parentStyle, const RenderStyle* shadowHostStyle) override; |
105 | |
106 | static QualifiedName animatableAttributeForName(const AtomicString&); |
107 | #ifndef NDEBUG |
108 | bool isAnimatableAttribute(const QualifiedName&) const; |
109 | #endif |
110 | |
111 | MutableStyleProperties* animatedSMILStyleProperties() const; |
112 | MutableStyleProperties& ensureAnimatedSMILStyleProperties(); |
113 | void setUseOverrideComputedStyle(bool); |
114 | |
115 | virtual bool haveLoadedRequiredResources(); |
116 | |
117 | bool addEventListener(const AtomicString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override; |
118 | bool removeEventListener(const AtomicString& eventType, EventListener&, const ListenerOptions&) override; |
119 | bool hasFocusEventListeners() const; |
120 | |
121 | bool hasTagName(const SVGQualifiedName& name) const { return hasLocalName(name.localName()); } |
122 | int tabIndex() const override; |
123 | |
124 | void callClearTarget() { clearTarget(); } |
125 | |
126 | class InstanceUpdateBlocker; |
127 | class InstanceInvalidationGuard; |
128 | |
129 | using PropertyRegistry = SVGPropertyOwnerRegistry<SVGElement>; |
130 | virtual const SVGPropertyRegistry& propertyRegistry() const { return m_propertyRegistry; } |
131 | void detachAllProperties() { propertyRegistry().detachAllProperties(); } |
132 | |
133 | bool isAnimatedPropertyAttribute(const QualifiedName&) const; |
134 | bool isAnimatedAttribute(const QualifiedName&) const; |
135 | bool isAnimatedStyleAttribute(const QualifiedName&) const; |
136 | |
137 | void synchronizeAttribute(const QualifiedName&); |
138 | void synchronizeAllAttributes(); |
139 | static void synchronizeAllAnimatedSVGAttribute(SVGElement&); |
140 | |
141 | void commitPropertyChange(SVGProperty*) override; |
142 | void commitPropertyChange(SVGAnimatedProperty&); |
143 | |
144 | const SVGElement* attributeContextElement() const override { return this; } |
145 | SVGPropertyAnimatorFactory& propertyAnimatorFactory() { return *m_propertyAnimatorFactory; } |
146 | std::unique_ptr<SVGAttributeAnimator> createAnimator(const QualifiedName&, AnimationMode, CalcMode, bool isAccumulated, bool isAdditive); |
147 | void animatorWillBeDeleted(const QualifiedName&); |
148 | |
149 | // These are needed for the RenderTree, animation and DOM. |
150 | String className() const { return m_className->currentValue(); } |
151 | SVGAnimatedString& classNameAnimated() { return m_className; } |
152 | |
153 | protected: |
154 | SVGElement(const QualifiedName&, Document&); |
155 | virtual ~SVGElement(); |
156 | |
157 | bool isMouseFocusable() const override; |
158 | bool supportsFocus() const override { return false; } |
159 | |
160 | bool rendererIsNeeded(const RenderStyle&) override; |
161 | void parseAttribute(const QualifiedName&, const AtomicString&) override; |
162 | |
163 | void finishParsingChildren() override; |
164 | void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason = ModifiedDirectly) override; |
165 | bool childShouldCreateRenderer(const Node&) const override; |
166 | |
167 | SVGElementRareData& ensureSVGRareData(); |
168 | |
169 | void reportAttributeParsingError(SVGParsingError, const QualifiedName&, const AtomicString&); |
170 | static CSSPropertyID cssPropertyIdForSVGAttributeName(const QualifiedName&); |
171 | |
172 | bool isPresentationAttribute(const QualifiedName&) const override; |
173 | void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) override; |
174 | InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override; |
175 | void removedFromAncestor(RemovalType, ContainerNode&) override; |
176 | void childrenChanged(const ChildChange&) override; |
177 | virtual bool selfHasRelativeLengths() const { return false; } |
178 | void updateRelativeLengthsInformation() { updateRelativeLengthsInformation(selfHasRelativeLengths(), this); } |
179 | void updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement*); |
180 | |
181 | void willRecalcStyle(Style::Change) override; |
182 | |
183 | private: |
184 | const RenderStyle* computedStyle(PseudoId = PseudoId::None) final; |
185 | |
186 | virtual void clearTarget() { } |
187 | |
188 | void buildPendingResourcesIfNeeded(); |
189 | void accessKeyAction(bool sendMouseEvents) override; |
190 | |
191 | #ifndef NDEBUG |
192 | virtual bool filterOutAnimatableAttribute(const QualifiedName&) const; |
193 | #endif |
194 | |
195 | void invalidateInstances(); |
196 | |
197 | std::unique_ptr<SVGElementRareData> m_svgRareData; |
198 | |
199 | HashSet<SVGElement*> m_elementsWithRelativeLengths; |
200 | |
201 | std::unique_ptr<SVGPropertyAnimatorFactory> m_propertyAnimatorFactory; |
202 | |
203 | PropertyRegistry m_propertyRegistry { *this }; |
204 | Ref<SVGAnimatedString> m_className { SVGAnimatedString::create(this) }; |
205 | }; |
206 | |
207 | class SVGElement::InstanceInvalidationGuard { |
208 | public: |
209 | InstanceInvalidationGuard(SVGElement&); |
210 | ~InstanceInvalidationGuard(); |
211 | private: |
212 | SVGElement& m_element; |
213 | }; |
214 | |
215 | class SVGElement::InstanceUpdateBlocker { |
216 | public: |
217 | InstanceUpdateBlocker(SVGElement&); |
218 | ~InstanceUpdateBlocker(); |
219 | private: |
220 | SVGElement& m_element; |
221 | }; |
222 | |
223 | struct SVGAttributeHashTranslator { |
224 | static unsigned hash(const QualifiedName& key) |
225 | { |
226 | if (key.hasPrefix()) { |
227 | QualifiedNameComponents components = { nullAtom().impl(), key.localName().impl(), key.namespaceURI().impl() }; |
228 | return hashComponents(components); |
229 | } |
230 | return DefaultHash<QualifiedName>::Hash::hash(key); |
231 | } |
232 | static bool equal(const QualifiedName& a, const QualifiedName& b) { return a.matches(b); } |
233 | }; |
234 | |
235 | inline SVGElement::InstanceInvalidationGuard::InstanceInvalidationGuard(SVGElement& element) |
236 | : m_element(element) |
237 | { |
238 | } |
239 | |
240 | inline SVGElement::InstanceInvalidationGuard::~InstanceInvalidationGuard() |
241 | { |
242 | m_element.invalidateInstances(); |
243 | } |
244 | |
245 | inline SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement& element) |
246 | : m_element(element) |
247 | { |
248 | m_element.setInstanceUpdatesBlocked(true); |
249 | } |
250 | |
251 | inline SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker() |
252 | { |
253 | m_element.setInstanceUpdatesBlocked(false); |
254 | } |
255 | |
256 | inline bool Node::hasTagName(const SVGQualifiedName& name) const |
257 | { |
258 | return isSVGElement() && downcast<SVGElement>(*this).hasTagName(name); |
259 | } |
260 | |
261 | } // namespace WebCore |
262 | |
263 | SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::SVGElement) |
264 | static bool isType(const WebCore::Node& node) { return node.isSVGElement(); } |
265 | SPECIALIZE_TYPE_TRAITS_END() |
266 | |
267 | #include "SVGElementTypeHelpers.h" |
268 | |