Inserting multiple rules into an empty style sheet should avoid style recalc if possible.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Aug 2013 17:41:11 +0000 (17:41 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Aug 2013 17:41:11 +0000 (17:41 +0000)
<http://webkit.org/b/119568>

Reviewed by Antti Koivisto.

As a follow-up to <http://webkit.org/b/119475>, where I added a hack for inserting
a single rule into an empty style sheet, this broadens the optimization to support
any number of rules.

This optimizes the scenario where a style sheet is added to the DOM and then populated
rule-by-rule via CSSOM insertRule()/addRule() calls. Previously we'd do a full style
recalc for this case, but now we'll treat it the same as a full sheet added at once.

* css/CSSStyleSheet.h:
* css/CSSStyleSheet.cpp:
(WebCore::CSSStyleSheet::willMutateRules):

    Made willMutateRules() return whether the style sheet contents were cloned by the
    copy-on-write mechanism.

* dom/Document.h:
(WebCore::CSSStyleSheet::didMutateRules):
(WebCore::CSSStyleSheet::insertRule):

    Replaced the InsertionIntoEmptySheet mutation type by a general RuleInsertion.
    The mutation callback checks if we're inserting into a rule that's not (yet) part
    of the document's active sheet set. In that case, we defer doing the style sheet
    until all the insertions are done (or something forces us to style+layout.)

    Note that this optimization only happens if the style sheet had a single client.
    Shared style sheets that just got cloned before mutation may have pointers into
    them from the Document's StyleResolver, so we're forced to do an immediate sheet
    update in that case.

(WebCore::CSSStyleSheet::RuleMutationScope::RuleMutationScope):
(WebCore::CSSStyleSheet::RuleMutationScope::~RuleMutationScope):

    Moved these out-of-line.

(WebCore::CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration):
* css/PropertySetCSSStyleDeclaration.cpp:
(WebCore::StyleRuleCSSStyleDeclaration::didMutate):

    Made a separate mutation callback for CSSStyleDeclaration since its needs are
    so simple compared to the mutation callback from CSSStyleSheet. Seems better
    than adding yet another mode to the enum.

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::recalcStyle):
(WebCore::Document::styleResolverChanged):
(WebCore::Document::optimizedStyleSheetUpdateTimerFired):
(WebCore::Document::scheduleOptimizedStyleSheetUpdate):

    Added mechanism to defer doing a RecalcStyleIfNeeded.

(WebCore::Document::updateStyleIfNeeded):

    Synchronize the optimized style sheet update if there's one scheduled.
    This ensures that stuff like layout-dependent property access won't operate
    on stale style.

* dom/DocumentStyleSheetCollection.h:
(WebCore::DocumentStyleSheetCollection::pendingUpdateType):
(WebCore::DocumentStyleSheetCollection::setPendingUpdateType):
(WebCore::DocumentStyleSheetCollection::flushPendingUpdates):
* dom/DocumentStyleSheetCollection.cpp:
(WebCore::DocumentStyleSheetCollection::DocumentStyleSheetCollection):
(WebCore::DocumentStyleSheetCollection::updateActiveStyleSheets):

    Have DSSC track the kind of style sheet update it needs to do (instead of just
    a boolean "needs update.") This is used by Document::recalcStyle() to make sure
    the right kind of update happens if there's one scheduled.

(WebCore::DocumentStyleSheetCollection::activeStyleSheetsContains):

    Added helper to check if a CSSStyleSheet is part of the active set.

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

Source/WebCore/ChangeLog
Source/WebCore/css/CSSStyleSheet.cpp
Source/WebCore/css/CSSStyleSheet.h
Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/DocumentStyleSheetCollection.cpp
Source/WebCore/dom/DocumentStyleSheetCollection.h

index aff3e2e..1af382b 100644 (file)
@@ -1,3 +1,83 @@
+2013-08-08  Andreas Kling  <akling@apple.com>
+
+        Inserting multiple rules into an empty style sheet should avoid style recalc if possible.
+        <http://webkit.org/b/119568>
+
+        Reviewed by Antti Koivisto.
+
+        As a follow-up to <http://webkit.org/b/119475>, where I added a hack for inserting
+        a single rule into an empty style sheet, this broadens the optimization to support
+        any number of rules.
+
+        This optimizes the scenario where a style sheet is added to the DOM and then populated
+        rule-by-rule via CSSOM insertRule()/addRule() calls. Previously we'd do a full style
+        recalc for this case, but now we'll treat it the same as a full sheet added at once.
+
+        * css/CSSStyleSheet.h:
+        * css/CSSStyleSheet.cpp:
+        (WebCore::CSSStyleSheet::willMutateRules):
+
+            Made willMutateRules() return whether the style sheet contents were cloned by the
+            copy-on-write mechanism.
+
+        * dom/Document.h:
+        (WebCore::CSSStyleSheet::didMutateRules):
+        (WebCore::CSSStyleSheet::insertRule):
+
+            Replaced the InsertionIntoEmptySheet mutation type by a general RuleInsertion.
+            The mutation callback checks if we're inserting into a rule that's not (yet) part
+            of the document's active sheet set. In that case, we defer doing the style sheet
+            until all the insertions are done (or something forces us to style+layout.)
+
+            Note that this optimization only happens if the style sheet had a single client.
+            Shared style sheets that just got cloned before mutation may have pointers into
+            them from the Document's StyleResolver, so we're forced to do an immediate sheet
+            update in that case.
+
+        (WebCore::CSSStyleSheet::RuleMutationScope::RuleMutationScope):
+        (WebCore::CSSStyleSheet::RuleMutationScope::~RuleMutationScope):
+
+            Moved these out-of-line.
+
+        (WebCore::CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration):
+        * css/PropertySetCSSStyleDeclaration.cpp:
+        (WebCore::StyleRuleCSSStyleDeclaration::didMutate):
+
+            Made a separate mutation callback for CSSStyleDeclaration since its needs are
+            so simple compared to the mutation callback from CSSStyleSheet. Seems better
+            than adding yet another mode to the enum.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::recalcStyle):
+        (WebCore::Document::styleResolverChanged):
+        (WebCore::Document::optimizedStyleSheetUpdateTimerFired):
+        (WebCore::Document::scheduleOptimizedStyleSheetUpdate):
+
+            Added mechanism to defer doing a RecalcStyleIfNeeded.
+
+        (WebCore::Document::updateStyleIfNeeded):
+
+            Synchronize the optimized style sheet update if there's one scheduled.
+            This ensures that stuff like layout-dependent property access won't operate
+            on stale style.
+
+        * dom/DocumentStyleSheetCollection.h:
+        (WebCore::DocumentStyleSheetCollection::pendingUpdateType):
+        (WebCore::DocumentStyleSheetCollection::setPendingUpdateType):
+        (WebCore::DocumentStyleSheetCollection::flushPendingUpdates):
+        * dom/DocumentStyleSheetCollection.cpp:
+        (WebCore::DocumentStyleSheetCollection::DocumentStyleSheetCollection):
+        (WebCore::DocumentStyleSheetCollection::updateActiveStyleSheets):
+
+            Have DSSC track the kind of style sheet update it needs to do (instead of just
+            a boolean "needs update.") This is used by Document::recalcStyle() to make sure
+            the right kind of update happens if there's one scheduled.
+
+        (WebCore::DocumentStyleSheetCollection::activeStyleSheetsContains):
+
+            Added helper to check if a CSSStyleSheet is part of the active set.
+
 2013-08-08  Allan Sandfeld Jensen  <allan.jensen@digia.com>
 
         [WK1] NPStream::headers not initialized
index 3af1cdd..59ff98e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2006, 2007, 2012, 2013 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -29,6 +29,7 @@
 #include "CSSStyleRule.h"
 #include "CachedCSSStyleSheet.h"
 #include "Document.h"
+#include "DocumentStyleSheetCollection.h"
 #include "ExceptionCode.h"
 #include "HTMLNames.h"
 #include "HTMLStyleElement.h"
@@ -126,12 +127,12 @@ CSSStyleSheet::~CSSStyleSheet()
     m_contents->unregisterClient(this);
 }
 
-void CSSStyleSheet::willMutateRules()
+CSSStyleSheet::WhetherContentsWereClonedForMutation CSSStyleSheet::willMutateRules()
 {
     // If we are the only client it is safe to mutate.
     if (m_contents->hasOneClient() && !m_contents->isInMemoryCache()) {
         m_contents->setMutable();
-        return;
+        return ContentsWereNotClonedForMutation;
     }
     // Only cacheable stylesheets should have multiple clients.
     ASSERT(m_contents->isCacheable());
@@ -145,9 +146,18 @@ void CSSStyleSheet::willMutateRules()
 
     // Any existing CSSOM wrappers need to be connected to the copied child rules.
     reattachChildRuleCSSOMWrappers();
+
+    return ContentsWereClonedForMutation;
 }
 
-void CSSStyleSheet::didMutateRules(RuleMutationType mutationType)
+void CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration()
+{
+    ASSERT(m_contents->isMutable());
+    ASSERT(m_contents->hasOneClient());
+    didMutate();
+}
+
+void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation)
 {
     ASSERT(m_contents->isMutable());
     ASSERT(m_contents->hasOneClient());
@@ -155,7 +165,13 @@ void CSSStyleSheet::didMutateRules(RuleMutationType mutationType)
     Document* owner = ownerDocument();
     if (!owner)
         return;
-    owner->styleResolverChanged(mutationType == InsertionIntoEmptySheet ? DeferRecalcStyleIfNeeded : DeferRecalcStyle);
+
+    if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !owner->styleSheetCollection()->activeStyleSheetsContains(this)) {
+        owner->scheduleOptimizedStyleSheetUpdate();
+        return;
+    }
+
+    owner->styleResolverChanged(DeferRecalcStyle);
 }
 
 void CSSStyleSheet::didMutate()
@@ -279,8 +295,7 @@ unsigned CSSStyleSheet::insertRule(const String& ruleString, unsigned index, Exc
         return 0;
     }
 
-    RuleMutationType mutationType = !length() ? InsertionIntoEmptySheet : OtherMutation;
-    RuleMutationScope mutationScope(this, mutationType);
+    RuleMutationScope mutationScope(this, RuleInsertion);
 
     bool success = m_contents->wrapperInsertRule(rule, index);
     if (!success) {
@@ -386,4 +401,27 @@ void CSSStyleSheet::clearChildRuleCSSOMWrappers()
     m_childRuleCSSOMWrappers.clear();
 }
 
+CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType)
+    : m_styleSheet(sheet)
+    , m_mutationType(mutationType)
+{
+    ASSERT(m_styleSheet);
+    m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
+}
+
+CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
+    : m_styleSheet(rule ? rule->parentStyleSheet() : 0)
+    , m_mutationType(OtherMutation)
+    , m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation)
+{
+    if (m_styleSheet)
+        m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
+}
+
+CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
+{
+    if (m_styleSheet)
+        m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation);
+}
+
 }
index 07f164a..6937592 100644 (file)
@@ -85,7 +85,8 @@ public:
     void setMediaQueries(PassRefPtr<MediaQuerySet>);
     void setTitle(const String& title) { m_title = title; }
 
-    enum RuleMutationType { OtherMutation, InsertionIntoEmptySheet };
+    enum RuleMutationType { OtherMutation, RuleInsertion };
+    enum WhetherContentsWereClonedForMutation { ContentsWereNotClonedForMutation = 0, ContentsWereClonedForMutation };
 
     class RuleMutationScope {
         WTF_MAKE_NONCOPYABLE(RuleMutationScope);
@@ -97,10 +98,12 @@ public:
     private:
         CSSStyleSheet* m_styleSheet;
         RuleMutationType m_mutationType;
+        WhetherContentsWereClonedForMutation m_contentsWereClonedForMutation;
     };
 
-    void willMutateRules();
-    void didMutateRules(RuleMutationType = OtherMutation);
+    WhetherContentsWereClonedForMutation willMutateRules();
+    void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation);
+    void didMutateRuleFromCSSStyleDeclaration();
     void didMutate();
     
     void clearChildRuleCSSOMWrappers();
@@ -131,28 +134,6 @@ private:
     mutable OwnPtr<CSSRuleList> m_ruleListCSSOMWrapper;
 };
 
-inline CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType)
-    : m_styleSheet(sheet)
-    , m_mutationType(mutationType)
-{
-    if (m_styleSheet)
-        m_styleSheet->willMutateRules();
-}
-
-inline CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
-    : m_styleSheet(rule ? rule->parentStyleSheet() : 0)
-    , m_mutationType(OtherMutation)
-{
-    if (m_styleSheet)
-        m_styleSheet->willMutateRules();
-}
-
-inline CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
-{
-    if (m_styleSheet)
-        m_styleSheet->didMutateRules(m_mutationType);
-}
-
 } // namespace
 
 #endif
index 9499eae..eaa24b2 100644 (file)
@@ -331,9 +331,9 @@ void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
     if (type == PropertyChanged)
         m_cssomCSSValueClones.clear();
 
-    // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
+    // Style sheet mutation needs to be signaled even if the change failed. willMutate*/didMutate* must pair.
     if (m_parentRule && m_parentRule->parentStyleSheet())
-        m_parentRule->parentStyleSheet()->didMutateRules();
+        m_parentRule->parentStyleSheet()->didMutateRuleFromCSSStyleDeclaration();
 }
 
 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
index 03aed7a..1acee17 100644 (file)
@@ -412,6 +412,7 @@ Document::Document(Frame* frame, const KURL& url, unsigned documentClasses)
     , m_visuallyOrdered(false)
     , m_readyState(Complete)
     , m_bParsing(false)
+    , m_optimizedStyleSheetUpdateTimer(this, &Document::optimizedStyleSheetUpdateTimerFired)
     , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
     , m_pendingStyleRecalcShouldForce(false)
     , m_inStyleRecalc(false)
@@ -1759,8 +1760,7 @@ void Document::recalcStyle(Style::Change change)
     // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed
     // hits a null-dereference due to security code always assuming the document has a SecurityOrigin.
 
-    if (m_styleSheetCollection->needsUpdateActiveStylesheetsOnStyleRecalc())
-        m_styleSheetCollection->updateActiveStyleSheets(DocumentStyleSheetCollection::FullUpdate);
+    m_styleSheetCollection->flushPendingUpdates();
 
     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
 
@@ -1845,7 +1845,10 @@ void Document::updateStyleIfNeeded()
 {
     ASSERT(isMainThread());
     ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
-    
+
+    if (m_optimizedStyleSheetUpdateTimer.isActive())
+        styleResolverChanged(RecalcStyleIfNeeded);
+
     if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache())
         return;
 
@@ -3135,8 +3138,24 @@ void Document::evaluateMediaQueryList()
         m_mediaQueryMatcher->styleResolverChanged();
 }
 
+void Document::optimizedStyleSheetUpdateTimerFired(Timer<Document>*)
+{
+    styleResolverChanged(RecalcStyleIfNeeded);
+}
+
+void Document::scheduleOptimizedStyleSheetUpdate()
+{
+    if (m_optimizedStyleSheetUpdateTimer.isActive())
+        return;
+    styleSheetCollection()->setPendingUpdateType(DocumentStyleSheetCollection::OptimizedUpdate);
+    m_optimizedStyleSheetUpdateTimer.startOneShot(0);
+}
+
 void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag)
 {
+    if (m_optimizedStyleSheetUpdateTimer.isActive())
+        m_optimizedStyleSheetUpdateTimer.stop();
+
     // Don't bother updating, since we haven't loaded all our style info yet
     // and haven't calculated the style selector for the first time.
     if (!attached() || (!m_didCalculateStyleResolver && !haveStylesheetsLoaded())) {
index 4548b1e..6ee9f4c 100644 (file)
@@ -481,6 +481,8 @@ public:
      */
     void styleResolverChanged(StyleResolverUpdateFlag);
 
+    void scheduleOptimizedStyleSheetUpdate();
+
     void didAccessStyleResolver();
 
     void evaluateMediaQueryList();
@@ -690,6 +692,7 @@ public:
     bool hasPendingStyleRecalc() const;
     bool hasPendingForcedStyleRecalc() const;
     void styleRecalcTimerFired(Timer<Document>*);
+    void optimizedStyleSheetUpdateTimerFired(Timer<Document>*);
 
     void registerNodeList(LiveNodeListBase*);
     void unregisterNodeList(LiveNodeListBase*);
@@ -1355,7 +1358,8 @@ private:
     bool m_visuallyOrdered;
     ReadyState m_readyState;
     bool m_bParsing;
-    
+
+    Timer<Document> m_optimizedStyleSheetUpdateTimer;
     Timer<Document> m_styleRecalcTimer;
     bool m_pendingStyleRecalcShouldForce;
     bool m_inStyleRecalc;
index 049d6c7..bedfec9 100644 (file)
@@ -58,7 +58,7 @@ DocumentStyleSheetCollection::DocumentStyleSheetCollection(Document* document)
     , m_pendingStylesheets(0)
     , m_injectedStyleSheetCacheValid(false)
     , m_hadActiveLoadingStylesheet(false)
-    , m_needsUpdateActiveStylesheetsOnStyleRecalc(false)
+    , m_pendingUpdateType(NoUpdate)
     , m_usesSiblingRules(false)
     , m_usesSiblingRulesOverride(false)
     , m_usesFirstLineRules(false)
@@ -459,7 +459,7 @@ bool DocumentStyleSheetCollection::updateActiveStyleSheets(UpdateFlag updateFlag
         // SVG <use> element may manage to invalidate style selector in the middle of a style recalc.
         // https://bugs.webkit.org/show_bug.cgi?id=54344
         // FIXME: This should be fixed in SVG and the call site replaced by ASSERT(!m_inStyleRecalc).
-        m_needsUpdateActiveStylesheetsOnStyleRecalc = true;
+        m_pendingUpdateType = FullUpdate;
         m_document->scheduleForcedStyleRecalc();
         return false;
 
@@ -493,15 +493,27 @@ bool DocumentStyleSheetCollection::updateActiveStyleSheets(UpdateFlag updateFlag
         }
         resetCSSFeatureFlags();
     }
+
+    m_weakCopyOfActiveStyleSheetListForFastLookup.clear();
     m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
     m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
 
     m_usesRemUnits = styleSheetsUseRemUnits(m_activeAuthorStyleSheets);
-    m_needsUpdateActiveStylesheetsOnStyleRecalc = false;
+    m_pendingUpdateType = NoUpdate;
 
     m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
 
     return requiresFullStyleRecalc;
 }
 
+bool DocumentStyleSheetCollection::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
+{
+    if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
+        m_weakCopyOfActiveStyleSheetListForFastLookup = adoptPtr(new HashSet<const CSSStyleSheet*>);
+        for (unsigned i = 0; i < m_activeAuthorStyleSheets.size(); ++i)
+            m_weakCopyOfActiveStyleSheetListForFastLookup->add(m_activeAuthorStyleSheets[i].get());
+    }
+    return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
+}
+
 }
index 6a9ca4d..a9c6b4c 100644 (file)
@@ -71,9 +71,21 @@ public:
     void addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet);
     void addUserSheet(PassRefPtr<StyleSheetContents> userSheet);
 
-    bool needsUpdateActiveStylesheetsOnStyleRecalc() const { return m_needsUpdateActiveStylesheetsOnStyleRecalc; }
+    enum UpdateFlag { NoUpdate = 0, OptimizedUpdate, FullUpdate };
+
+    UpdateFlag pendingUpdateType() const { return m_pendingUpdateType; }
+    void setPendingUpdateType(UpdateFlag updateType)
+    {
+        if (updateType > m_pendingUpdateType)
+            m_pendingUpdateType = updateType;
+    }
+
+    void flushPendingUpdates()
+    {
+        if (m_pendingUpdateType != NoUpdate)
+            updateActiveStyleSheets(m_pendingUpdateType);
+    }
 
-    enum UpdateFlag { FullUpdate, OptimizedUpdate };
     bool updateActiveStyleSheets(UpdateFlag);
 
     String preferredStylesheetSetName() const { return m_preferredStylesheetSetName; }
@@ -103,6 +115,8 @@ public:
     void combineCSSFeatureFlags();
     void resetCSSFeatureFlags();
 
+    bool activeStyleSheetsContains(const CSSStyleSheet*) const;
+
 private:
     DocumentStyleSheetCollection(Document*);
 
@@ -119,6 +133,9 @@ private:
     Vector<RefPtr<StyleSheet> > m_styleSheetsForStyleSheetList;
     Vector<RefPtr<CSSStyleSheet> > m_activeAuthorStyleSheets;
 
+    // This is a mirror of m_activeAuthorStyleSheets that gets populated on demand for activeStyleSheetsContains().
+    mutable OwnPtr<HashSet<const CSSStyleSheet*>> m_weakCopyOfActiveStyleSheetListForFastLookup;
+
     // Track the number of currently loading top-level stylesheets needed for rendering.
     // Sheets loaded using the @import directive are not included in this count.
     // We use this count of pending sheets to detect when we can begin attaching
@@ -135,7 +152,7 @@ private:
     Vector<RefPtr<CSSStyleSheet> > m_authorStyleSheets;
 
     bool m_hadActiveLoadingStylesheet;
-    bool m_needsUpdateActiveStylesheetsOnStyleRecalc;
+    UpdateFlag m_pendingUpdateType;
 
     typedef ListHashSet<Node*, 32> StyleSheetCandidateListHashSet;
     StyleSheetCandidateListHashSet m_styleSheetCandidateNodes;