summaryrefslogtreecommitdiff
path: root/Source/WebCore/svg/SVGElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/svg/SVGElement.cpp')
-rw-r--r--Source/WebCore/svg/SVGElement.cpp829
1 files changed, 410 insertions, 419 deletions
diff --git a/Source/WebCore/svg/SVGElement.cpp b/Source/WebCore/svg/SVGElement.cpp
index bdb7ea1fc..49195090c 100644
--- a/Source/WebCore/svg/SVGElement.cpp
+++ b/Source/WebCore/svg/SVGElement.cpp
@@ -1,10 +1,11 @@
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
* Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -23,27 +24,22 @@
*/
#include "config.h"
-
-#if ENABLE(SVG)
#include "SVGElement.h"
-#include "Attr.h"
-#include "CSSCursorImageValue.h"
-#include "CSSParser.h"
-#include "DOMImplementation.h"
+#include "CSSPropertyParser.h"
+#include "DeprecatedCSSOMValue.h"
#include "Document.h"
#include "ElementIterator.h"
#include "Event.h"
#include "EventNames.h"
+#include "HTMLElement.h"
#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
#include "RenderObject.h"
#include "RenderSVGResource.h"
-#include "RenderSVGResourceClipper.h"
#include "RenderSVGResourceFilter.h"
#include "RenderSVGResourceMasker.h"
-#include "SVGCursorElement.h"
#include "SVGDocumentExtensions.h"
-#include "SVGElementInstance.h"
#include "SVGElementRareData.h"
#include "SVGGraphicsElement.h"
#include "SVGImageElement.h"
@@ -72,11 +68,11 @@ BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGElement)
REGISTER_LOCAL_ANIMATED_PROPERTY(className)
END_REGISTER_ANIMATED_PROPERTIES
-using namespace HTMLNames;
-using namespace SVGNames;
-
static NEVER_INLINE void populateAttributeNameToCSSPropertyIDMap(HashMap<AtomicStringImpl*, CSSPropertyID>& map)
{
+ using namespace HTMLNames;
+ using namespace SVGNames;
+
// This list should include all base CSS and SVG CSS properties which are exposed as SVG XML attributes.
static const QualifiedName* const attributeNames[] = {
&alignment_baselineAttr,
@@ -91,6 +87,8 @@ static NEVER_INLINE void populateAttributeNameToCSSPropertyIDMap(HashMap<AtomicS
&color_profileAttr,
&color_renderingAttr,
&cursorAttr,
+ &cxAttr,
+ &cyAttr,
&SVGNames::directionAttr,
&displayAttr,
&dominant_baselineAttr,
@@ -110,6 +108,7 @@ static NEVER_INLINE void populateAttributeNameToCSSPropertyIDMap(HashMap<AtomicS
&glyph_orientation_horizontalAttr,
&glyph_orientation_verticalAttr,
&image_renderingAttr,
+ &SVGNames::heightAttr,
&kerningAttr,
&letter_spacingAttr,
&lighting_colorAttr,
@@ -120,7 +119,11 @@ static NEVER_INLINE void populateAttributeNameToCSSPropertyIDMap(HashMap<AtomicS
&mask_typeAttr,
&opacityAttr,
&overflowAttr,
+ &paint_orderAttr,
&pointer_eventsAttr,
+ &rAttr,
+ &rxAttr,
+ &ryAttr,
&shape_renderingAttr,
&stop_colorAttr,
&stop_opacityAttr,
@@ -138,22 +141,28 @@ static NEVER_INLINE void populateAttributeNameToCSSPropertyIDMap(HashMap<AtomicS
&unicode_bidiAttr,
&vector_effectAttr,
&visibilityAttr,
+ &SVGNames::widthAttr,
&word_spacingAttr,
&writing_modeAttr,
+ &xAttr,
+ &yAttr,
};
- for (unsigned i = 0; i < WTF_ARRAY_LENGTH(attributeNames); ++i) {
- const AtomicString& localName = attributeNames[i]->localName();
+ for (auto& name : attributeNames) {
+ const AtomicString& localName = name->localName();
map.add(localName.impl(), cssPropertyID(localName));
}
// FIXME: When CSS supports "transform-origin" this special case can be removed,
// and we can add transform_originAttr to the table above instead.
- map.add(transform_originAttr.localName().impl(), CSSPropertyWebkitTransformOrigin);
+ map.add(transform_originAttr.localName().impl(), CSSPropertyTransformOrigin);
}
static NEVER_INLINE void populateAttributeNameToAnimatedPropertyTypeMap(HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& map)
{
+ using namespace HTMLNames;
+ using namespace SVGNames;
+
struct TableEntry {
const QualifiedName& attributeName;
AnimatedPropertyType type;
@@ -197,6 +206,7 @@ static NEVER_INLINE void populateAttributeNameToAnimatedPropertyTypeMap(HashMap<
{ mask_typeAttr, AnimatedString },
{ opacityAttr, AnimatedNumber },
{ overflowAttr, AnimatedString },
+ { paint_orderAttr, AnimatedString },
{ pointer_eventsAttr, AnimatedString },
{ shape_renderingAttr, AnimatedString },
{ stop_colorAttr, AnimatedColor },
@@ -217,8 +227,8 @@ static NEVER_INLINE void populateAttributeNameToAnimatedPropertyTypeMap(HashMap<
{ word_spacingAttr, AnimatedLength },
};
- for (unsigned i = 0; i < WTF_ARRAY_LENGTH(table); ++i)
- map.add(table[i].attributeName.impl(), table[i].type);
+ for (auto& entry : table)
+ map.add(entry.attributeName.impl(), entry.type);
}
static inline HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& attributeNameToAnimatedPropertyTypeMap()
@@ -229,6 +239,40 @@ static inline HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>&
return map;
}
+static NEVER_INLINE void populateCSSPropertyWithSVGDOMNameToAnimatedPropertyTypeMap(HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& map)
+{
+ using namespace HTMLNames;
+ using namespace SVGNames;
+
+ struct TableEntry {
+ const QualifiedName& attributeName;
+ AnimatedPropertyType type;
+ };
+
+ static const TableEntry table[] = {
+ { cxAttr, AnimatedLength },
+ { cyAttr, AnimatedLength },
+ { rAttr, AnimatedLength },
+ { rxAttr, AnimatedLength },
+ { ryAttr, AnimatedLength },
+ { SVGNames::heightAttr, AnimatedLength },
+ { SVGNames::widthAttr, AnimatedLength },
+ { xAttr, AnimatedLength },
+ { yAttr, AnimatedLength },
+ };
+
+ for (auto& entry : table)
+ map.add(entry.attributeName.impl(), entry.type);
+}
+
+static inline HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap()
+{
+ static NeverDestroyed<HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>> map;
+ if (map.get().isEmpty())
+ populateCSSPropertyWithSVGDOMNameToAnimatedPropertyTypeMap(map);
+ return map;
+}
+
SVGElement::SVGElement(const QualifiedName& tagName, Document& document)
: StyledElement(tagName, document, CreateSVGElement)
{
@@ -238,27 +282,32 @@ SVGElement::SVGElement(const QualifiedName& tagName, Document& document)
SVGElement::~SVGElement()
{
if (m_svgRareData) {
- m_svgRareData->destroyAnimatedSMILStyleProperties();
- if (SVGCursorElement* cursorElement = m_svgRareData->cursorElement())
- cursorElement->removeClient(this);
- if (CSSCursorImageValue* cursorImageValue = m_svgRareData->cursorImageValue())
- cursorImageValue->removeReferencedElement(this);
+ for (SVGElement* instance : m_svgRareData->instances())
+ instance->m_svgRareData->setCorrespondingElement(nullptr);
+ if (SVGElement* correspondingElement = m_svgRareData->correspondingElement())
+ correspondingElement->m_svgRareData->instances().remove(this);
m_svgRareData = nullptr;
}
- document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
- document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
+ document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
+ document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
}
-bool SVGElement::willRecalcStyle(Style::Change change)
+int SVGElement::tabIndex() const
{
- if (!m_svgRareData || styleChangeType() == SyntheticStyleChange)
- return true;
+ if (supportsFocus())
+ return Element::tabIndex();
+ return -1;
+}
+
+void SVGElement::willRecalcStyle(Style::Change change)
+{
+ if (!m_svgRareData || styleResolutionShouldRecompositeLayer())
+ return;
// If the style changes because of a regular property change (not induced by SMIL animations themselves)
// reset the "computed style without SMIL style properties", so the base value change gets reflected.
if (change > Style::NoChange || needsStyleRecalc())
m_svgRareData->setNeedsOverrideComputedStyleUpdate();
- return true;
}
SVGElementRareData& SVGElement::ensureSVGRareData()
@@ -270,7 +319,7 @@ SVGElementRareData& SVGElement::ensureSVGRareData()
bool SVGElement::isOutermostSVGSVGElement() const
{
- if (!isSVGSVGElement(this))
+ if (!is<SVGSVGElement>(*this))
return false;
// If we're living in a shadow tree, we're a <svg> element that got created as replacement
@@ -297,233 +346,161 @@ void SVGElement::reportAttributeParsingError(SVGParsingError error, const Qualif
return;
String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
- SVGDocumentExtensions* extensions = document().accessSVGExtensions();
+ SVGDocumentExtensions& extensions = document().accessSVGExtensions();
if (error == NegativeValueForbiddenError) {
- extensions->reportError("Invalid negative value for " + errorString);
+ extensions.reportError("Invalid negative value for " + errorString);
return;
}
if (error == ParsingAttributeFailedError) {
- extensions->reportError("Invalid value for " + errorString);
+ extensions.reportError("Invalid value for " + errorString);
return;
}
ASSERT_NOT_REACHED();
}
-
-bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
-{
- return DOMImplementation::hasFeature(feature, version);
-}
-
-String SVGElement::xmlbase() const
-{
- return fastGetAttribute(XMLNames::baseAttr);
-}
-
-void SVGElement::setXmlbase(const String& value, ExceptionCode&)
-{
- setAttribute(XMLNames::baseAttr, value);
-}
-
void SVGElement::removedFrom(ContainerNode& rootParent)
{
- bool wasInDocument = rootParent.inDocument();
+ bool wasInDocument = rootParent.isConnected();
if (wasInDocument)
updateRelativeLengthsInformation(false, this);
StyledElement::removedFrom(rootParent);
if (wasInDocument) {
- document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
- document().accessSVGExtensions()->removeAllElementReferencesForTarget(this);
+ document().accessSVGExtensions().clearTargetDependencies(*this);
+ document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
}
- SVGElementInstance::invalidateAllInstancesOfElement(this);
+ invalidateInstances();
}
SVGSVGElement* SVGElement::ownerSVGElement() const
{
- ContainerNode* n = parentOrShadowHostNode();
- while (n) {
- if (n->hasTagName(SVGNames::svgTag))
- return toSVGSVGElement(n);
+ ContainerNode* node = parentOrShadowHostNode();
+ while (node) {
+ if (is<SVGSVGElement>(*node))
+ return downcast<SVGSVGElement>(node);
- n = n->parentOrShadowHostNode();
+ node = node->parentOrShadowHostNode();
}
- return 0;
+ return nullptr;
}
SVGElement* SVGElement::viewportElement() const
{
// This function needs shadow tree support - as RenderSVGContainer uses this function
// to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
- ContainerNode* n = parentOrShadowHostNode();
- while (n) {
- if (n->hasTagName(SVGNames::svgTag) || isSVGImageElement(n) || n->hasTagName(SVGNames::symbolTag))
- return toSVGElement(n);
+ ContainerNode* node = parentOrShadowHostNode();
+ while (node) {
+ if (is<SVGSVGElement>(*node) || is<SVGImageElement>(*node) || node->hasTagName(SVGNames::symbolTag))
+ return downcast<SVGElement>(node);
- n = n->parentOrShadowHostNode();
+ node = node->parentOrShadowHostNode();
}
- return 0;
-}
-
-SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
-{
- // This function is provided for use by SVGAnimatedProperty to avoid
- // global inclusion of Document.h in SVG code.
- return document().accessSVGExtensions();
-}
-
-void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
-{
- ASSERT(instance);
-
- HashSet<SVGElementInstance*>& instances = ensureSVGRareData().elementInstances();
- ASSERT(!instances.contains(instance));
-
- instances.add(instance);
+ return nullptr;
}
-void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
-{
- ASSERT(instance);
- ASSERT(m_svgRareData);
-
- HashSet<SVGElementInstance*>& instances = m_svgRareData->elementInstances();
- ASSERT(instances.contains(instance));
-
- instances.remove(instance);
-}
-
-const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
+const HashSet<SVGElement*>& SVGElement::instances() const
{
if (!m_svgRareData) {
- DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
+ static NeverDestroyed<HashSet<SVGElement*>> emptyInstances;
return emptyInstances;
}
- return m_svgRareData->elementInstances();
+ return m_svgRareData->instances();
}
bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
{
- if (isSVGGraphicsElement()) {
- rect = toSVGGraphicsElement(this)->getBBox(styleUpdateStrategy);
+ if (is<SVGGraphicsElement>(*this)) {
+ rect = downcast<SVGGraphicsElement>(*this).getBBox(styleUpdateStrategy);
return true;
}
return false;
}
-void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
+SVGElement* SVGElement::correspondingElement() const
{
- SVGElementRareData& rareData = ensureSVGRareData();
- if (SVGCursorElement* oldCursorElement = rareData.cursorElement()) {
- if (cursorElement == oldCursorElement)
- return;
- oldCursorElement->removeReferencedElement(this);
- }
- rareData.setCursorElement(cursorElement);
+ return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr;
}
-void SVGElement::cursorElementRemoved()
+SVGUseElement* SVGElement::correspondingUseElement() const
{
- ASSERT(m_svgRareData);
- m_svgRareData->setCursorElement(0);
+ auto* root = containingShadowRoot();
+ if (!root)
+ return nullptr;
+ if (root->mode() != ShadowRootMode::UserAgent)
+ return nullptr;
+ auto* host = root->host();
+ if (!is<SVGUseElement>(host))
+ return nullptr;
+ return &downcast<SVGUseElement>(*host);
}
-void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
+void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
{
- SVGElementRareData& rareData = ensureSVGRareData();
- if (CSSCursorImageValue* oldCursorImageValue = rareData.cursorImageValue()) {
- if (cursorImageValue == oldCursorImageValue)
- return;
- oldCursorImageValue->removeReferencedElement(this);
+ if (m_svgRareData) {
+ if (SVGElement* oldCorrespondingElement = m_svgRareData->correspondingElement())
+ oldCorrespondingElement->m_svgRareData->instances().remove(this);
}
- rareData.setCursorImageValue(cursorImageValue);
+ if (m_svgRareData || correspondingElement)
+ ensureSVGRareData().setCorrespondingElement(correspondingElement);
+ if (correspondingElement)
+ correspondingElement->ensureSVGRareData().instances().add(this);
}
-void SVGElement::cursorImageValueRemoved()
+void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- ASSERT(m_svgRareData);
- m_svgRareData->setCursorImageValue(0);
-}
+ if (name == HTMLNames::classAttr) {
+ setClassNameBaseValue(value);
+ return;
+ }
-SVGElement* SVGElement::correspondingElement()
-{
- ASSERT(!m_svgRareData || !m_svgRareData->correspondingElement() || containingShadowRoot());
- return m_svgRareData ? m_svgRareData->correspondingElement() : 0;
-}
+ if (name == HTMLNames::tabindexAttr) {
+ if (value.isEmpty())
+ clearTabIndexExplicitlyIfNeeded();
+ else if (std::optional<int> tabIndex = parseHTMLInteger(value))
+ setTabIndexExplicitly(tabIndex.value());
+ return;
+ }
-void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
-{
- ensureSVGRareData().setCorrespondingElement(correspondingElement);
-}
+ auto& eventName = HTMLElement::eventNameForEventHandlerAttribute(name);
+ if (!eventName.isNull()) {
+ setAttributeEventListener(eventName, name, value);
+ return;
+ }
-void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
-{
- // standard events
- if (name == onloadAttr)
- setAttributeEventListener(eventNames().loadEvent, name, value);
- else if (name == onclickAttr)
- setAttributeEventListener(eventNames().clickEvent, name, value);
- else if (name == onmousedownAttr)
- setAttributeEventListener(eventNames().mousedownEvent, name, value);
- else if (name == onmouseenterAttr)
- setAttributeEventListener(eventNames().mouseenterEvent, name, value);
- else if (name == onmouseleaveAttr)
- setAttributeEventListener(eventNames().mouseleaveEvent, name, value);
- else if (name == onmousemoveAttr)
- setAttributeEventListener(eventNames().mousemoveEvent, name, value);
- else if (name == onmouseoutAttr)
- setAttributeEventListener(eventNames().mouseoutEvent, name, value);
- else if (name == onmouseoverAttr)
- setAttributeEventListener(eventNames().mouseoverEvent, name, value);
- else if (name == onmouseupAttr)
- setAttributeEventListener(eventNames().mouseupEvent, name, value);
- else if (name == SVGNames::onfocusinAttr)
- setAttributeEventListener(eventNames().focusinEvent, name, value);
- else if (name == SVGNames::onfocusoutAttr)
- setAttributeEventListener(eventNames().focusoutEvent, name, value);
- else if (name == SVGNames::onactivateAttr)
- setAttributeEventListener(eventNames().DOMActivateEvent, name, value);
- else if (name == HTMLNames::classAttr)
- setClassNameBaseValue(value);
-#if ENABLE(TOUCH_EVENTS)
- else if (name == ontouchstartAttr)
- setAttributeEventListener(eventNames().touchstartEvent, name, value);
- else if (name == ontouchmoveAttr)
- setAttributeEventListener(eventNames().touchmoveEvent, name, value);
- else if (name == ontouchendAttr)
- setAttributeEventListener(eventNames().touchendEvent, name, value);
- else if (name == ontouchcancelAttr)
- setAttributeEventListener(eventNames().touchcancelEvent, name, value);
-#endif
-#if ENABLE(IOS_GESTURE_EVENTS)
- else if (name == ongesturestartAttr)
- setAttributeEventListener(eventNames().gesturestartEvent, name, value);
- else if (name == ongesturechangeAttr)
- setAttributeEventListener(eventNames().gesturechangeEvent, name, value);
- else if (name == ongestureendAttr)
- setAttributeEventListener(eventNames().gestureendEvent, name, value);
-#endif
- else if (SVGLangSpace::parseAttribute(name, value)) {
- } else
- StyledElement::parseAttribute(name, value);
+ SVGLangSpace::parseAttribute(name, value);
}
-void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
+Vector<AnimatedPropertyType> SVGElement::animatedPropertyTypesForAttribute(const QualifiedName& attributeName)
{
- localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
- if (!propertyTypes.isEmpty())
- return;
+ auto types = localAttributeToPropertyMap().types(attributeName);
+ if (!types.isEmpty())
+ return types;
+
+ {
+ auto& map = attributeNameToAnimatedPropertyTypeMap();
+ auto it = map.find(attributeName.impl());
+ if (it != map.end()) {
+ types.append(it->value);
+ return types;
+ }
+ }
+
+ {
+ auto& map = cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap();
+ auto it = map.find(attributeName.impl());
+ if (it != map.end()) {
+ types.append(it->value);
+ return types;
+ }
+ }
- auto& map = attributeNameToAnimatedPropertyTypeMap();
- auto it = map.find(attributeName.impl());
- if (it != map.end())
- propertyTypes.append(it->value);
+ return types;
}
bool SVGElement::haveLoadedRequiredResources()
@@ -535,82 +512,61 @@ bool SVGElement::haveLoadedRequiredResources()
return true;
}
-static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances)
-{
- ASSERT(element);
- if (element->containingShadowRoot())
- return;
-
- ASSERT(!element->instanceUpdatesBlocked());
-
- instances = element->instancesForElement();
-}
-
-bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
-{
- RefPtr<EventListener> listener = prpListener;
-
+bool SVGElement::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
+{
// Add event listener to regular DOM element
- if (!Node::addEventListener(eventType, listener, useCapture))
+ if (!Node::addEventListener(eventType, listener.copyRef(), options))
return false;
+ if (containingShadowRoot())
+ return true;
+
// Add event listener to all shadow tree DOM element instances
- HashSet<SVGElementInstance*> instances;
- collectInstancesForSVGElement(this, instances);
- const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
- for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
- ASSERT((*it)->shadowTreeElement());
- ASSERT((*it)->correspondingElement() == this);
-
- bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture);
+ ASSERT(!instanceUpdatesBlocked());
+ for (auto* instance : instances()) {
+ ASSERT(instance->correspondingElement() == this);
+ bool result = instance->Node::addEventListener(eventType, listener.copyRef(), options);
ASSERT_UNUSED(result, result);
}
return true;
}
-bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener& listener, const ListenerOptions& options)
{
- HashSet<SVGElementInstance*> instances;
- collectInstancesForSVGElement(this, instances);
- if (instances.isEmpty())
- return Node::removeEventListener(eventType, listener, useCapture);
+ if (containingShadowRoot())
+ return Node::removeEventListener(eventType, listener, options);
- // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
+ // EventTarget::removeEventListener creates a Ref around the given EventListener
// object when creating a temporary RegisteredEventListener object used to look up the
// event listener in a cache. If we want to be able to call removeEventListener() multiple
// times on different nodes, we have to delay its immediate destruction, which would happen
// after the first call below.
- RefPtr<EventListener> protector(listener);
+ Ref<EventListener> protector(listener);
// Remove event listener from regular DOM element
- if (!Node::removeEventListener(eventType, listener, useCapture))
+ if (!Node::removeEventListener(eventType, listener, options))
return false;
// Remove event listener from all shadow tree DOM element instances
- const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
- for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
- ASSERT((*it)->correspondingElement() == this);
-
- SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
- ASSERT(shadowTreeElement);
+ ASSERT(!instanceUpdatesBlocked());
+ for (auto& instance : instances()) {
+ ASSERT(instance->correspondingElement() == this);
- if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture))
+ if (instance->Node::removeEventListener(eventType, listener, options))
continue;
// This case can only be hit for event listeners created from markup
- ASSERT(listener->wasCreatedFromMarkup());
+ ASSERT(listener.wasCreatedFromMarkup());
// If the event listener 'listener' has been created from markup and has been fired before
// then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
// has been created (read: it's not 0 anymore). During shadow tree creation, the event
// listener DOM attribute has been cloned, and another event listener has been setup in
// the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
- // and tryRemoveEventListener() above will fail. Work around that very seldom problem.
- EventTargetData* data = shadowTreeElement->eventTargetData();
- ASSERT(data);
-
- data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
+ // and tryRemoveEventListener() above will fail. Work around that very rare problem.
+ ASSERT(instance->eventTargetData());
+ instance->eventTargetData()->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
}
return true;
@@ -622,11 +578,8 @@ static bool hasLoadListener(Element* element)
return true;
for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
- const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent);
- for (size_t i = 0; i < entry.size(); ++i) {
- if (entry[i].useCapture)
- return true;
- }
+ if (element->hasCapturingEventListeners(eventNames().loadEvent))
+ return true;
}
return false;
@@ -642,6 +595,9 @@ bool SVGElement::shouldMoveToFlowThread(const RenderStyle& styleToUse) const
void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
{
+ if (!isConnected() || !document().frame())
+ return;
+
RefPtr<SVGElement> currentTarget = this;
while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
RefPtr<Element> parent;
@@ -672,12 +628,12 @@ void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
svgLoadEventTimer()->startOneShot(0);
}
-void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
+void SVGElement::svgLoadEventTimerFired()
{
sendSVGLoadEventIfPossible();
}
-Timer<SVGElement>* SVGElement::svgLoadEventTimer()
+Timer* SVGElement::svgLoadEventTimer()
{
ASSERT_NOT_REACHED();
return 0;
@@ -694,23 +650,27 @@ void SVGElement::finishParsingChildren()
// finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
// we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
sendSVGLoadEventIfPossible();
+
+ // Notify all the elements which have references to this element to rebuild their shadow and render
+ // trees, e.g. a <use> element references a target element before this target element is defined.
+ invalidateInstances();
}
bool SVGElement::childShouldCreateRenderer(const Node& child) const
{
- DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ());
+ static NeverDestroyed<HashSet<QualifiedName>> invalidTextContent;
- if (invalidTextContent.isEmpty()) {
- invalidTextContent.add(SVGNames::textPathTag);
+ if (invalidTextContent.get().isEmpty()) {
+ invalidTextContent.get().add(SVGNames::textPathTag);
#if ENABLE(SVG_FONTS)
- invalidTextContent.add(SVGNames::altGlyphTag);
+ invalidTextContent.get().add(SVGNames::altGlyphTag);
#endif
- invalidTextContent.add(SVGNames::trefTag);
- invalidTextContent.add(SVGNames::tspanTag);
+ invalidTextContent.get().add(SVGNames::trefTag);
+ invalidTextContent.get().add(SVGNames::tspanTag);
}
if (child.isSVGElement()) {
- const SVGElement& svgChild = toSVGElement(child);
- if (invalidTextContent.contains(svgChild.tagQName()))
+ const SVGElement& svgChild = downcast<SVGElement>(child);
+ if (invalidTextContent.get().contains(svgChild.tagQName()))
return false;
return svgChild.isValid();
@@ -722,8 +682,8 @@ void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString&
{
StyledElement::attributeChanged(name, oldValue, newValue);
- if (isIdAttributeName(name))
- document().accessSVGExtensions()->rebuildAllElementReferencesForTarget(this);
+ if (name == HTMLNames::idAttr)
+ document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
// Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
// so we don't want changes to the style attribute to result in extra work here.
@@ -731,17 +691,25 @@ void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString&
svgAttributeChanged(name);
}
+void SVGElement::synchronizeAllAnimatedSVGAttribute(SVGElement* svgElement)
+{
+ ASSERT(svgElement->elementData());
+ ASSERT(svgElement->elementData()->animatedSVGAttributesAreDirty());
+
+ svgElement->localAttributeToPropertyMap().synchronizeProperties(*svgElement);
+ svgElement->elementData()->setAnimatedSVGAttributesAreDirty(false);
+}
+
void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
{
if (!elementData() || !elementData()->animatedSVGAttributesAreDirty())
return;
SVGElement* nonConstThis = const_cast<SVGElement*>(this);
- if (name == anyQName()) {
- nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
- elementData()->setAnimatedSVGAttributesAreDirty(false);
- } else
- nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
+ if (name == anyQName())
+ synchronizeAllAnimatedSVGAttribute(nonConstThis);
+ else
+ nonConstThis->localAttributeToPropertyMap().synchronizeProperty(*nonConstThis, name);
}
void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement)
@@ -762,18 +730,13 @@ void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
contextElement->synchronizeSystemLanguage();
}
-PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
+std::optional<ElementStyle> SVGElement::resolveCustomStyle(const RenderStyle& parentStyle, const RenderStyle*)
{
- if (!correspondingElement())
- return document().ensureStyleResolver().styleForElement(this);
-
- RenderStyle* style = 0;
- if (Element* parent = parentOrShadowHostElement()) {
- if (auto renderer = parent->renderer())
- style = &renderer->style();
- }
+ // If the element is in a <use> tree we get the style from the definition tree.
+ if (auto* styleElement = this->correspondingElement())
+ return styleElement->resolveStyle(&parentStyle);
- return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
+ return resolveStyle(&parentStyle);
}
MutableStyleProperties* SVGElement::animatedSMILStyleProperties() const
@@ -794,155 +757,152 @@ void SVGElement::setUseOverrideComputedStyle(bool value)
m_svgRareData->setUseOverrideComputedStyle(value);
}
-RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
+const RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
{
if (!m_svgRareData || !m_svgRareData->useOverrideComputedStyle())
return Element::computedStyle(pseudoElementSpecifier);
- RenderStyle* parentStyle = nullptr;
+ const RenderStyle* parentStyle = nullptr;
if (Element* parent = parentOrShadowHostElement()) {
if (auto renderer = parent->renderer())
parentStyle = &renderer->style();
}
- return m_svgRareData->overrideComputedStyle(this, parentStyle);
+ return m_svgRareData->overrideComputedStyle(*this, parentStyle);
}
-#ifndef NDEBUG
-bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
+static void addQualifiedName(HashMap<AtomicString, QualifiedName>& map, const QualifiedName& name)
{
- DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
+ HashMap<AtomicString, QualifiedName>::AddResult addResult = map.add(name.localName(), name);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+}
+
+QualifiedName SVGElement::animatableAttributeForName(const AtomicString& localName)
+{
+ static NeverDestroyed<HashMap<AtomicString, QualifiedName>> neverDestroyedAnimatableAttributes;
+ HashMap<AtomicString, QualifiedName>& animatableAttributes = neverDestroyedAnimatableAttributes;
if (animatableAttributes.isEmpty()) {
- animatableAttributes.add(XLinkNames::hrefAttr);
- animatableAttributes.add(SVGNames::amplitudeAttr);
- animatableAttributes.add(SVGNames::azimuthAttr);
- animatableAttributes.add(SVGNames::baseFrequencyAttr);
- animatableAttributes.add(SVGNames::biasAttr);
- animatableAttributes.add(SVGNames::clipPathUnitsAttr);
- animatableAttributes.add(SVGNames::cxAttr);
- animatableAttributes.add(SVGNames::cyAttr);
- animatableAttributes.add(SVGNames::diffuseConstantAttr);
- animatableAttributes.add(SVGNames::divisorAttr);
- animatableAttributes.add(SVGNames::dxAttr);
- animatableAttributes.add(SVGNames::dyAttr);
- animatableAttributes.add(SVGNames::edgeModeAttr);
- animatableAttributes.add(SVGNames::elevationAttr);
- animatableAttributes.add(SVGNames::exponentAttr);
- animatableAttributes.add(SVGNames::externalResourcesRequiredAttr);
- animatableAttributes.add(SVGNames::filterResAttr);
- animatableAttributes.add(SVGNames::filterUnitsAttr);
- animatableAttributes.add(SVGNames::fxAttr);
- animatableAttributes.add(SVGNames::fyAttr);
- animatableAttributes.add(SVGNames::gradientTransformAttr);
- animatableAttributes.add(SVGNames::gradientUnitsAttr);
- animatableAttributes.add(SVGNames::heightAttr);
- animatableAttributes.add(SVGNames::in2Attr);
- animatableAttributes.add(SVGNames::inAttr);
- animatableAttributes.add(SVGNames::interceptAttr);
- animatableAttributes.add(SVGNames::k1Attr);
- animatableAttributes.add(SVGNames::k2Attr);
- animatableAttributes.add(SVGNames::k3Attr);
- animatableAttributes.add(SVGNames::k4Attr);
- animatableAttributes.add(SVGNames::kernelMatrixAttr);
- animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
- animatableAttributes.add(SVGNames::lengthAdjustAttr);
- animatableAttributes.add(SVGNames::limitingConeAngleAttr);
- animatableAttributes.add(SVGNames::markerHeightAttr);
- animatableAttributes.add(SVGNames::markerUnitsAttr);
- animatableAttributes.add(SVGNames::markerWidthAttr);
- animatableAttributes.add(SVGNames::maskContentUnitsAttr);
- animatableAttributes.add(SVGNames::maskUnitsAttr);
- animatableAttributes.add(SVGNames::methodAttr);
- animatableAttributes.add(SVGNames::modeAttr);
- animatableAttributes.add(SVGNames::numOctavesAttr);
- animatableAttributes.add(SVGNames::offsetAttr);
- animatableAttributes.add(SVGNames::operatorAttr);
- animatableAttributes.add(SVGNames::orderAttr);
- animatableAttributes.add(SVGNames::orientAttr);
- animatableAttributes.add(SVGNames::pathLengthAttr);
- animatableAttributes.add(SVGNames::patternContentUnitsAttr);
- animatableAttributes.add(SVGNames::patternTransformAttr);
- animatableAttributes.add(SVGNames::patternUnitsAttr);
- animatableAttributes.add(SVGNames::pointsAtXAttr);
- animatableAttributes.add(SVGNames::pointsAtYAttr);
- animatableAttributes.add(SVGNames::pointsAtZAttr);
- animatableAttributes.add(SVGNames::preserveAlphaAttr);
- animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
- animatableAttributes.add(SVGNames::primitiveUnitsAttr);
- animatableAttributes.add(SVGNames::radiusAttr);
- animatableAttributes.add(SVGNames::rAttr);
- animatableAttributes.add(SVGNames::refXAttr);
- animatableAttributes.add(SVGNames::refYAttr);
- animatableAttributes.add(SVGNames::resultAttr);
- animatableAttributes.add(SVGNames::rotateAttr);
- animatableAttributes.add(SVGNames::rxAttr);
- animatableAttributes.add(SVGNames::ryAttr);
- animatableAttributes.add(SVGNames::scaleAttr);
- animatableAttributes.add(SVGNames::seedAttr);
- animatableAttributes.add(SVGNames::slopeAttr);
- animatableAttributes.add(SVGNames::spacingAttr);
- animatableAttributes.add(SVGNames::specularConstantAttr);
- animatableAttributes.add(SVGNames::specularExponentAttr);
- animatableAttributes.add(SVGNames::spreadMethodAttr);
- animatableAttributes.add(SVGNames::startOffsetAttr);
- animatableAttributes.add(SVGNames::stdDeviationAttr);
- animatableAttributes.add(SVGNames::stitchTilesAttr);
- animatableAttributes.add(SVGNames::surfaceScaleAttr);
- animatableAttributes.add(SVGNames::tableValuesAttr);
- animatableAttributes.add(SVGNames::targetAttr);
- animatableAttributes.add(SVGNames::targetXAttr);
- animatableAttributes.add(SVGNames::targetYAttr);
- animatableAttributes.add(SVGNames::transformAttr);
- animatableAttributes.add(SVGNames::typeAttr);
- animatableAttributes.add(SVGNames::valuesAttr);
- animatableAttributes.add(SVGNames::viewBoxAttr);
- animatableAttributes.add(SVGNames::widthAttr);
- animatableAttributes.add(SVGNames::x1Attr);
- animatableAttributes.add(SVGNames::x2Attr);
- animatableAttributes.add(SVGNames::xAttr);
- animatableAttributes.add(SVGNames::xChannelSelectorAttr);
- animatableAttributes.add(SVGNames::y1Attr);
- animatableAttributes.add(SVGNames::y2Attr);
- animatableAttributes.add(SVGNames::yAttr);
- animatableAttributes.add(SVGNames::yChannelSelectorAttr);
- animatableAttributes.add(SVGNames::zAttr);
+ addQualifiedName(animatableAttributes, HTMLNames::classAttr);
+ addQualifiedName(animatableAttributes, SVGNames::amplitudeAttr);
+ addQualifiedName(animatableAttributes, SVGNames::azimuthAttr);
+ addQualifiedName(animatableAttributes, SVGNames::baseFrequencyAttr);
+ addQualifiedName(animatableAttributes, SVGNames::biasAttr);
+ addQualifiedName(animatableAttributes, SVGNames::clipPathUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::cxAttr);
+ addQualifiedName(animatableAttributes, SVGNames::cyAttr);
+ addQualifiedName(animatableAttributes, SVGNames::diffuseConstantAttr);
+ addQualifiedName(animatableAttributes, SVGNames::divisorAttr);
+ addQualifiedName(animatableAttributes, SVGNames::dxAttr);
+ addQualifiedName(animatableAttributes, SVGNames::dyAttr);
+ addQualifiedName(animatableAttributes, SVGNames::edgeModeAttr);
+ addQualifiedName(animatableAttributes, SVGNames::elevationAttr);
+ addQualifiedName(animatableAttributes, SVGNames::exponentAttr);
+ addQualifiedName(animatableAttributes, SVGNames::externalResourcesRequiredAttr);
+ addQualifiedName(animatableAttributes, SVGNames::filterResAttr);
+ addQualifiedName(animatableAttributes, SVGNames::filterUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::fxAttr);
+ addQualifiedName(animatableAttributes, SVGNames::fyAttr);
+ addQualifiedName(animatableAttributes, SVGNames::gradientTransformAttr);
+ addQualifiedName(animatableAttributes, SVGNames::gradientUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::heightAttr);
+ addQualifiedName(animatableAttributes, SVGNames::in2Attr);
+ addQualifiedName(animatableAttributes, SVGNames::inAttr);
+ addQualifiedName(animatableAttributes, SVGNames::interceptAttr);
+ addQualifiedName(animatableAttributes, SVGNames::k1Attr);
+ addQualifiedName(animatableAttributes, SVGNames::k2Attr);
+ addQualifiedName(animatableAttributes, SVGNames::k3Attr);
+ addQualifiedName(animatableAttributes, SVGNames::k4Attr);
+ addQualifiedName(animatableAttributes, SVGNames::kernelMatrixAttr);
+ addQualifiedName(animatableAttributes, SVGNames::kernelUnitLengthAttr);
+ addQualifiedName(animatableAttributes, SVGNames::lengthAdjustAttr);
+ addQualifiedName(animatableAttributes, SVGNames::limitingConeAngleAttr);
+ addQualifiedName(animatableAttributes, SVGNames::markerHeightAttr);
+ addQualifiedName(animatableAttributes, SVGNames::markerUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::markerWidthAttr);
+ addQualifiedName(animatableAttributes, SVGNames::maskContentUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::maskUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::methodAttr);
+ addQualifiedName(animatableAttributes, SVGNames::modeAttr);
+ addQualifiedName(animatableAttributes, SVGNames::numOctavesAttr);
+ addQualifiedName(animatableAttributes, SVGNames::offsetAttr);
+ addQualifiedName(animatableAttributes, SVGNames::operatorAttr);
+ addQualifiedName(animatableAttributes, SVGNames::orderAttr);
+ addQualifiedName(animatableAttributes, SVGNames::orientAttr);
+ addQualifiedName(animatableAttributes, SVGNames::pathLengthAttr);
+ addQualifiedName(animatableAttributes, SVGNames::patternContentUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::patternTransformAttr);
+ addQualifiedName(animatableAttributes, SVGNames::patternUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::pointsAtXAttr);
+ addQualifiedName(animatableAttributes, SVGNames::pointsAtYAttr);
+ addQualifiedName(animatableAttributes, SVGNames::pointsAtZAttr);
+ addQualifiedName(animatableAttributes, SVGNames::preserveAlphaAttr);
+ addQualifiedName(animatableAttributes, SVGNames::preserveAspectRatioAttr);
+ addQualifiedName(animatableAttributes, SVGNames::primitiveUnitsAttr);
+ addQualifiedName(animatableAttributes, SVGNames::radiusAttr);
+ addQualifiedName(animatableAttributes, SVGNames::rAttr);
+ addQualifiedName(animatableAttributes, SVGNames::refXAttr);
+ addQualifiedName(animatableAttributes, SVGNames::refYAttr);
+ addQualifiedName(animatableAttributes, SVGNames::resultAttr);
+ addQualifiedName(animatableAttributes, SVGNames::rotateAttr);
+ addQualifiedName(animatableAttributes, SVGNames::rxAttr);
+ addQualifiedName(animatableAttributes, SVGNames::ryAttr);
+ addQualifiedName(animatableAttributes, SVGNames::scaleAttr);
+ addQualifiedName(animatableAttributes, SVGNames::seedAttr);
+ addQualifiedName(animatableAttributes, SVGNames::slopeAttr);
+ addQualifiedName(animatableAttributes, SVGNames::spacingAttr);
+ addQualifiedName(animatableAttributes, SVGNames::specularConstantAttr);
+ addQualifiedName(animatableAttributes, SVGNames::specularExponentAttr);
+ addQualifiedName(animatableAttributes, SVGNames::spreadMethodAttr);
+ addQualifiedName(animatableAttributes, SVGNames::startOffsetAttr);
+ addQualifiedName(animatableAttributes, SVGNames::stdDeviationAttr);
+ addQualifiedName(animatableAttributes, SVGNames::stitchTilesAttr);
+ addQualifiedName(animatableAttributes, SVGNames::surfaceScaleAttr);
+ addQualifiedName(animatableAttributes, SVGNames::tableValuesAttr);
+ addQualifiedName(animatableAttributes, SVGNames::targetAttr);
+ addQualifiedName(animatableAttributes, SVGNames::targetXAttr);
+ addQualifiedName(animatableAttributes, SVGNames::targetYAttr);
+ addQualifiedName(animatableAttributes, SVGNames::transformAttr);
+ addQualifiedName(animatableAttributes, SVGNames::typeAttr);
+ addQualifiedName(animatableAttributes, SVGNames::valuesAttr);
+ addQualifiedName(animatableAttributes, SVGNames::viewBoxAttr);
+ addQualifiedName(animatableAttributes, SVGNames::widthAttr);
+ addQualifiedName(animatableAttributes, SVGNames::x1Attr);
+ addQualifiedName(animatableAttributes, SVGNames::x2Attr);
+ addQualifiedName(animatableAttributes, SVGNames::xAttr);
+ addQualifiedName(animatableAttributes, SVGNames::xChannelSelectorAttr);
+ addQualifiedName(animatableAttributes, SVGNames::y1Attr);
+ addQualifiedName(animatableAttributes, SVGNames::y2Attr);
+ addQualifiedName(animatableAttributes, SVGNames::yAttr);
+ addQualifiedName(animatableAttributes, SVGNames::yChannelSelectorAttr);
+ addQualifiedName(animatableAttributes, SVGNames::zAttr);
+ addQualifiedName(animatableAttributes, XLinkNames::hrefAttr);
}
+ return animatableAttributes.get(localName);
+}
- if (name == classAttr)
- return true;
+#ifndef NDEBUG
+bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
+{
+ if (SVGElement::animatableAttributeForName(name.localName()) == name)
+ return !filterOutAnimatableAttribute(name);
+ return false;
+}
- return animatableAttributes.contains(name);
+bool SVGElement::filterOutAnimatableAttribute(const QualifiedName&) const
+{
+ return false;
}
#endif
String SVGElement::title() const
{
- // According to spec, we should not return titles when hovering over root <svg> elements (those
- // <title> elements are the title of the document, not a tooltip) so we instantly return.
- if (isOutermostSVGSVGElement())
+ // According to spec, for stand-alone SVG documents we should not return a title when
+ // hovering over the rootmost SVG element (the first <title> element is the title of
+ // the document, not a tooltip) so we instantly return.
+ if (isOutermostSVGSVGElement() && document().topDocument().isSVGDocument())
return String();
-
- // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
- if (isInShadowTree()) {
- Element* shadowHostElement = toShadowRoot(treeScope().rootNode())->hostElement();
- // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do
- // have should be a use. The assert and following test is here to catch future shadow DOM changes
- // that do enable SVG in a shadow tree.
- ASSERT(!shadowHostElement || shadowHostElement->hasTagName(SVGNames::useTag));
- if (shadowHostElement && shadowHostElement->hasTagName(SVGNames::useTag)) {
- SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
-
- // If the <use> title is not empty we found the title to use.
- String useTitle(useElement->title());
- if (!useTitle.isEmpty())
- return useTitle;
- }
- }
-
- // If we aren't an instance in a <use> or the <use> title was not found, then find the first
- // <title> child of this element.
- auto firstTitle = descendantsOfType<SVGTitleElement>(*this).first();
+ auto firstTitle = childrenOfType<SVGTitleElement>(*this).first();
return firstTitle ? const_cast<SVGTitleElement*>(firstTitle)->innerText() : String();
}
@@ -973,7 +933,13 @@ CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName&
bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attributeName)
{
- return attributeNameToAnimatedPropertyTypeMap().contains(attributeName.impl());
+ return attributeNameToAnimatedPropertyTypeMap().contains(attributeName.impl())
+ || cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap().contains(attributeName.impl());
+}
+
+bool SVGElement::isPresentationAttributeWithSVGDOM(const QualifiedName& attributeName)
+{
+ return !localAttributeToPropertyMap().types(attributeName).isEmpty();
}
bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
@@ -992,31 +958,31 @@ void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name,
bool SVGElement::isKnownAttribute(const QualifiedName& attrName)
{
- return isIdAttributeName(attrName);
+ return attrName == HTMLNames::idAttr;
}
void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
{
CSSPropertyID propId = cssPropertyIdForSVGAttributeName(attrName);
if (propId > 0) {
- SVGElementInstance::invalidateAllInstancesOfElement(this);
+ invalidateInstances();
return;
}
if (attrName == HTMLNames::classAttr) {
classAttributeChanged(className());
- SVGElementInstance::invalidateAllInstancesOfElement(this);
+ invalidateInstances();
return;
}
- if (isIdAttributeName(attrName)) {
- RenderObject* object = renderer();
+ if (attrName == HTMLNames::idAttr) {
+ auto renderer = this->renderer();
// Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
- if (object && object->isSVGResourceContainer())
- object->toRenderSVGResourceContainer()->idChanged();
- if (inDocument())
+ if (is<RenderSVGResourceContainer>(renderer))
+ downcast<RenderSVGResourceContainer>(*renderer).idChanged();
+ if (isConnected())
buildPendingResourcesIfNeeded();
- SVGElementInstance::invalidateAllInstancesOfElement(this);
+ invalidateInstances();
return;
}
}
@@ -1031,23 +997,23 @@ Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode& rootP
void SVGElement::buildPendingResourcesIfNeeded()
{
- if (!needsPendingResourceHandling() || !inDocument() || isInShadowTree())
+ if (!needsPendingResourceHandling() || !isConnected() || isInShadowTree())
return;
- SVGDocumentExtensions* extensions = document().accessSVGExtensions();
+ SVGDocumentExtensions& extensions = document().accessSVGExtensions();
String resourceId = getIdAttribute();
- if (!extensions->isIdOfPendingResource(resourceId))
+ if (!extensions.isIdOfPendingResource(resourceId))
return;
// Mark pending resources as pending for removal.
- extensions->markPendingResourcesForRemoval(resourceId);
+ extensions.markPendingResourcesForRemoval(resourceId);
// Rebuild pending resources for each client of a pending resource that is being removed.
- while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemovalMap(resourceId)) {
+ while (Element* clientElement = extensions.removeElementFromPendingResourcesForRemovalMap(resourceId)) {
ASSERT(clientElement->hasPendingResources());
if (clientElement->hasPendingResources()) {
clientElement->buildPendingResource();
- extensions->clearHasPendingResourcesIfPossible(clientElement);
+ extensions.clearHasPendingResourcesIfPossible(clientElement);
}
}
}
@@ -1058,10 +1024,10 @@ void SVGElement::childrenChanged(const ChildChange& change)
if (change.source == ChildChangeSourceParser)
return;
- SVGElementInstance::invalidateAllInstancesOfElement(this);
+ invalidateInstances();
}
-PassRefPtr<CSSValue> SVGElement::getPresentationAttribute(const String& name)
+RefPtr<DeprecatedCSSOMValue> SVGElement::getPresentationAttribute(const String& name)
{
if (!hasAttributesWithoutUpdate())
return 0;
@@ -1074,8 +1040,10 @@ PassRefPtr<CSSValue> SVGElement::getPresentationAttribute(const String& name)
RefPtr<MutableStyleProperties> style = MutableStyleProperties::create(SVGAttributeMode);
CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(attribute->name());
style->setProperty(propertyID, attribute->value());
- RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(propertyID);
- return cssValue ? cssValue->cloneForCSSOM() : 0;
+ auto cssValue = style->getPropertyCSSValue(propertyID);
+ if (!cssValue)
+ return nullptr;
+ return cssValue->createDeprecatedCSSOMWrapper();
}
bool SVGElement::instanceUpdatesBlocked() const
@@ -1085,6 +1053,10 @@ bool SVGElement::instanceUpdatesBlocked() const
void SVGElement::setInstanceUpdatesBlocked(bool value)
{
+ // Catch any callers that calls setInstanceUpdatesBlocked(true) twice in a row.
+ // That probably indicates nested use of InstanceUpdateBlocker and a bug.
+ ASSERT(!value || !instanceUpdatesBlocked());
+
if (m_svgRareData)
m_svgRareData->setInstanceUpdatesBlocked(value);
}
@@ -1098,7 +1070,7 @@ AffineTransform SVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope
void SVGElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement* element)
{
// If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
- if (!inDocument())
+ if (!isConnected())
return;
// An element wants to notify us that its own relative lengths state changed.
@@ -1126,22 +1098,29 @@ void SVGElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGEl
break;
// Register us in the parent element map.
- toSVGElement(node)->updateRelativeLengthsInformation(hasRelativeLengths, this);
+ downcast<SVGElement>(*node).updateRelativeLengthsInformation(hasRelativeLengths, this);
break;
}
}
-bool SVGElement::isMouseFocusable() const
+bool SVGElement::hasFocusEventListeners() const
{
- if (!isFocusable())
- return false;
Element* eventTarget = const_cast<SVGElement*>(this);
- return eventTarget->hasEventListeners(eventNames().focusinEvent) || eventTarget->hasEventListeners(eventNames().focusoutEvent);
+ return eventTarget->hasEventListeners(eventNames().focusinEvent)
+ || eventTarget->hasEventListeners(eventNames().focusoutEvent)
+ || eventTarget->hasEventListeners(eventNames().focusEvent)
+ || eventTarget->hasEventListeners(eventNames().blurEvent);
}
-bool SVGElement::isKeyboardFocusable(KeyboardEvent*) const
+bool SVGElement::isMouseFocusable() const
{
- return isMouseFocusable();
+ if (!isFocusable())
+ return false;
+ Element* eventTarget = const_cast<SVGElement*>(this);
+ return hasFocusEventListeners()
+ || eventTarget->hasEventListeners(eventNames().keydownEvent)
+ || eventTarget->hasEventListeners(eventNames().keyupEvent)
+ || eventTarget->hasEventListeners(eventNames().keypressEvent);
}
void SVGElement::accessKeyAction(bool sendMouseEvents)
@@ -1149,6 +1128,18 @@ void SVGElement::accessKeyAction(bool sendMouseEvents)
dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
}
+void SVGElement::invalidateInstances()
+{
+ if (instanceUpdatesBlocked())
+ return;
+
+ auto& instances = this->instances();
+ while (!instances.isEmpty()) {
+ SVGElement* instance = *instances.begin();
+ if (SVGUseElement* useElement = instance->correspondingUseElement())
+ useElement->invalidateShadowTree();
+ instance->setCorrespondingElement(nullptr);
+ } while (!instances.isEmpty());
}
-#endif // ENABLE(SVG)
+}