| 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 | |