Increased style sharing for elements with presentation attributes.
authorkling@webkit.org <kling@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 04:41:19 +0000 (04:41 +0000)
committerkling@webkit.org <kling@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Feb 2012 04:41:19 +0000 (04:41 +0000)
<http://webkit.org/b/78199>

Reviewed by Antti Koivisto.

When determining whether two elements can share style, we can do a lot better.
Instead of comparing the attribute maps for exact equality, do a property-by-property
comparison of the attributeStyle() and the additionalAttributeStyle() (if any.)

This increases our style sharing hit rate and shaves 100ms off of each cycle on
Chromium's "Moz" page cycler test on my machine.

The function that compares attribute styles has O(n^2) runtime in the worst case,
where n is the number of properties in the styles. However, given the low number of
properties found in attribute styles, this should be fine, and it doesn't seem to
heat up in profiles.

* css/CSSStyleSelector.cpp:
(WebCore::attributeStylesEqual):
(WebCore::CSSStyleSelector::canShareStyleWithElement):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@107173 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/css/CSSStyleSelector.cpp

index 2f58add..6ec5a25 100644 (file)
@@ -1,3 +1,26 @@
+2012-02-08  Andreas Kling  <awesomekling@apple.com>
+
+        Increased style sharing for elements with presentation attributes.
+        <http://webkit.org/b/78199>
+
+        Reviewed by Antti Koivisto.
+
+        When determining whether two elements can share style, we can do a lot better.
+        Instead of comparing the attribute maps for exact equality, do a property-by-property
+        comparison of the attributeStyle() and the additionalAttributeStyle() (if any.)
+
+        This increases our style sharing hit rate and shaves 100ms off of each cycle on
+        Chromium's "Moz" page cycler test on my machine.
+
+        The function that compares attribute styles has O(n^2) runtime in the worst case,
+        where n is the number of properties in the styles. However, given the low number of
+        properties found in attribute styles, this should be fine, and it doesn't seem to
+        heat up in profiles.
+
+        * css/CSSStyleSelector.cpp:
+        (WebCore::attributeStylesEqual):
+        (WebCore::CSSStyleSelector::canShareStyleWithElement):
+
 2012-02-08  Raymond Liu  <raymond.liu@intel.com>
 
         Fix the caculation of preDelayFrames in DynamicsCompressorKernel
index 54cdd93..7f158f6 100644 (file)
@@ -1194,6 +1194,32 @@ bool CSSStyleSelector::canShareStyleWithControl(StyledElement* element) const
     return true;
 }
 
+// This function makes some assumptions that only make sense for attribute styles (we only compare CSSProperty::id() and CSSProperty::value().)
+static inline bool attributeStylesEqual(StylePropertySet* a, StylePropertySet* b)
+{
+    if (a == b)
+        return true;
+    if (a->propertyCount() != b->propertyCount())
+        return false;
+    unsigned propertyCount = a->propertyCount();
+    for (unsigned i = 0; i < propertyCount; ++i) {
+        const CSSProperty& aProperty = a->propertyAt(i);
+        unsigned j;
+        for (j = 0; j < propertyCount; ++j) {
+            const CSSProperty& bProperty = b->propertyAt(j);
+            if (aProperty.id() != bProperty.id())
+                continue;
+            // We could get a few more hits by comparing cssText() here, but that gets expensive quickly.
+            if (aProperty.value() != bProperty.value())
+                return false;
+            break;
+        }
+        if (j == propertyCount)
+            return false;
+    }
+    return true;
+}
+
 bool CSSStyleSelector::canShareStyleWithElement(StyledElement* element) const
 {
     RenderStyle* style = element->renderStyle();
@@ -1210,6 +1236,10 @@ bool CSSStyleSelector::canShareStyleWithElement(StyledElement* element) const
         return false;
     if (!!element->attributeStyle() != !!m_styledElement->attributeStyle())
         return false;
+    StylePropertySet* additionalAttributeStyleA = element->additionalAttributeStyle().get();
+    StylePropertySet* additionalAttributeStyleB = m_styledElement->additionalAttributeStyle().get();
+    if (!additionalAttributeStyleA != !additionalAttributeStyleB)
+        return false;
     if (element->isLink() != m_element->isLink())
         return false;
     if (style->affectedByUncommonAttributeSelectors())
@@ -1274,7 +1304,10 @@ bool CSSStyleSelector::canShareStyleWithElement(StyledElement* element) const
     if (element->hasClass() && m_element->getAttribute(classAttr) != element->getAttribute(classAttr))
         return false;
 
-    if (element->attributeStyle() && !element->attributeMap()->mapsEquivalent(m_styledElement->attributeMap()))
+    if (element->attributeStyle() && !attributeStylesEqual(element->attributeStyle(), m_styledElement->attributeStyle()))
+        return false;
+
+    if (additionalAttributeStyleA && !attributeStylesEqual(additionalAttributeStyleA, additionalAttributeStyleB))
         return false;
 
     if (element->isLink() && m_elementLinkState != style->insideLink())