Title: [117323] trunk/Source/WebCore
Revision
117323
Author
kl...@webkit.org
Date
2012-05-16 12:31:40 -0700 (Wed, 16 May 2012)

Log Message

Avoid reparsing the style attribute when cloning elements.
<http://webkit.org/b/86574>

Reviewed by Antti Koivisto.

Refactor cloning of attributes a bit to dodge the styleAttr reparse previously
caused by ElementAttributeData::setAttributes().

Introduced Element::cloneDataFromElement() which takes care of cloning the
ElementAttributeData as well as "non-attribute properties" (which is currently
specific to HTMLInputElement.)

Also includes some additional dodging of attribute vector traversal to find
old/new 'id' and 'name' attributes.

I'm seeing a ~10% improvement on PerformanceTests/DOM/CloneNodes locally.

* dom/Document.cpp:
(WebCore::Document::importNode):
* dom/Element.cpp:
(WebCore::Element::cloneElementWithoutChildren):
(WebCore::Element::cloneAttributesFromElement):
(WebCore::Element::cloneDataFromElement):
* dom/Element.h:
(WebCore::Element::copyNonAttributePropertiesFromElement):
* dom/ElementAttributeData.cpp:
(WebCore::ElementAttributeData::cloneDataFrom):
* dom/ElementAttributeData.h:
(ElementAttributeData):
* dom/Node.h:
* dom/StyledElement.cpp:
(WebCore::StyledElement::styleAttributeChanged):
(WebCore::StyledElement::parseAttribute):
* dom/StyledElement.h:
* editing/ReplaceNodeWithSpanCommand.cpp:
(WebCore::swapInNodePreservingAttributesAndChildren):
* html/HTMLElement.cpp:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::copyNonAttributePropertiesFromElement):
* html/HTMLInputElement.h:
* inspector/DOMPatchSupport.cpp:
(WebCore::DOMPatchSupport::innerPatchNode):
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::setNodeName):
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::expandSymbolElementsInShadowTree):
(WebCore::SVGUseElement::transferUseAttributesToReplacedElement):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (117322 => 117323)


--- trunk/Source/WebCore/ChangeLog	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/ChangeLog	2012-05-16 19:31:40 UTC (rev 117323)
@@ -1,3 +1,53 @@
+2012-05-16  Andreas Kling  <kl...@webkit.org>
+
+        Avoid reparsing the style attribute when cloning elements.
+        <http://webkit.org/b/86574>
+
+        Reviewed by Antti Koivisto.
+
+        Refactor cloning of attributes a bit to dodge the styleAttr reparse previously
+        caused by ElementAttributeData::setAttributes().
+
+        Introduced Element::cloneDataFromElement() which takes care of cloning the
+        ElementAttributeData as well as "non-attribute properties" (which is currently
+        specific to HTMLInputElement.)
+
+        Also includes some additional dodging of attribute vector traversal to find
+        old/new 'id' and 'name' attributes.
+
+        I'm seeing a ~10% improvement on PerformanceTests/DOM/CloneNodes locally.
+
+        * dom/Document.cpp:
+        (WebCore::Document::importNode):
+        * dom/Element.cpp:
+        (WebCore::Element::cloneElementWithoutChildren):
+        (WebCore::Element::cloneAttributesFromElement):
+        (WebCore::Element::cloneDataFromElement):
+        * dom/Element.h:
+        (WebCore::Element::copyNonAttributePropertiesFromElement):
+        * dom/ElementAttributeData.cpp:
+        (WebCore::ElementAttributeData::cloneDataFrom):
+        * dom/ElementAttributeData.h:
+        (ElementAttributeData):
+        * dom/Node.h:
+        * dom/StyledElement.cpp:
+        (WebCore::StyledElement::styleAttributeChanged):
+        (WebCore::StyledElement::parseAttribute):
+        * dom/StyledElement.h:
+        * editing/ReplaceNodeWithSpanCommand.cpp:
+        (WebCore::swapInNodePreservingAttributesAndChildren):
+        * html/HTMLElement.cpp:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::copyNonAttributePropertiesFromElement):
+        * html/HTMLInputElement.h:
+        * inspector/DOMPatchSupport.cpp:
+        (WebCore::DOMPatchSupport::innerPatchNode):
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::setNodeName):
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::expandSymbolElementsInShadowTree):
+        (WebCore::SVGUseElement::transferUseAttributesToReplacedElement):
+
 2012-05-16  Brent Fulgham  <bfulg...@webkit.org>
 
         [WinCairo] Unreviewed build change after r115385.  Several Cairo

Modified: trunk/Source/WebCore/dom/Document.cpp (117322 => 117323)


--- trunk/Source/WebCore/dom/Document.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/Document.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -914,8 +914,7 @@
         if (ec)
             return 0;
 
-        newElement->setAttributesFromElement(*oldElement);
-        newElement->copyNonAttributeProperties(oldElement);
+        newElement->cloneDataFromElement(*oldElement);
 
         if (deep) {
             for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {

Modified: trunk/Source/WebCore/dom/Element.cpp (117322 => 117323)


--- trunk/Source/WebCore/dom/Element.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/Element.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -178,9 +178,7 @@
     // This is a sanity check as HTML overloads some of the DOM methods.
     ASSERT(isHTMLElement() == clone->isHTMLElement());
 
-    clone->setAttributesFromElement(*this);
-    clone->copyNonAttributeProperties(this);
-
+    clone->cloneDataFromElement(*this);
     return clone.release();
 }
 
@@ -189,10 +187,6 @@
     return document()->createElement(tagQName(), false);
 }
 
-void Element::copyNonAttributeProperties(const Element*)
-{
-}
-
 PassRefPtr<Attr> Element::detachAttribute(size_t index)
 {
     if (!attributeData())
@@ -2117,4 +2111,20 @@
 }
 
 
+void Element::cloneAttributesFromElement(const Element& other)
+{
+    if (ElementAttributeData* attributeData = other.updatedAttributeData())
+        ensureUpdatedAttributeData()->cloneDataFrom(*attributeData, other, *this);
+    else if (m_attributeData) {
+        m_attributeData->clearAttributes(this);
+        m_attributeData.clear();
+    }
+}
+
+void Element::cloneDataFromElement(const Element& other)
+{
+    cloneAttributesFromElement(other);
+    copyNonAttributePropertiesFromElement(other);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Element.h (117322 => 117323)


--- trunk/Source/WebCore/dom/Element.h	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/Element.h	2012-05-16 19:31:40 UTC (rev 117323)
@@ -251,10 +251,15 @@
     ElementAttributeData* updatedAttributeData() const;
     ElementAttributeData* ensureUpdatedAttributeData() const;
 
-    void setAttributesFromElement(const Element&);
+    // Clones attributes only.
+    void cloneAttributesFromElement(const Element&);
+
+    // Clones all attribute-derived data, including subclass specifics (through copyNonAttributeProperties.)
+    void cloneDataFromElement(const Element&);
+
     bool hasEquivalentAttributes(const Element* other) const;
 
-    virtual void copyNonAttributeProperties(const Element* source);
+    virtual void copyNonAttributePropertiesFromElement(const Element&) { }
 
     virtual void attach();
     virtual void detach();
@@ -562,12 +567,6 @@
     return ensureAttributeData();
 }
 
-inline void Element::setAttributesFromElement(const Element& other)
-{
-    if (ElementAttributeData* attributeData = other.updatedAttributeData())
-        ensureUpdatedAttributeData()->setAttributes(*attributeData, this);
-}
-
 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
 {
     if (!inDocument())

Modified: trunk/Source/WebCore/dom/ElementAttributeData.cpp (117322 => 117323)


--- trunk/Source/WebCore/dom/ElementAttributeData.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/ElementAttributeData.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -252,28 +252,36 @@
     return notFound;
 }
 
-void ElementAttributeData::setAttributes(const ElementAttributeData& other, Element* element)
+void ElementAttributeData::cloneDataFrom(const ElementAttributeData& sourceData, const Element& sourceElement, Element& targetElement)
 {
-    ASSERT(element);
+    const AtomicString& oldID = targetElement.getIdAttribute();
+    const AtomicString& newID = sourceElement.getIdAttribute();
 
-    // If assigning the map changes the id attribute, we need to call
-    // updateId.
-    Attribute* oldId = getAttributeItem(element->document()->idAttributeName());
-    Attribute* newId = other.getAttributeItem(element->document()->idAttributeName());
+    if (!oldID.isNull() || !newID.isNull())
+        targetElement.updateId(oldID, newID);
 
-    if (oldId || newId)
-        element->updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
+    const AtomicString& oldName = targetElement.getNameAttribute();
+    const AtomicString& newName = sourceElement.getNameAttribute();
 
-    Attribute* oldName = getAttributeItem(HTMLNames::nameAttr);
-    Attribute* newName = other.getAttributeItem(HTMLNames::nameAttr);
+    if (!oldName.isNull() || !newName.isNull())
+        targetElement.updateName(oldName, newName);
 
-    if (oldName || newName)
-        element->updateName(oldName ? oldName->value() : nullAtom, newName ? newName->value() : nullAtom);
+    clearAttributes(&targetElement);
+    m_attributes = sourceData.m_attributes;
+    for (unsigned i = 0; i < m_attributes.size(); ++i) {
+        if (targetElement.isStyledElement() && m_attributes[i].name() == HTMLNames::styleAttr) {
+            static_cast<StyledElement&>(targetElement).styleAttributeChanged(m_attributes[i].value(), StyledElement::DoNotReparseStyleAttribute);
+            continue;
+        }
+        targetElement.attributeChanged(m_attributes[i]);
+    }
 
-    clearAttributes(element);
-    m_attributes = other.m_attributes;
-    for (unsigned i = 0; i < m_attributes.size(); ++i)
-        element->attributeChanged(m_attributes[i]);
+    if (targetElement.isStyledElement() && sourceData.m_inlineStyleDecl) {
+        StylePropertySet* inlineStyle = ensureMutableInlineStyle(static_cast<StyledElement*>(&targetElement));
+        inlineStyle->copyPropertiesFrom(*sourceData.m_inlineStyleDecl);
+        inlineStyle->setCSSParserMode(sourceData.m_inlineStyleDecl->cssParserMode());
+        targetElement.setIsStyleAttributeValid(sourceElement.isStyleAttributeValid());
+    }
 }
 
 void ElementAttributeData::clearAttributes(Element* element)

Modified: trunk/Source/WebCore/dom/ElementAttributeData.h (117322 => 117323)


--- trunk/Source/WebCore/dom/ElementAttributeData.h	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/ElementAttributeData.h	2012-05-16 19:31:40 UTC (rev 117323)
@@ -113,7 +113,7 @@
     void detachAttributesFromElement(Element*);
     Attribute* getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const;
     size_t getAttributeItemIndexSlowCase(const String& name, bool shouldIgnoreAttributeCase) const;
-    void setAttributes(const ElementAttributeData& other, Element*);
+    void cloneDataFrom(const ElementAttributeData& sourceData, const Element& sourceElement, Element& targetElement);
     void clearAttributes(Element*);
     void replaceAttribute(size_t index, const Attribute&, Element*);
 

Modified: trunk/Source/WebCore/dom/Node.h (117322 => 117323)


--- trunk/Source/WebCore/dom/Node.h	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/Node.h	2012-05-16 19:31:40 UTC (rev 117323)
@@ -790,15 +790,17 @@
     Node* m_next;
     RenderObject* m_renderer;
 
-protected:
-    bool isParsingChildrenFinished() const { return getFlag(IsParsingChildrenFinishedFlag); }
-    void setIsParsingChildrenFinished() { setFlag(IsParsingChildrenFinishedFlag); }
-    void clearIsParsingChildrenFinished() { clearFlag(IsParsingChildrenFinishedFlag); }
+public:
     bool isStyleAttributeValid() const { return getFlag(IsStyleAttributeValidFlag); }
     void setIsStyleAttributeValid(bool f) { setFlag(f, IsStyleAttributeValidFlag); }
     void setIsStyleAttributeValid() const { setFlag(IsStyleAttributeValidFlag); }
     void clearIsStyleAttributeValid() { clearFlag(IsStyleAttributeValidFlag); }
 
+protected:
+    bool isParsingChildrenFinished() const { return getFlag(IsParsingChildrenFinishedFlag); }
+    void setIsParsingChildrenFinished() { setFlag(IsParsingChildrenFinishedFlag); }
+    void clearIsParsingChildrenFinished() { clearFlag(IsParsingChildrenFinishedFlag); }
+
 #if ENABLE(SVG)
     bool areSVGAttributesValid() const { return getFlag(AreSVGAttributesValidFlag); }
     void setAreSVGAttributesValid() const { setFlag(AreSVGAttributesValidFlag); }

Modified: trunk/Source/WebCore/dom/StyledElement.cpp (117322 => 117323)


--- trunk/Source/WebCore/dom/StyledElement.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/StyledElement.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -168,21 +168,27 @@
     setNeedsStyleRecalc();
 }
 
-void StyledElement::parseAttribute(const Attribute& attribute)
+void StyledElement::styleAttributeChanged(const AtomicString& newStyleString, ShouldReparseStyleAttribute shouldReparse)
 {
-    if (attribute.name() == classAttr)
-        classAttributeChanged(attribute.value());
-    else if (attribute.name() == styleAttr) {
-        if (attribute.isNull())
+    if (shouldReparse) {
+        if (newStyleString.isNull())
             destroyInlineStyle();
         else if (document()->contentSecurityPolicy()->allowInlineStyle())
-            ensureAttributeData()->updateInlineStyleAvoidingMutation(this, attribute.value());
+            ensureAttributeData()->updateInlineStyleAvoidingMutation(this, newStyleString);
         setIsStyleAttributeValid();
-        setNeedsStyleRecalc();
-        InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
     }
+    setNeedsStyleRecalc();
+    InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
 }
 
+void StyledElement::parseAttribute(const Attribute& attribute)
+{
+    if (attribute.name() == classAttr)
+        classAttributeChanged(attribute.value());
+    else if (attribute.name() == styleAttr)
+        styleAttributeChanged(attribute.value());
+}
+
 void StyledElement::inlineStyleChanged()
 {
     setNeedsStyleRecalc(InlineStyleChange);

Modified: trunk/Source/WebCore/dom/StyledElement.h (117322 => 117323)


--- trunk/Source/WebCore/dom/StyledElement.h	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/dom/StyledElement.h	2012-05-16 19:31:40 UTC (rev 117323)
@@ -57,6 +57,10 @@
 
     virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) { }
 
+    // May be called by ElementAttributeData::cloneDataFrom().
+    enum ShouldReparseStyleAttribute { DoNotReparseStyleAttribute = 0, ReparseStyleAttribute = 1 };
+    void styleAttributeChanged(const AtomicString& newStyleString, ShouldReparseStyleAttribute = ReparseStyleAttribute);
+
 protected:
     StyledElement(const QualifiedName& name, Document* document, ConstructionType type)
         : Element(name, document, type)
@@ -65,7 +69,6 @@
 
     virtual void attributeChanged(const Attribute&) OVERRIDE;
     virtual void parseAttribute(const Attribute&);
-    virtual void copyNonAttributeProperties(const Element*);
 
     virtual bool isPresentationAttribute(const QualifiedName&) const { return false; }
 

Modified: trunk/Source/WebCore/editing/ReplaceNodeWithSpanCommand.cpp (117322 => 117323)


--- trunk/Source/WebCore/editing/ReplaceNodeWithSpanCommand.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/editing/ReplaceNodeWithSpanCommand.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -64,7 +64,7 @@
     }
 
     // FIXME: Fix this to send the proper MutationRecords when MutationObservers are present.
-    newNode->setAttributesFromElement(*nodeToReplace);
+    newNode->cloneDataFromElement(*nodeToReplace);
 
     parentNode->removeChild(nodeToReplace, ec);
     ASSERT(!ec);

Modified: trunk/Source/WebCore/html/HTMLElement.cpp (117322 => 117323)


--- trunk/Source/WebCore/html/HTMLElement.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/html/HTMLElement.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -1108,25 +1108,6 @@
     style->setProperty(propertyID, cssValuePool().createColorValue(parsedColor.rgb()));
 }
 
-void StyledElement::copyNonAttributeProperties(const Element* sourceElement)
-{
-    ASSERT(sourceElement);
-    ASSERT(sourceElement->isStyledElement());
-
-    const StyledElement* source = static_cast<const StyledElement*>(sourceElement);
-    if (!source->inlineStyle())
-        return;
-
-    StylePropertySet* inlineStyle = ensureAttributeData()->ensureMutableInlineStyle(this);
-    inlineStyle->copyPropertiesFrom(*source->inlineStyle());
-    inlineStyle->setCSSParserMode(source->inlineStyle()->cssParserMode());
-
-    setIsStyleAttributeValid(source->isStyleAttributeValid());
-
-    Element::copyNonAttributeProperties(sourceElement);
-}
-
-
 } // namespace WebCore
 
 #ifndef NDEBUG

Modified: trunk/Source/WebCore/html/HTMLInputElement.cpp (117322 => 117323)


--- trunk/Source/WebCore/html/HTMLInputElement.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/html/HTMLInputElement.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -825,17 +825,17 @@
     return m_inputType->sizeShouldIncludeDecoration(defaultSize, preferredSize);
 }
 
-void HTMLInputElement::copyNonAttributeProperties(const Element* source)
+void HTMLInputElement::copyNonAttributePropertiesFromElement(const Element& source)
 {
-    const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source);
+    const HTMLInputElement& sourceElement = static_cast<const HTMLInputElement&>(source);
 
-    m_valueIfDirty = sourceElement->m_valueIfDirty;
+    m_valueIfDirty = sourceElement.m_valueIfDirty;
     m_wasModifiedByUser = false;
-    setChecked(sourceElement->m_isChecked);
-    m_reflectsCheckedAttribute = sourceElement->m_reflectsCheckedAttribute;
-    m_isIndeterminate = sourceElement->m_isIndeterminate;
+    setChecked(sourceElement.m_isChecked);
+    m_reflectsCheckedAttribute = sourceElement.m_reflectsCheckedAttribute;
+    m_isIndeterminate = sourceElement.m_isIndeterminate;
 
-    HTMLTextFormControlElement::copyNonAttributeProperties(source);
+    HTMLTextFormControlElement::copyNonAttributePropertiesFromElement(source);
 
     setFormControlValueMatchesRenderer(false);
     updateInnerTextValue();

Modified: trunk/Source/WebCore/html/HTMLInputElement.h (117322 => 117323)


--- trunk/Source/WebCore/html/HTMLInputElement.h	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/html/HTMLInputElement.h	2012-05-16 19:31:40 UTC (rev 117323)
@@ -290,7 +290,7 @@
     virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE;
     virtual void finishParsingChildren();
 
-    virtual void copyNonAttributeProperties(const Element* source);
+    virtual void copyNonAttributePropertiesFromElement(const Element&);
 
     virtual void attach();
 

Modified: trunk/Source/WebCore/inspector/DOMPatchSupport.cpp (117322 => 117323)


--- trunk/Source/WebCore/inspector/DOMPatchSupport.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/inspector/DOMPatchSupport.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -180,7 +180,7 @@
             }
         }
 
-        // FIXME: Create a function in Element for copying properties. setAttributesFromElement() is close but not enough for this case.
+        // FIXME: Create a function in Element for copying properties. cloneDataFromElement() is close but not enough for this case.
         if (newElement->hasAttributesWithoutUpdate()) {
             size_t numAttrs = newElement->attributeCount();
             for (size_t i = 0; i < numAttrs; ++i) {

Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (117322 => 117323)


--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -653,7 +653,7 @@
         return;
 
     // Copy over the original node's attributes.
-    newElem->setAttributesFromElement(*toElement(oldNode));
+    newElem->cloneAttributesFromElement(*toElement(oldNode));
 
     // Copy over the original node's children.
     Node* child;

Modified: trunk/Source/WebCore/svg/SVGUseElement.cpp (117322 => 117323)


--- trunk/Source/WebCore/svg/SVGUseElement.cpp	2012-05-16 19:25:25 UTC (rev 117322)
+++ trunk/Source/WebCore/svg/SVGUseElement.cpp	2012-05-16 19:31:40 UTC (rev 117323)
@@ -766,8 +766,8 @@
         // 'svg' element will use values of 100% for these attributes.
         RefPtr<SVGSVGElement> svgElement = SVGSVGElement::create(SVGNames::svgTag, referencedDocument());
 
-        // Transfer all attributes from <symbol> to the new <svg> element
-        svgElement->setAttributesFromElement(*toElement(element));
+        // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
+        svgElement->cloneDataFromElement(*toElement(element));
 
         // Only clone symbol children, and add them to the new <svg> element
         for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
@@ -898,7 +898,7 @@
     ASSERT(from);
     ASSERT(to);
 
-    to->setAttributesFromElement(*from);
+    to->cloneDataFromElement(*from);
 
     to->removeAttribute(SVGNames::xAttr);
     to->removeAttribute(SVGNames::yAttr);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to