Chromium Code Reviews| 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) |
|
do-not-use
2013/07/30 15:44:07
This is the tough part:
- SVGElement::rendererIsNe
|
| +{ |
| + // 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); |
| } |