- 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) {