Changeset 96393 in webkit


Ignore:
Timestamp:
Sep 30, 2011 12:07:17 AM (13 years ago)
Author:
Antti Koivisto
Message:

https://bugs.webkit.org/show_bug.cgi?id=69106
Universal attribute selectors disable style sharing

Reviewed by Dave Hyatt.

Selectors of type [foo="bar"] ended up marking every element style with the affectedByAttributeSelectors bit
rendering style sharing inoperative. This happens on http://www.whatwg.org/specs/web-apps/current-work/ for example.

Instead we now mark style with affectedByUncommonAttributeSelectors bit only if an attribute selector actually
matches the element. Before sharing, we also check the current element against collected attribute rules.
We can share the style if neither element was affected.

This speeds up style matching and applying ~15% on full HTML5 spec (=~0.7s). Sharing percentage goes from 0% to ~30%.
Increased sharing should also save a substantial amount of memory.

  • css/CSSSelector.h:

(WebCore::CSSSelector::isAttributeSelector):

  • css/CSSStyleSelector.cpp:

(WebCore::RuleData::containsUncommonAttributeSelector):
(WebCore::collectSpecialRulesInDefaultStyle):
(WebCore::assertNoSiblingRulesInDefaultStyle):
(WebCore::CSSStyleSelector::CSSStyleSelector):
(WebCore::CSSStyleSelector::matchRules):
(WebCore::CSSStyleSelector::matchesRuleSet):
(WebCore::CSSStyleSelector::canShareStyleWithElement):
(WebCore::CSSStyleSelector::locateSharedStyle):
(WebCore::CSSStyleSelector::styleForElement):
(WebCore::selectorListContainsUncommonAttributeSelector):
(WebCore::isCommonAttributeSelectorAttribute):
(WebCore::containsUncommonAttributeSelector):
(WebCore::RuleData::RuleData):
(WebCore::collectFeaturesFromSelector):
(WebCore::collectFeaturesFromList):

  • css/CSSStyleSelector.h:
  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::checkOneSelector):

  • rendering/style/RenderStyle.cpp:

(WebCore::RenderStyle::RenderStyle):

  • rendering/style/RenderStyle.h:

(WebCore::InheritedFlags::affectedByUncommonAttributeSelectors):
(WebCore::InheritedFlags::setAffectedByUncommonAttributeSelectors):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r96392 r96393  
     12011-09-29  Antti Koivisto  <antti@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=69106
     4        Universal attribute selectors disable style sharing
     5
     6        Reviewed by Dave Hyatt.
     7
     8        Selectors of type [foo="bar"] ended up marking every element style with the affectedByAttributeSelectors bit
     9        rendering style sharing inoperative. This happens on http://www.whatwg.org/specs/web-apps/current-work/ for example.
     10
     11        Instead we now mark style with affectedByUncommonAttributeSelectors bit only if an attribute selector actually
     12        matches the element. Before sharing, we also check the current element against collected attribute rules.
     13        We can share the style if neither element was affected.
     14       
     15        This speeds up style matching and applying ~15% on full HTML5 spec (=~0.7s). Sharing percentage goes from 0% to ~30%.
     16        Increased sharing should also save a substantial amount of memory.
     17
     18        * css/CSSSelector.h:
     19        (WebCore::CSSSelector::isAttributeSelector):
     20        * css/CSSStyleSelector.cpp:
     21        (WebCore::RuleData::containsUncommonAttributeSelector):
     22        (WebCore::collectSpecialRulesInDefaultStyle):
     23        (WebCore::assertNoSiblingRulesInDefaultStyle):
     24        (WebCore::CSSStyleSelector::CSSStyleSelector):
     25        (WebCore::CSSStyleSelector::matchRules):
     26        (WebCore::CSSStyleSelector::matchesRuleSet):
     27        (WebCore::CSSStyleSelector::canShareStyleWithElement):
     28        (WebCore::CSSStyleSelector::locateSharedStyle):
     29        (WebCore::CSSStyleSelector::styleForElement):
     30        (WebCore::selectorListContainsUncommonAttributeSelector):
     31        (WebCore::isCommonAttributeSelectorAttribute):
     32        (WebCore::containsUncommonAttributeSelector):
     33        (WebCore::RuleData::RuleData):
     34        (WebCore::collectFeaturesFromSelector):
     35        (WebCore::collectFeaturesFromList):
     36        * css/CSSStyleSelector.h:
     37        * css/SelectorChecker.cpp:
     38        (WebCore::SelectorChecker::checkOneSelector):
     39        * rendering/style/RenderStyle.cpp:
     40        (WebCore::RenderStyle::RenderStyle):
     41        * rendering/style/RenderStyle.h:
     42        (WebCore::InheritedFlags::affectedByUncommonAttributeSelectors):
     43        (WebCore::InheritedFlags::setAffectedByUncommonAttributeSelectors):
     44
    1452011-09-30  James Robinson  <jamesr@chromium.org>
    246
  • trunk/Source/WebCore/css/CSSSelector.h

    r93952 r96393  
    243243        bool isUnknownPseudoElement() const;
    244244        bool isSiblingSelector() const;
     245        bool isAttributeSelector() const;
    245246
    246247        Relation relation() const { return static_cast<Relation>(m_relation); }
     
    327328        || type == PseudoNthLastOfType;
    328329}
    329    
     330
     331inline bool CSSSelector::isAttributeSelector() const
     332{
     333    if (!hasAttribute())
     334        return false;
     335    return m_match == CSSSelector::Exact
     336        || m_match ==  CSSSelector::Set
     337        || m_match == CSSSelector::List
     338        || m_match == CSSSelector::Hyphen
     339        || m_match == CSSSelector::Contain
     340        || m_match == CSSSelector::Begin
     341        || m_match == CSSSelector::End;
     342}
     343
    330344inline void CSSSelector::setValue(const AtomicString& value)
    331345{
  • trunk/Source/WebCore/css/CSSStyleSelector.cpp

    r96281 r96393  
    190190    bool hasMultipartSelector() const { return m_hasMultipartSelector; }
    191191    bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; }
     192    bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
    192193    unsigned specificity() const { return m_specificity; }
    193194   
     
    200201    CSSSelector* m_selector;
    201202    unsigned m_specificity;
    202     unsigned m_position : 29;
     203    unsigned m_position : 28;
    203204    bool m_hasFastCheckableSelector : 1;
    204205    bool m_hasMultipartSelector : 1;
    205206    bool m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1;
     207    bool m_containsUncommonAttributeSelector : 1;
    206208    // Use plain array instead of a Vector to minimize memory overhead.
    207209    unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount];
     
    259261   
    260262static RuleSet* siblingRulesInDefaultStyle;
     263static RuleSet* uncommonAttributeRulesInDefaultStyle;
    261264
    262265RenderStyle* CSSStyleSelector::s_styleNotYetAvailable;
     
    272275}
    273276
    274 static inline void collectSiblingRulesInDefaultStyle()
     277static inline void collectSpecialRulesInDefaultStyle()
    275278{
    276279    CSSStyleSelector::Features features;
     
    278281    ASSERT(features.idsInRules.isEmpty());
    279282    delete siblingRulesInDefaultStyle;
     283    delete uncommonAttributeRulesInDefaultStyle;
    280284    siblingRulesInDefaultStyle = features.siblingRules.leakPtr();
     285    uncommonAttributeRulesInDefaultStyle = features.uncommonAttributeRules.leakPtr();
    281286}
    282287
     
    286291    if (siblingRulesInDefaultStyle)
    287292        return;
    288     collectSiblingRulesInDefaultStyle();
     293    collectSpecialRulesInDefaultStyle();
    289294    ASSERT(!siblingRulesInDefaultStyle);
    290295#endif
     
    412417    if (siblingRulesInDefaultStyle)
    413418        siblingRulesInDefaultStyle->collectFeatures(m_features);
     419    if (uncommonAttributeRulesInDefaultStyle)
     420        uncommonAttributeRulesInDefaultStyle->collectFeatures(m_features);
    414421    m_authorStyle->collectFeatures(m_features);
    415422    if (m_userStyle)
     
    419426    if (m_features.siblingRules)
    420427        m_features.siblingRules->shrinkToFit();
     428    if (m_features.uncommonAttributeRules)
     429        m_features.uncommonAttributeRules->shrinkToFit();
    421430
    422431    if (document->renderer() && document->renderer()->style())
     
    560569    // Now transfer the set of matched rules over to our list of decls.
    561570    if (!m_checker.isCollectingRulesOnly()) {
    562         for (unsigned i = 0; i < m_matchedRules.size(); i++)
     571        for (unsigned i = 0; i < m_matchedRules.size(); i++) {
     572            if (m_style && m_matchedRules[i]->containsUncommonAttributeSelector())
     573                m_style->setAffectedByUncommonAttributeSelectors();
    563574            addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
     575        }
    564576    } else {
    565577        for (unsigned i = 0; i < m_matchedRules.size(); i++) {
     
    741753}
    742754
    743 bool CSSStyleSelector::matchesSiblingRules()
     755bool CSSStyleSelector::matchesRuleSet(RuleSet* ruleSet)
    744756{
    745757    int firstSiblingRule = -1, lastSiblingRule = -1;
    746     matchRules(m_features.siblingRules.get(), firstSiblingRule, lastSiblingRule, false);
     758    matchRules(ruleSet, firstSiblingRule, lastSiblingRule, false);
    747759    if (m_matchedDecls.isEmpty())
    748760        return false;
     
    828840    if (element->isLink() != m_element->isLink())
    829841        return false;
    830     if (style->affectedByAttributeSelectors())
     842    if (style->affectedByUncommonAttributeSelectors())
    831843        return false;
    832844    if (element->hovered() != m_element->hovered())
     
    912924}
    913925
    914 ALWAYS_INLINE RenderStyle* CSSStyleSelector::locateSharedStyle()
     926RenderStyle* CSSStyleSelector::locateSharedStyle()
    915927{
    916928    if (!m_styledElement || !m_parentStyle)
     
    942954
    943955    // Can't share if sibling rules apply. This is checked at the end as it should rarely fail.
    944     if (matchesSiblingRules())
     956    if (matchesRuleSet(m_features.siblingRules.get()))
     957        return 0;
     958    // Can't share if attribute rules apply.
     959    if (matchesRuleSet(m_features.uncommonAttributeRules.get()))
    945960        return 0;
    946961    // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
     
    11131128        loadFullDefaultStyle();
    11141129        assertNoSiblingRulesInDefaultStyle();
     1130        collectSpecialRulesInDefaultStyle();
    11151131    }
    11161132
     
    11241140        defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
    11251141        assertNoSiblingRulesInDefaultStyle();
     1142        collectSpecialRulesInDefaultStyle();
    11261143    }
    11271144#endif
     
    11351152        defaultStyle->addRulesFromSheet(mathMLSheet, screenEval());
    11361153        defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval());
    1137         // There are some sibling rules here.
    1138         collectSiblingRulesInDefaultStyle();
     1154        // There are some sibling and uncommon attribute rules here.
     1155        collectSpecialRulesInDefaultStyle();
    11391156    }
    11401157#endif
     
    11481165        defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval());
    11491166        defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval());
    1150         assertNoSiblingRulesInDefaultStyle();
     1167        collectSpecialRulesInDefaultStyle();
    11511168    }
    11521169#endif
     
    11601177        defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval());
    11611178        defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval());
     1179        collectSpecialRulesInDefaultStyle();
    11621180    }
    11631181#endif
     
    18391857}
    18401858
     1859static inline bool selectorListContainsUncommonAttributeSelector(const CSSSelector* selector)
     1860{
     1861    CSSSelectorList* selectorList = selector->selectorList();
     1862    if (!selectorList)
     1863        return false;
     1864    for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
     1865        if (subSelector->isAttributeSelector())
     1866            return true;
     1867    }
     1868    return false;
     1869}
     1870
     1871static inline bool isCommonAttributeSelectorAttribute(const QualifiedName& attribute)
     1872{
     1873    // These are explicitly tested for equality in canShareStyleWithElement.
     1874    return attribute == typeAttr || attribute == readonlyAttr;
     1875}
     1876
     1877static inline bool containsUncommonAttributeSelector(const CSSSelector* selector)
     1878{
     1879    while (selector) {
     1880        // Allow certain common attributes (used in the default style) in the selectors that match the current element.
     1881        if (selector->isAttributeSelector() && !isCommonAttributeSelectorAttribute(selector->attribute()))
     1882            return true;
     1883        if (selectorListContainsUncommonAttributeSelector(selector))
     1884            return true;
     1885        if (selector->relation() != CSSSelector::SubSelector)
     1886            break;
     1887        selector = selector->tagHistory();
     1888    };
     1889
     1890    for (selector = selector->tagHistory(); selector; selector = selector->tagHistory()) {           
     1891        if (selector->isAttributeSelector())
     1892            return true;
     1893        if (selectorListContainsUncommonAttributeSelector(selector))
     1894            return true;
     1895    }
     1896    return false;
     1897}
     1898
    18411899RuleData::RuleData(CSSStyleRule* rule, CSSSelector* selector, unsigned position)
    18421900    : m_rule(rule)
     
    18471905    , m_hasMultipartSelector(selector->tagHistory())
    18481906    , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector))
     1907    , m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector))
    18491908{
    18501909    SelectorChecker::collectIdentifierHashes(m_selector, m_descendantSelectorIdentifierHashes, maximumIdentifierCount);
     
    19962055    if (selector->m_match == CSSSelector::Id && !selector->value().isEmpty())
    19972056        features.idsInRules.add(selector->value().impl());
    1998     if (selector->hasAttribute()) {
    1999         switch (selector->m_match) {
    2000         case CSSSelector::Exact:
    2001         case CSSSelector::Set:
    2002         case CSSSelector::List:
    2003         case CSSSelector::Hyphen:
    2004         case CSSSelector::Contain:
    2005         case CSSSelector::Begin:
    2006         case CSSSelector::End:
    2007             features.attrsInRules.add(selector->attribute().localName().impl());
    2008             break;
    2009         default:
    2010             break;
    2011         }
    2012     }
     2057    if (selector->isAttributeSelector())
     2058        features.attrsInRules.add(selector->attribute().localName().impl());
    20132059    switch (selector->pseudoType()) {
    20142060    case CSSSelector::PseudoFirstLine:
     
    20502096                features.siblingRules = adoptPtr(new RuleSet);
    20512097            features.siblingRules->addRule(ruleData.rule(), ruleData.selector());   
     2098        }
     2099        if (ruleData.containsUncommonAttributeSelector()) {
     2100            if (!features.uncommonAttributeRules)
     2101                features.uncommonAttributeRules = adoptPtr(new RuleSet);
     2102            features.uncommonAttributeRules->addRule(ruleData.rule(), ruleData.selector());
    20522103        }
    20532104    }
  • trunk/Source/WebCore/css/CSSStyleSelector.h

    r95052 r96393  
    123123    void initElement(Element*);
    124124    RenderStyle* locateSharedStyle();
    125     bool matchesSiblingRules();
     125    bool matchesRuleSet(RuleSet*);
    126126    Node* locateCousinList(Element* parent, unsigned& visitedNodeCount) const;
    127127    Node* findSiblingForStyleSharing(Node*, unsigned& count) const;
     
    203203        HashSet<AtomicStringImpl*> attrsInRules;
    204204        OwnPtr<RuleSet> siblingRules;
     205        OwnPtr<RuleSet> uncommonAttributeRules;
    205206        bool usesFirstLineRules;
    206207        bool usesBeforeAfterRules;
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r95966 r96393  
    687687        const QualifiedName& attr = sel->attribute();
    688688       
    689         // FIXME: Handle the case were elementStyle is 0.
    690         if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr)))
    691             elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
    692        
    693689        NamedNodeMap* attributes = e->attributes(true);
    694690        if (!attributes)
  • trunk/Source/WebCore/rendering/style/RenderStyle.cpp

    r96142 r96393  
    7272
    7373ALWAYS_INLINE RenderStyle::RenderStyle()
    74     : m_affectedByAttributeSelectors(false)
     74    : m_affectedByUncommonAttributeSelectors(false)
    7575    , m_unique(false)
    7676    , m_affectedByEmpty(false)
     
    9999
    100100ALWAYS_INLINE RenderStyle::RenderStyle(bool)
    101     : m_affectedByAttributeSelectors(false)
     101    : m_affectedByUncommonAttributeSelectors(false)
    102102    , m_unique(false)
    103103    , m_affectedByEmpty(false)
     
    139139ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
    140140    : RefCounted<RenderStyle>()
    141     , m_affectedByAttributeSelectors(false)
     141    , m_affectedByUncommonAttributeSelectors(false)
    142142    , m_unique(false)
    143143    , m_affectedByEmpty(false)
  • trunk/Source/WebCore/rendering/style/RenderStyle.h

    r96142 r96393  
    128128    // The following bitfield is 32-bits long, which optimizes padding with the
    129129    // int refCount in the base class. Beware when adding more bits.
    130     bool m_affectedByAttributeSelectors : 1;
     130    bool m_affectedByUncommonAttributeSelectors : 1;
    131131    bool m_unique : 1;
    132132
     
    13071307
    13081308    // To tell if this style matched attribute selectors. This makes it impossible to share.
    1309     bool affectedByAttributeSelectors() const { return m_affectedByAttributeSelectors; }
    1310     void setAffectedByAttributeSelectors() { m_affectedByAttributeSelectors = true; }
     1309    bool affectedByUncommonAttributeSelectors() const { return m_affectedByUncommonAttributeSelectors; }
     1310    void setAffectedByUncommonAttributeSelectors() { m_affectedByUncommonAttributeSelectors = true; }
    13111311
    13121312    bool affectedByDirectAdjacentRules() const { return m_affectedByDirectAdjacentRules; }
Note: See TracChangeset for help on using the changeset viewer.