Title: [201159] trunk
Revision
201159
Author
[email protected]
Date
2016-05-19 06:22:18 -0700 (Thu, 19 May 2016)

Log Message

Style resolution for explicitly inherited properties is inefficient
https://bugs.webkit.org/show_bug.cgi?id=157860

Reviewed by Andreas Kling.

Source/WebCore:

We mark the parent style with hasExplicitlyInheritedProperties bit rather than the style that is actually
affected by inherited properties. This leads to various inefficiencies including unnecessarily wide style recalcs.

* css/StyleResolver.cpp:
(WebCore::isCacheableInMatchedPropertiesCache):

    Check the style itself rather than the parent. This allows more caching.

(WebCore::StyleResolver::applyProperty):

    Mark the style rather than the parent.

* style/StyleChange.cpp:
(WebCore::Style::determineChange):

    Remove hasExplicitlyInheritedProperties test and just return NoInherit. Having explicitly inherited
    properties doesn't make the children inherit them automatically.

    This allows smaller style recalcs.

* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::resolveElement):

    This patch exposed a bug with appearance property in meter and progress elements.
    They may construct different renderer based on appearance so we need to force
    render tree reconstruction when it changes.

(WebCore::Style::TreeResolver::popParentsToDepth):
(WebCore::Style::shouldResolvePseudoElement):

    Don't clear the style recalc bits here.

(WebCore::Style::shouldResolveElement):

    Add a helper.
    If the parent had a NoInherit style change, test if the element has existing style with
    hasExplicitlyInheritedProperties bit. If so we need to re-resolve this element.

(WebCore::Style::clearNeedsStyleResolution):

    Also clear pseudo elements.

(WebCore::Style::TreeResolver::resolveComposedTree):

LayoutTests:

* platform/ios-simulator/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt:
* platform/mac/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt:

This is a progression.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (201158 => 201159)


--- trunk/LayoutTests/ChangeLog	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/LayoutTests/ChangeLog	2016-05-19 13:22:18 UTC (rev 201159)
@@ -1,3 +1,15 @@
+2016-05-18  Antti Koivisto  <[email protected]>
+
+        Style resolution for explicitly inherited properties is inefficient
+        https://bugs.webkit.org/show_bug.cgi?id=157860
+
+        Reviewed by Andreas Kling.
+
+        * platform/ios-simulator/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt:
+        * platform/mac/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt:
+
+        This is a progression.
+
 2016-05-19  Yoav Weiss  <[email protected]>
 
         REGRESSION (r200887): LayoutTest http/tests/performance/performance-resource-timing-cached-entries.html is flaky

Modified: trunk/LayoutTests/platform/ios-simulator/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt (201158 => 201159)


--- trunk/LayoutTests/platform/ios-simulator/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/LayoutTests/platform/ios-simulator/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt	2016-05-19 13:22:18 UTC (rev 201159)
@@ -56,7 +56,7 @@
           RenderListMarker at (-18,0) size 7x19: bullet
           RenderText {#text} at (0,0) size 235x19
             text run at (0,0) width 235: "Removing appearance dynamically: "
-          RenderProgress {PROGRESS} at (234,2) size 161x17
+          RenderBlock {PROGRESS} at (234,2) size 161x17
             RenderProgress {DIV} at (0,0) size 160x16
               RenderBlock {DIV} at (0,0) size 160x16 [bgcolor=#808080]
                 RenderBlock {DIV} at (0,0) size 112x16 [bgcolor=#008000]

Modified: trunk/LayoutTests/platform/mac/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt (201158 => 201159)


--- trunk/LayoutTests/platform/mac/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/LayoutTests/platform/mac/fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element-expected.txt	2016-05-19 13:22:18 UTC (rev 201159)
@@ -56,7 +56,7 @@
           RenderListMarker at (-17,0) size 7x18: bullet
           RenderText {#text} at (0,0) size 235x18
             text run at (0,0) width 235: "Removing appearance dynamically: "
-          RenderProgress {PROGRESS} at (234,1) size 161x17
+          RenderBlock {PROGRESS} at (234,1) size 161x17
             RenderProgress {DIV} at (0,0) size 160x16
               RenderBlock {DIV} at (0,0) size 160x16 [bgcolor=#808080]
                 RenderBlock {DIV} at (0,0) size 112x16 [bgcolor=#008000]

Modified: trunk/Source/WebCore/ChangeLog (201158 => 201159)


--- trunk/Source/WebCore/ChangeLog	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/Source/WebCore/ChangeLog	2016-05-19 13:22:18 UTC (rev 201159)
@@ -1,3 +1,54 @@
+2016-05-18  Antti Koivisto  <[email protected]>
+
+        Style resolution for explicitly inherited properties is inefficient
+        https://bugs.webkit.org/show_bug.cgi?id=157860
+
+        Reviewed by Andreas Kling.
+
+        We mark the parent style with hasExplicitlyInheritedProperties bit rather than the style that is actually
+        affected by inherited properties. This leads to various inefficiencies including unnecessarily wide style recalcs.
+
+        * css/StyleResolver.cpp:
+        (WebCore::isCacheableInMatchedPropertiesCache):
+
+            Check the style itself rather than the parent. This allows more caching.
+
+        (WebCore::StyleResolver::applyProperty):
+
+            Mark the style rather than the parent.
+
+        * style/StyleChange.cpp:
+        (WebCore::Style::determineChange):
+
+            Remove hasExplicitlyInheritedProperties test and just return NoInherit. Having explicitly inherited
+            properties doesn't make the children inherit them automatically.
+
+            This allows smaller style recalcs.
+
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::resolveElement):
+
+            This patch exposed a bug with appearance property in meter and progress elements.
+            They may construct different renderer based on appearance so we need to force
+            render tree reconstruction when it changes.
+
+        (WebCore::Style::TreeResolver::popParentsToDepth):
+        (WebCore::Style::shouldResolvePseudoElement):
+
+            Don't clear the style recalc bits here.
+
+        (WebCore::Style::shouldResolveElement):
+
+            Add a helper.
+            If the parent had a NoInherit style change, test if the element has existing style with
+            hasExplicitlyInheritedProperties bit. If so we need to re-resolve this element.
+
+        (WebCore::Style::clearNeedsStyleResolution):
+
+            Also clear pseudo elements.
+
+        (WebCore::Style::TreeResolver::resolveComposedTree):
+
 2016-05-19  Youenn Fablet  <[email protected]>
 
         Refactor toJS functions to use toJSNewlyCreated

Modified: trunk/Source/WebCore/css/StyleResolver.cpp (201158 => 201159)


--- trunk/Source/WebCore/css/StyleResolver.cpp	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/Source/WebCore/css/StyleResolver.cpp	2016-05-19 13:22:18 UTC (rev 201159)
@@ -1255,7 +1255,7 @@
     if (style->writingMode() != RenderStyle::initialWritingMode() || style->direction() != RenderStyle::initialDirection())
         return false;
     // The cache assumes static knowledge about which properties are inherited.
-    if (parentStyle->hasExplicitlyInheritedProperties())
+    if (style->hasExplicitlyInheritedProperties())
         return false;
     return true;
 }
@@ -1636,8 +1636,8 @@
         return;
     }
 
-    if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id))
-        const_cast<RenderStyle*>(state.parentStyle())->setHasExplicitlyInheritedProperties();
+    if (isInherit && !CSSProperty::isInheritedProperty(id))
+        state.style()->setHasExplicitlyInheritedProperties();
     
     if (id == CSSPropertyCustom) {
         CSSCustomPropertyValue* customProperty = &downcast<CSSCustomPropertyValue>(*valueToApply);

Modified: trunk/Source/WebCore/style/StyleChange.cpp (201158 => 201159)


--- trunk/Source/WebCore/style/StyleChange.cpp	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/Source/WebCore/style/StyleChange.cpp	2016-05-19 13:22:18 UTC (rev 201159)
@@ -63,8 +63,6 @@
     if (s1 != s2) {
         if (s1.inheritedNotEqual(&s2))
             return Inherit;
-        if (s1.hasExplicitlyInheritedProperties() || s2.hasExplicitlyInheritedProperties())
-            return Inherit;
 
         return NoInherit;
     }

Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (201158 => 201159)


--- trunk/Source/WebCore/style/StyleTreeResolver.cpp	2016-05-19 12:03:16 UTC (rev 201158)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp	2016-05-19 13:22:18 UTC (rev 201159)
@@ -32,6 +32,8 @@
 #include "ComposedTreeIterator.h"
 #include "ElementIterator.h"
 #include "HTMLBodyElement.h"
+#include "HTMLMeterElement.h"
+#include "HTMLProgressElement.h"
 #include "HTMLSlotElement.h"
 #include "LoaderStrategy.h"
 #include "MainFrame.h"
@@ -198,13 +200,15 @@
     if (element.styleChangeType() == SyntheticStyleChange)
         update.isSynthetic = true;
 
+    auto* existingStyle = element.renderStyle();
+
     if (&element == m_document.documentElement()) {
         m_documentElementStyle = RenderStyle::clonePtr(*update.style);
         scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
 
         // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
         // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
-        if (m_document.authorStyleSheets().usesRemUnits() && update.change != NoChange && element.renderer() && element.renderer()->style().fontSize() != update.style->fontSize()) {
+        if (m_document.authorStyleSheets().usesRemUnits() && update.change != NoChange && existingStyle && existingStyle->fontSize() != update.style->fontSize()) {
             // Cached RenderStyles may depend on the rem units.
             scope().styleResolver.invalidateMatchedPropertiesCache();
             update.change = Force;
@@ -216,6 +220,12 @@
     if (&element == m_document.body())
         m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
 
+    // FIXME: These elements should not change renderer based on appearance property.
+    if (is<HTMLMeterElement>(element) || is<HTMLProgressElement>(element)) {
+        if (existingStyle && update.style->appearance() != existingStyle->appearance())
+            update.change = Detach;
+    }
+
     if (update.change != Detach && (parent().change == Force || element.styleChangeType() >= FullStyleChange))
         update.change = Force;
 
@@ -341,15 +351,43 @@
         popParent();
 }
 
-static bool shouldResolvePseudoElement(PseudoElement* pseudoElement)
+static bool shouldResolvePseudoElement(const PseudoElement* pseudoElement)
 {
     if (!pseudoElement)
         return false;
-    bool needsStyleRecalc = pseudoElement->needsStyleRecalc();
-    pseudoElement->clearNeedsStyleRecalc();
-    return needsStyleRecalc;
+    return pseudoElement->needsStyleRecalc();
 }
 
+static bool shouldResolveElement(const Element& element, Style::Change parentChange)
+{
+    if (parentChange >= Inherit)
+        return true;
+    if (parentChange == NoInherit) {
+        auto* existingStyle = element.renderStyle();
+        if (existingStyle && existingStyle->hasExplicitlyInheritedProperties())
+            return true;
+    }
+    if (element.needsStyleRecalc())
+        return true;
+    if (element.hasDisplayContents())
+        return true;
+    if (shouldResolvePseudoElement(element.beforePseudoElement()))
+        return true;
+    if (shouldResolvePseudoElement(element.afterPseudoElement()))
+        return true;
+
+    return false;
+}
+
+static void clearNeedsStyleResolution(Element& element)
+{
+    element.clearNeedsStyleRecalc();
+    if (auto* before = element.beforePseudoElement())
+        before->clearNeedsStyleRecalc();
+    if (auto* after = element.afterPseudoElement())
+        after->clearNeedsStyleRecalc();
+}
+
 void TreeResolver::resolveComposedTree()
 {
     ASSERT(m_parentStack.size() == 1);
@@ -395,12 +433,10 @@
         if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
             parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
 
-        bool shouldResolveForPseudoElement = shouldResolvePseudoElement(element.beforePseudoElement()) || shouldResolvePseudoElement(element.afterPseudoElement());
+        auto* style = element.renderStyle();
+        auto change = NoChange;
 
-        const RenderStyle* style;
-        Change change;
-
-        bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || shouldResolveForPseudoElement || affectedByPreviousSibling || element.hasDisplayContents();
+        bool shouldResolve = shouldResolveElement(element, parent.change) || affectedByPreviousSibling;
         if (shouldResolve) {
 #if PLATFORM(IOS)
             CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle());
@@ -428,10 +464,7 @@
             if (elementUpdate.style)
                 m_update->addElement(element, parent.element, WTFMove(elementUpdate));
 
-            element.clearNeedsStyleRecalc();
-        } else {
-            style = element.renderStyle();
-            change = NoChange;
+            clearNeedsStyleResolution(element);
         }
 
         if (!style) {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to