Bug 75508

Summary: Analyze stylesheet scope to minimize style recalcs
Product: WebKit Reporter: Antti Koivisto <koivisto>
Component: CSSAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: dglazkov, hyatt, kling, macpherson, manyoso, mihaip, phiw2, pnormand, rolandsteiner, sam, staikos, tonikitoo, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
patch
webkit.review.bot: commit-queue-
Chromium build fix plus some cleanups
none
update to tot hyatt: review+

Description Antti Koivisto 2012-01-03 18:22:50 PST
It is a relatively common pattern to use inline stylesheets in document body where all rules are scoped using descendant selector

<style>
#foo {...}
#foo div {...}
#foo .bar {...}
</style>

When this pattern is used it is also common that the rules only apply to elements that come after the style element. 

When the set of active stylesheets changes we invalidate and recompute the entire document style. This is very expensive.  We can detect the case above and avoid the style recalc.
Comment 1 Antti Koivisto 2012-01-03 18:58:57 PST
Created attachment 121038 [details]
patch

On engadget.com, this patch cuts the time spent in style recalcs to roughly half. There are further savings from reduced relayouts. In total the engine CPU time used over the page load is reduced by ~10%.
Comment 2 WebKit Review Bot 2012-01-03 19:40:54 PST
Comment on attachment 121038 [details]
patch

Attachment 121038 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/11082256
Comment 3 Antti Koivisto 2012-01-04 08:18:11 PST
Created attachment 121113 [details]
Chromium build fix plus some cleanups
Comment 4 Antti Koivisto 2012-01-04 09:00:02 PST
Created attachment 121115 [details]
update to tot
Comment 5 Dave Hyatt 2012-01-04 09:28:35 PST
Comment on attachment 121115 [details]
update to tot

I think RecalcStyleOnlyifNeeded would be better than PendingStylesheetCompleted.

r=me
Comment 6 Antti Koivisto 2012-01-04 10:55:26 PST
<rdar://problem/10643107>
Comment 7 Antti Koivisto 2012-01-04 12:05:28 PST
http://trac.webkit.org/changeset/104060
Comment 8 Philippe Normand 2012-01-05 07:02:43 PST
(In reply to comment #7)
> http://trac.webkit.org/changeset/104060

It seems this patch broke a test in GTK: http://build.webkit.org/results/GTK%20Linux%2064-bit%20Release/r104153%20(15719)/fast/forms/textarea-metrics-diff.txt

--- /home/slave/webkitgtk/gtk-linux-64-release/build/layout-test-results/fast/forms/textarea-metrics-expected.txt 
+++ /home/slave/webkitgtk/gtk-linux-64-release/build/layout-test-results/fast/forms/textarea-metrics-actual.txt 
@@ -88,84 +88,84 @@
 
 Testing CSS1Compat document.
 Properties = none
-PASS CSS1Compatdoc.getElementById('no-styles').clientWidth is 54
-PASS CSS1Compatdoc.getElementById('no-styles').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('no-styles').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('no-styles').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('no-styles').scrollWidth is 54
-PASS CSS1Compatdoc.getElementById('no-styles').scrollHeight is 54
+FAIL CSS1Compatdoc.getElementById('no-styles').clientWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('no-styles').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('no-styles').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('no-styles').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('no-styles').scrollWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('no-styles').scrollHeight should be 54. Was 48.
 
 Properties = disabled: "true",
-PASS CSS1Compatdoc.getElementById('-disabled-true-').clientWidth is 54
-PASS CSS1Compatdoc.getElementById('-disabled-true-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-disabled-true-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-disabled-true-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-disabled-true-').scrollWidth is 54
-PASS CSS1Compatdoc.getElementById('-disabled-true-').scrollHeight is 54
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').clientWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').scrollWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-disabled-true-').scrollHeight should be 54. Was 48.
 
 Properties = innerHTML: "A",
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').clientWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').scrollWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-').scrollHeight is 54
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').clientWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').scrollWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-').scrollHeight should be 54. Was 48.
 
 Properties = innerHTML: "AAAAAAAAA",
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').clientWidth is 37
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').scrollWidth is 37
-FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').scrollHeight should be 64. Was 104.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').clientWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').scrollWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-').scrollHeight should be 64. Was 184.
 
 Properties = innerHTML: "A", disabled: "true",
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').clientWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').scrollWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').scrollHeight is 54
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').clientWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').scrollWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-disabled-true-').scrollHeight should be 54. Was 48.
 
 Properties = innerHTML: "AAAAAAAAA", disabled: "true",
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').clientWidth is 37
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').scrollWidth is 37
-FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').scrollHeight should be 64. Was 104.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').clientWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').scrollWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-disabled-true-').scrollHeight should be 64. Was 184.
 
 Properties = innerHTML: "A", style: "padding:8px",
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').clientWidth is 66
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').clientHeight is 66
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').offsetWidth is 68
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').offsetHeight is 68
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').scrollWidth is 66
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').scrollHeight is 66
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').clientWidth should be 66. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').clientHeight should be 66. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').offsetWidth should be 68. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').offsetHeight should be 68. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').scrollWidth should be 66. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-style-padding-8px-').scrollHeight should be 66. Was 48.
 
 Properties = innerHTML: "AAAAAAAAA", style: "padding:8px",
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').clientWidth is 49
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').clientHeight is 66
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').offsetWidth is 68
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').offsetHeight is 68
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').scrollWidth is 49
-FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').scrollHeight should be 76. Was 116.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').clientWidth should be 49. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').clientHeight should be 66. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').offsetWidth should be 68. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').offsetHeight should be 68. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').scrollWidth should be 49. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-style-padding-8px-').scrollHeight should be 76. Was 196.
 
 Properties = innerHTML: "A", rows: "10",
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').clientWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').scrollWidth is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').scrollHeight is 54
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').clientWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').scrollWidth should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-A-rows-10-').scrollHeight should be 54. Was 48.
 
 Properties = innerHTML: "AAAAAAAAA", rows: "10",
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').clientWidth is 37
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').clientHeight is 54
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').offsetWidth is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').offsetHeight is 56
-PASS CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').scrollWidth is 37
-FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').scrollHeight should be 64. Was 104.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').clientWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').clientHeight should be 54. Was 48.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').offsetWidth should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').offsetHeight should be 56. Was 50.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').scrollWidth should be 37. Was 31.
+FAIL CSS1Compatdoc.getElementById('-innerHTML-AAAAAAAAA-rows-10-').scrollHeight should be 64. Was 184.
 
 PASS successfullyParsed is true
Comment 9 Antti Koivisto 2012-01-05 12:40:37 PST
Filed bug 75644: REGRESSION (r104060): fast/forms/textarea-metrics.html.

Philippe, next time please file a new bug instead of pasting stuff to the bug you think is causing the regression.
Comment 10 Philippe Wittenbergh 2012-01-06 23:30:38 PST
Did this cause bug 75772 ?
Comment 11 Mihai Parparita 2012-01-18 14:49:08 PST
FWIW, this causes http://crbug.com/109888. I'll see if I can create a reduced test case, and file a separate bug.
Comment 12 Mihai Parparita 2012-01-19 07:26:37 PST
(In reply to comment #11)
> FWIW, this causes http://crbug.com/109888. I'll see if I can create a reduced test case, and file a separate bug.

I filed https://bugs.webkit.org/show_bug.cgi?id=76590