Title: [114265] trunk
Revision
114265
Author
an...@apple.com
Date
2012-04-16 09:37:10 -0700 (Mon, 16 Apr 2012)

Log Message

REGRESSION (r104445): Style is not recomputed on serenaandlily.com
https://bugs.webkit.org/show_bug.cgi?id=83663

Source/WebCore: 

Reviewed by Andreas Kling.
        
CSS class and id selectors are case insensitive in non-strict modes. The code
that invalidated the scope elements used getElementByID() which is case
sensitive in all modes. As a result we would fail to invalidate elements
that would match a style rule but used different case in id.
        
The new code invalidates by crawling the DOM tree. This often (when there are classes) 
actually faster than the existing code as we can now handle everything in a single pass.
Each class scope required a crawl with the old code.
        
The code uses the same functions as the selector matching code to get the same behavior.
        
The maximum class limit is lifted as number of classes does not affect complexity anymore.

Test: fast/css/id-or-class-before-stylesheet-strict.html

* css/SelectorChecker.h:
(WebCore::SelectorChecker::elementMatchesSelectorScopes):
(WebCore):
* dom/Document.cpp:
(WebCore::Document::testAddedStylesheetRequiresStyleRecalc):
(WebCore):

LayoutTests: 

Reviewed by Andreas Kling.
        
Update the existing test with case insensitive comparisons and add a strict mode test.

* fast/css/id-or-class-before-stylesheet-expected.txt:
* fast/css/id-or-class-before-stylesheet-strict-expected.txt: Added.
* fast/css/id-or-class-before-stylesheet-strict.html: Added.
* fast/css/id-or-class-before-stylesheet.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (114264 => 114265)


--- trunk/LayoutTests/ChangeLog	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/LayoutTests/ChangeLog	2012-04-16 16:37:10 UTC (rev 114265)
@@ -1,3 +1,17 @@
+2012-04-15  Antti Koivisto  <an...@apple.com>
+
+        REGRESSION (r104445): Style is not recomputed on serenaandlily.com
+        https://bugs.webkit.org/show_bug.cgi?id=83663
+
+        Reviewed by Andreas Kling.
+        
+        Update the existing test with case insensitive comparisons and add a strict mode test.
+
+        * fast/css/id-or-class-before-stylesheet-expected.txt:
+        * fast/css/id-or-class-before-stylesheet-strict-expected.txt: Added.
+        * fast/css/id-or-class-before-stylesheet-strict.html: Added.
+        * fast/css/id-or-class-before-stylesheet.html:
+
 2012-04-16  Zalan Bujtas  <zbuj...@gmail.com>
 
         [Qt] LayoutTest: Replace setTimeout with synchronous layout for frame flattening where possible.

Modified: trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-expected.txt (114264 => 114265)


--- trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-expected.txt	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-expected.txt	2012-04-16 16:37:10 UTC (rev 114265)
@@ -5,8 +5,12 @@
 
 PASS window.getComputedStyle(document.getElementById("testid")).backgroundColor is "rgb(0, 128, 0)"
 PASS window.getComputedStyle(document.getElementsByClassName("testclass")[0]).backgroundColor is "rgb(0, 128, 0)"
+PASS window.getComputedStyle(document.getElementById("testID2")).backgroundColor is "rgb(0, 128, 0)"
+PASS window.getComputedStyle(document.getElementsByClassName("testClass2")[0]).backgroundColor is "rgb(0, 128, 0)"
 PASS successfullyParsed is true
 
 TEST COMPLETE
 id test
 class test
+case insensitive id test
+case insensitive class test

Added: trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict-expected.txt (0 => 114265)


--- trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict-expected.txt	2012-04-16 16:37:10 UTC (rev 114265)
@@ -0,0 +1,16 @@
+Test that elements before inline stylesheets get their style updated properly
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.getComputedStyle(document.getElementById("testid")).backgroundColor is "rgb(0, 128, 0)"
+PASS window.getComputedStyle(document.getElementsByClassName("testclass")[0]).backgroundColor is "rgb(0, 128, 0)"
+PASS window.getComputedStyle(document.getElementById("testID2")).backgroundColor is "rgb(255, 0, 0)"
+PASS window.getComputedStyle(document.getElementsByClassName("testClass2")[0]).backgroundColor is "rgb(255, 0, 0)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+id test
+class test
+case insensitive id test
+case insensitive class test

Added: trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict.html (0 => 114265)


--- trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css/id-or-class-before-stylesheet-strict.html	2012-04-16 16:37:10 UTC (rev 114265)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html lang=en>
+<head>
+<script src=""
+<style>
+#testid { background-color: red; }
+#testID2 { background-color: red; }
+.testclass { background-color: red; }
+.testClass2 { background-color: red; }
+</style>
+</head>
+<body>
+<div id=testid>id test</div>
+<style>
+#testid { background-color: green }
+</style>
+<div class=testclass>class test</div>
+<style>
+.testclass { background-color: green; }
+</style>
+<div id=testID2>case insensitive id test</div>
+<style>
+#TESTid2 { background-color: green }
+</style>
+<div class=testClass2>case insensitive class test</div>
+<style>
+.TESTclass2 { background-color: green; }
+</style>
+<script>
+description("Test that elements before inline stylesheets get their style updated properly");
+shouldBe('window.getComputedStyle(document.getElementById("testid")).backgroundColor','"rgb(0, 128, 0)"');
+shouldBe('window.getComputedStyle(document.getElementsByClassName("testclass")[0]).backgroundColor','"rgb(0, 128, 0)"');
+shouldBe('window.getComputedStyle(document.getElementById("testID2")).backgroundColor','"rgb(255, 0, 0)"');
+shouldBe('window.getComputedStyle(document.getElementsByClassName("testClass2")[0]).backgroundColor','"rgb(255, 0, 0)"');
+</script>
+<script src=""
+</body>

Modified: trunk/LayoutTests/fast/css/id-or-class-before-stylesheet.html (114264 => 114265)


--- trunk/LayoutTests/fast/css/id-or-class-before-stylesheet.html	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/LayoutTests/fast/css/id-or-class-before-stylesheet.html	2012-04-16 16:37:10 UTC (rev 114265)
@@ -3,7 +3,9 @@
 <script src=""
 <style>
 #testid { background-color: red; }
+#testID2 { background-color: red; }
 .testclass { background-color: red; }
+.testClass2 { background-color: red; }
 </style>
 </head>
 <body>
@@ -15,10 +17,20 @@
 <style>
 .testclass { background-color: green; }
 </style>
+<div id=testID2>case insensitive id test</div>
+<style>
+#TESTid2 { background-color: green }
+</style>
+<div class=testClass2>case insensitive class test</div>
+<style>
+.TESTclass2 { background-color: green; }
+</style>
 <script>
 description("Test that elements before inline stylesheets get their style updated properly");
 shouldBe('window.getComputedStyle(document.getElementById("testid")).backgroundColor','"rgb(0, 128, 0)"');
 shouldBe('window.getComputedStyle(document.getElementsByClassName("testclass")[0]).backgroundColor','"rgb(0, 128, 0)"');
+shouldBe('window.getComputedStyle(document.getElementById("testID2")).backgroundColor','"rgb(0, 128, 0)"');
+shouldBe('window.getComputedStyle(document.getElementsByClassName("testClass2")[0]).backgroundColor','"rgb(0, 128, 0)"');
 </script>
 <script src=""
 </body>

Modified: trunk/Source/WebCore/ChangeLog (114264 => 114265)


--- trunk/Source/WebCore/ChangeLog	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/Source/WebCore/ChangeLog	2012-04-16 16:37:10 UTC (rev 114265)
@@ -1,3 +1,32 @@
+2012-04-16  Antti Koivisto  <an...@apple.com>
+
+        REGRESSION (r104445): Style is not recomputed on serenaandlily.com
+        https://bugs.webkit.org/show_bug.cgi?id=83663
+
+        Reviewed by Andreas Kling.
+        
+        CSS class and id selectors are case insensitive in non-strict modes. The code
+        that invalidated the scope elements used getElementByID() which is case
+        sensitive in all modes. As a result we would fail to invalidate elements
+        that would match a style rule but used different case in id.
+        
+        The new code invalidates by crawling the DOM tree. This often (when there are classes) 
+        actually faster than the existing code as we can now handle everything in a single pass.
+        Each class scope required a crawl with the old code.
+        
+        The code uses the same functions as the selector matching code to get the same behavior.
+        
+        The maximum class limit is lifted as number of classes does not affect complexity anymore.
+
+        Test: fast/css/id-or-class-before-stylesheet-strict.html
+
+        * css/SelectorChecker.h:
+        (WebCore::SelectorChecker::elementMatchesSelectorScopes):
+        (WebCore):
+        * dom/Document.cpp:
+        (WebCore::Document::testAddedStylesheetRequiresStyleRecalc):
+        (WebCore):
+
 2012-04-16  Uday Kiran  <udayki...@motorola.com>
 
         CSS3 Selectors failures on css3test.com

Modified: trunk/Source/WebCore/css/SelectorChecker.h (114264 => 114265)


--- trunk/Source/WebCore/css/SelectorChecker.h	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2012-04-16 16:37:10 UTC (rev 114265)
@@ -30,10 +30,11 @@
 
 #include "Attribute.h"
 #include "CSSSelector.h"
-#include "Element.h"
 #include "InspectorInstrumentation.h"
 #include "LinkHash.h"
 #include "RenderStyleConstants.h"
+#include "SpaceSplitString.h"
+#include "StyledElement.h"
 #include <wtf/BloomFilter.h>
 #include <wtf/HashSet.h>
 #include <wtf/Vector.h>
@@ -116,6 +117,7 @@
 
     // Find the ids or classes selectors are scoped to. The selectors only apply to elements in subtrees where the root element matches the scope.
     static bool determineSelectorScopes(const CSSSelectorList&, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes);
+    static bool elementMatchesSelectorScopes(const StyledElement*, const HashSet<AtomicStringImpl*>& idScopes, const HashSet<AtomicStringImpl*>& classScopes);
 
 private:
     bool checkOneSelector(const SelectorCheckingContext&, PseudoId&) const;
@@ -226,6 +228,20 @@
     return true;
 }
 
+inline bool SelectorChecker::elementMatchesSelectorScopes(const StyledElement* element, const HashSet<AtomicStringImpl*>& idScopes, const HashSet<AtomicStringImpl*>& classScopes)
+{
+    if (!idScopes.isEmpty() && element->hasID() && idScopes.contains(element->idForStyleResolution().impl()))
+        return true;
+    if (classScopes.isEmpty() || !element->hasClass())
+        return false;
+    const SpaceSplitString& classNames = element->classNames();
+    for (unsigned i = 0; i < classNames.size(); ++i) {
+        if (classScopes.contains(classNames[i].impl()))
+            return true;
+    }
+    return false;
 }
 
+}
+
 #endif

Modified: trunk/Source/WebCore/dom/Document.cpp (114264 => 114265)


--- trunk/Source/WebCore/dom/Document.cpp	2012-04-16 15:56:42 UTC (rev 114264)
+++ trunk/Source/WebCore/dom/Document.cpp	2012-04-16 16:37:10 UTC (rev 114265)
@@ -3333,36 +3333,29 @@
 {
     // See if all rules on the sheet are scoped to some specific ids or classes.
     // Then test if we actually have any of those in the tree at the moment.
-    // FIXME: Even we if we find some, we could just invalidate those subtrees instead of invalidating the entire style.
     HashSet<AtomicStringImpl*> idScopes; 
     HashSet<AtomicStringImpl*> classScopes;
     if (!CSSStyleSelector::determineStylesheetSelectorScopes(stylesheet, idScopes, classScopes))
         return true;
-    // Testing for classes is not particularly fast so bail out if there are more than a few.
-    static const int maximumClassScopesToTest = 4;
-    if (classScopes.size() > maximumClassScopesToTest)
-        return true;
-    HashSet<AtomicStringImpl*>::iterator end = idScopes.end();
-    for (HashSet<AtomicStringImpl*>::iterator it = idScopes.begin(); it != end; ++it) {
-        AtomicStringImpl* id = *it;
-        Element* idElement = getElementById(id);
-        if (!idElement)
+    // Invalidate the subtrees that match the scopes.
+    Node* node = firstChild();
+    while (node) {
+        if (!node->isStyledElement()) {
+            node = node->traverseNextNode();
             continue;
-        if (containsMultipleElementsWithId(id))
-            return true;
-        idElement->setNeedsStyleRecalc();
+        }
+        StyledElement* element = static_cast<StyledElement*>(node);
+        if (SelectorChecker::elementMatchesSelectorScopes(element, idScopes, classScopes)) {
+            element->setNeedsStyleRecalc();
+            // The whole subtree is now invalidated, we can skip to the next sibling.
+            node = node->traverseNextSibling();
+            continue;
+        }
+        node = node->traverseNextNode();
     }
-    end = classScopes.end();
-    for (HashSet<AtomicStringImpl*>::iterator it = classScopes.begin(); it != end; ++it) {
-        // FIXME: getElementsByClassName is not optimal for this. We should handle all classes in a single pass.
-        RefPtr<NodeList> classElements = getElementsByClassName(*it);
-        unsigned elementCount = classElements->length();
-        for (unsigned i = 0; i < elementCount; ++i)
-            classElements->item(i)->setNeedsStyleRecalc();
-    }
     return false;
 }
-    
+
 void Document::analyzeStylesheetChange(StyleSelectorUpdateFlag updateFlag, const Vector<RefPtr<StyleSheet> >& newStylesheets, bool& requiresStyleSelectorReset, bool& requiresFullStyleRecalc)
 {
     requiresStyleSelectorReset = true;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to