Index: Source/core/svg/SVGElement.cpp |
diff --git a/Source/core/svg/SVGElement.cpp b/Source/core/svg/SVGElement.cpp |
index 70cb07169cb099e0eb4c731836af9e19ad070e85..0d811ffd597e6402f0cfeb8256840aa13174b65b 100644 |
--- a/Source/core/svg/SVGElement.cpp |
+++ b/Source/core/svg/SVGElement.cpp |
@@ -31,26 +31,50 @@ |
#include "XMLNames.h" |
#include "bindings/v8/ScriptEventListener.h" |
#include "core/css/CSSCursorImageValue.h" |
+#include "core/css/CSSParser.h" |
#include "core/dom/DOMImplementation.h" |
#include "core/dom/Document.h" |
#include "core/dom/Event.h" |
#include "core/dom/NodeRenderingContext.h" |
+#include "core/dom/NodeTraversal.h" |
+#include "core/dom/shadow/ShadowRoot.h" |
#include "core/rendering/RenderObject.h" |
+#include "core/rendering/svg/RenderSVGResourceContainer.h" |
#include "core/svg/SVGCursorElement.h" |
#include "core/svg/SVGDocumentExtensions.h" |
#include "core/svg/SVGElementInstance.h" |
#include "core/svg/SVGElementRareData.h" |
#include "core/svg/SVGGraphicsElement.h" |
#include "core/svg/SVGSVGElement.h" |
+#include "core/svg/SVGUseElement.h" |
namespace WebCore { |
+// Animated property definitions |
+DEFINE_ANIMATED_STRING(SVGElement, HTMLNames::classAttr, ClassName, className) |
+ |
+BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGElement) |
+ REGISTER_LOCAL_ANIMATED_PROPERTY(className) |
+END_REGISTER_ANIMATED_PROPERTIES |
+ |
using namespace HTMLNames; |
+using namespace SVGNames; |
+ |
+void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName) |
+{ |
+ // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed. |
+ CSSPropertyID propertyId = cssPropertyID(attrName.localName()); |
+ if (!propertyId && attrName == transform_originAttr) |
+ propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin") |
+ ASSERT(propertyId > 0); |
+ propertyNameToIdMap->set(attrName.localName().impl(), propertyId); |
+} |
SVGElement::SVGElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType) |
: Element(tagName, document, constructionType) |
{ |
ScriptWrappable::init(this); |
+ registerAnimatedPropertiesForSVGElement(); |
setHasCustomStyleCallbacks(); |
} |
@@ -82,6 +106,10 @@ SVGElement::~SVGElement() |
// modifying the rare data map. Do not rely on the existing iterator. |
ASSERT(rareDataMap.contains(this)); |
rareDataMap.remove(this); |
+ // Clear HasSVGRareData flag now so that we are in a consistent state when |
+ // calling rebuildAllElementReferencesForTarget() and |
+ // removeAllElementReferencesForTarget() below. |
+ clearHasSVGRareData(); |
} |
ASSERT(document()); |
document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this); |
@@ -102,6 +130,43 @@ void SVGElement::willRecalcStyle(StyleChange change) |
svgRareData()->setNeedsOverrideComputedStyleUpdate(); |
} |
+void SVGElement::buildPendingResourcesIfNeeded() |
+{ |
+ Document* document = this->document(); |
+ if (!needsPendingResourceHandling() || !document || !inDocument() || isInShadowTree()) |
+ return; |
+ |
+ SVGDocumentExtensions* extensions = document->accessSVGExtensions(); |
+ String resourceId = getIdAttribute(); |
+ if (!extensions->hasPendingResource(resourceId)) |
+ return; |
+ |
+ // Mark pending resources as pending for removal. |
+ extensions->markPendingResourcesForRemoval(resourceId); |
+ |
+ // Rebuild pending resources for each client of a pending resource that is being removed. |
+ while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) { |
+ ASSERT(clientElement->hasPendingResources()); |
+ if (clientElement->hasPendingResources()) { |
+ clientElement->buildPendingResource(); |
+ extensions->clearHasPendingResourcesIfPossible(clientElement); |
+ } |
+ } |
+} |
+ |
+bool SVGElement::rendererIsNeededInternal(const NodeRenderingContext& context) |
+{ |
+ // http://www.w3.org/TR/SVG/extend.html#PrivateData |
+ // Prevent anything other than SVG renderers from appearing in our render tree |
+ // Spec: SVG allows inclusion of elements from foreign namespaces anywhere |
+ // with the SVG content. In general, the SVG user agent will include the unknown |
+ // elements in the DOM but will otherwise ignore unknown elements. |
+ if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement()) |
+ return Element::rendererIsNeeded(context); |
+ |
+ return false; |
+} |
+ |
SVGElementRareData* SVGElement::svgRareData() const |
{ |
ASSERT(hasSVGRareData()); |
@@ -170,6 +235,85 @@ bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const |
return DOMImplementation::hasFeature(feature, version); |
} |
+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()) |
+ 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())->host(); |
+ // 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 = static_cast<SVGUseElement*>(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. |
+ Element* titleElement = ElementTraversal::firstWithin(this); |
+ for (; titleElement; titleElement = ElementTraversal::nextSkippingChildren(titleElement, this)) { |
+ if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement()) |
+ break; |
+ } |
+ |
+ // If a title child was found, return the text contents. |
+ if (titleElement) |
+ return titleElement->innerText(); |
+ |
+ // Otherwise return a null/empty string. |
+ return String(); |
+} |
+ |
+PassRefPtr<CSSValue> SVGElement::getPresentationAttribute(const String& name) |
+{ |
+ if (!hasAttributesWithoutUpdate()) |
+ return 0; |
+ |
+ QualifiedName attributeName(nullAtom, name, nullAtom); |
+ const Attribute* attr = getAttributeItem(attributeName); |
+ if (!attr) |
+ return 0; |
+ |
+ RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(SVGAttributeMode); |
+ CSSPropertyID propertyID = SVGElement::cssPropertyIdForSVGAttributeName(attr->name()); |
+ style->setProperty(propertyID, attr->value()); |
+ RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(propertyID); |
+ return cssValue ? cssValue->cloneForCSSOM() : 0; |
+} |
+ |
+bool SVGElement::isKnownAttribute(const QualifiedName& attrName) |
+{ |
+ return isIdAttributeName(attrName); |
+} |
+ |
+bool SVGElement::instanceUpdatesBlocked() const |
+{ |
+ return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked(); |
+} |
+ |
+void SVGElement::setInstanceUpdatesBlocked(bool value) |
+{ |
+ if (hasSVGRareData()) |
+ svgRareData()->setInstanceUpdatesBlocked(value); |
+} |
+ |
+AffineTransform SVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const |
+{ |
+ // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement) |
+ return AffineTransform(); |
+} |
+ |
String SVGElement::xmlbase() const |
{ |
return fastGetAttribute(XMLNames::baseAttr); |
@@ -180,16 +324,148 @@ void SVGElement::setXmlbase(const String& value) |
setAttribute(XMLNames::baseAttr, value); |
} |
+Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent) |
+{ |
+ Element::insertedInto(rootParent); |
+ updateRelativeLengthsInformation(); |
+ buildPendingResourcesIfNeeded(); |
+ return InsertionDone; |
+} |
+ |
void SVGElement::removedFrom(ContainerNode* rootParent) |
{ |
bool wasInDocument = rootParent->inDocument(); |
+ if (wasInDocument) |
+ updateRelativeLengthsInformation(false, this); |
+ |
Element::removedFrom(rootParent); |
if (wasInDocument) { |
document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this); |
document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this); |
} |
+ |
+ SVGElementInstance::invalidateAllInstancesOfElement(this); |
+} |
+ |
+void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) |
+{ |
+ Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); |
+ |
+ // Invalidate all SVGElementInstances associated with us. |
+ if (!changedByParser) |
+ SVGElementInstance::invalidateAllInstancesOfElement(this); |
+} |
+ |
+CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName) |
+{ |
+ if (!attrName.namespaceURI().isNull()) |
+ return CSSPropertyInvalid; |
+ |
+ static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0; |
+ if (!propertyNameToIdMap) { |
+ propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>; |
+ // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes |
+ mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr); |
+ mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr); |
+ } |
+ |
+ return propertyNameToIdMap->get(attrName.localName().impl()); |
+} |
+ |
+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()) |
+ return; |
+ |
+ // An element wants to notify us that its own relative lengths state changed. |
+ // Register it in the relative length map, and register us in the parent relative length map. |
+ // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree. |
+ if (hasRelativeLengths) { |
+ m_elementsWithRelativeLengths.add(element); |
+ } else { |
+ if (!m_elementsWithRelativeLengths.contains(element)) { |
+ // We were never registered. Do nothing. |
+ return; |
+ } |
+ |
+ m_elementsWithRelativeLengths.remove(element); |
+ } |
+ |
+ // Find first styled parent node, and notify it that we've changed our relative length state. |
+ ContainerNode* node = parentNode(); |
+ while (node) { |
+ if (!node->isSVGElement()) |
+ break; |
+ |
+ SVGElement* element = toSVGElement(node); |
+ |
+ // Register us in the parent element map. |
+ element->updateRelativeLengthsInformation(hasRelativeLengths, this); |
+ break; |
+ } |
} |
SVGSVGElement* SVGElement::ownerSVGElement() const |
@@ -338,14 +614,110 @@ void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& v |
setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, name, value)); |
else if (name == SVGNames::onactivateAttr) |
setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, name, value)); |
- else if (SVGLangSpace::parseAttribute(name, value)) { |
+ else if (name == HTMLNames::classAttr) { |
+ // SVG animation has currently requires special storage of values so we set |
+ // the className here. svgAttributeChanged actually causes the resulting |
+ // style updates (instead of Element::parseAttribute). We don't |
+ // tell Element about the change to avoid parsing the class list twice |
+ setClassNameBaseValue(value); |
+ } else if (SVGLangSpace::parseAttribute(name, value)) { |
} else |
Element::parseAttribute(name, value); |
} |
+typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap; |
+static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap() |
+{ |
+ DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_cssPropertyMap, ()); |
+ |
+ if (!s_cssPropertyMap.isEmpty()) |
+ return s_cssPropertyMap; |
+ |
+ // Fill the map for the first use. |
+ s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString); |
+ s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString); |
+ s_cssPropertyMap.set(buffered_renderingAttr, AnimatedString); |
+ s_cssPropertyMap.set(clipAttr, AnimatedRect); |
+ s_cssPropertyMap.set(clip_pathAttr, AnimatedString); |
+ s_cssPropertyMap.set(clip_ruleAttr, AnimatedString); |
+ s_cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor); |
+ s_cssPropertyMap.set(color_interpolationAttr, AnimatedString); |
+ s_cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString); |
+ s_cssPropertyMap.set(color_profileAttr, AnimatedString); |
+ s_cssPropertyMap.set(color_renderingAttr, AnimatedString); |
+ s_cssPropertyMap.set(cursorAttr, AnimatedString); |
+ s_cssPropertyMap.set(displayAttr, AnimatedString); |
+ s_cssPropertyMap.set(dominant_baselineAttr, AnimatedString); |
+ s_cssPropertyMap.set(fillAttr, AnimatedColor); |
+ s_cssPropertyMap.set(fill_opacityAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(fill_ruleAttr, AnimatedString); |
+ s_cssPropertyMap.set(filterAttr, AnimatedString); |
+ s_cssPropertyMap.set(flood_colorAttr, AnimatedColor); |
+ s_cssPropertyMap.set(flood_opacityAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(font_familyAttr, AnimatedString); |
+ s_cssPropertyMap.set(font_sizeAttr, AnimatedLength); |
+ s_cssPropertyMap.set(font_stretchAttr, AnimatedString); |
+ s_cssPropertyMap.set(font_styleAttr, AnimatedString); |
+ s_cssPropertyMap.set(font_variantAttr, AnimatedString); |
+ s_cssPropertyMap.set(font_weightAttr, AnimatedString); |
+ s_cssPropertyMap.set(image_renderingAttr, AnimatedString); |
+ s_cssPropertyMap.set(kerningAttr, AnimatedLength); |
+ s_cssPropertyMap.set(letter_spacingAttr, AnimatedLength); |
+ s_cssPropertyMap.set(lighting_colorAttr, AnimatedColor); |
+ s_cssPropertyMap.set(marker_endAttr, AnimatedString); |
+ s_cssPropertyMap.set(marker_midAttr, AnimatedString); |
+ s_cssPropertyMap.set(marker_startAttr, AnimatedString); |
+ s_cssPropertyMap.set(maskAttr, AnimatedString); |
+ s_cssPropertyMap.set(mask_typeAttr, AnimatedString); |
+ s_cssPropertyMap.set(opacityAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(overflowAttr, AnimatedString); |
+ s_cssPropertyMap.set(pointer_eventsAttr, AnimatedString); |
+ s_cssPropertyMap.set(shape_renderingAttr, AnimatedString); |
+ s_cssPropertyMap.set(stop_colorAttr, AnimatedColor); |
+ s_cssPropertyMap.set(stop_opacityAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(strokeAttr, AnimatedColor); |
+ s_cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList); |
+ s_cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength); |
+ s_cssPropertyMap.set(stroke_linecapAttr, AnimatedString); |
+ s_cssPropertyMap.set(stroke_linejoinAttr, AnimatedString); |
+ s_cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber); |
+ s_cssPropertyMap.set(stroke_widthAttr, AnimatedLength); |
+ s_cssPropertyMap.set(text_anchorAttr, AnimatedString); |
+ s_cssPropertyMap.set(text_decorationAttr, AnimatedString); |
+ s_cssPropertyMap.set(text_renderingAttr, AnimatedString); |
+ s_cssPropertyMap.set(vector_effectAttr, AnimatedString); |
+ s_cssPropertyMap.set(visibilityAttr, AnimatedString); |
+ s_cssPropertyMap.set(word_spacingAttr, AnimatedLength); |
+ return s_cssPropertyMap; |
+} |
+ |
void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes) |
{ |
localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes); |
+ if (!propertyTypes.isEmpty()) |
+ return; |
+ |
+ AttributeToPropertyTypeMap& cssPropertyTypeMap = cssPropertyToTypeMap(); |
+ if (cssPropertyTypeMap.contains(attributeName)) |
+ propertyTypes.append(cssPropertyTypeMap.get(attributeName)); |
+} |
+ |
+bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName) |
+{ |
+ return cssPropertyToTypeMap().contains(attrName); |
+} |
+ |
+bool SVGElement::isPresentationAttribute(const QualifiedName& name) const |
+{ |
+ return cssPropertyIdForSVGAttributeName(name) > 0; |
+} |
+ |
+void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) |
+{ |
+ CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name); |
+ if (propertyID > 0) |
+ addPropertyToPresentationAttributeStyle(style, propertyID, value); |
} |
bool SVGElement::haveLoadedRequiredResources() |
@@ -365,13 +737,9 @@ static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SV |
if (element->containingShadowRoot()) |
return; |
- if (!element->isSVGStyledElement()) |
- return; |
- |
- SVGStyledElement* styledElement = toSVGStyledElement(element); |
- ASSERT(!styledElement->instanceUpdatesBlocked()); |
+ ASSERT(!element->instanceUpdatesBlocked()); |
- instances = styledElement->instancesForElement(); |
+ instances = element->instancesForElement(); |
} |
bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture) |
@@ -557,6 +925,32 @@ void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& |
svgAttributeChanged(name); |
} |
+void SVGElement::svgAttributeChanged(const QualifiedName& attrName) |
+{ |
+ CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName); |
+ if (propId > 0) { |
+ SVGElementInstance::invalidateAllInstancesOfElement(this); |
+ return; |
+ } |
+ |
+ if (attrName == HTMLNames::classAttr) { |
+ classAttributeChanged(classNameCurrentValue()); |
+ SVGElementInstance::invalidateAllInstancesOfElement(this); |
+ return; |
+ } |
+ |
+ if (isIdAttributeName(attrName)) { |
+ RenderObject* object = 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()) |
+ buildPendingResourcesIfNeeded(); |
+ SVGElementInstance::invalidateAllInstancesOfElement(this); |
+ return; |
+ } |
+} |
+ |
void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const |
{ |
if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty) |
@@ -570,12 +964,6 @@ void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) cons |
nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name); |
} |
-SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap() const |
-{ |
- DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, emptyMap, ()); |
- return emptyMap; |
-} |
- |
void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement) |
{ |
ASSERT(contextElement); |
@@ -754,7 +1142,7 @@ bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const |
} |
if (name == classAttr) |
- return isSVGStyledElement(); |
+ return true; |
return animatableAttributes.contains(name); |
} |