Changeset 132941 in webkit


Ignore:
Timestamp:
Oct 30, 2012 1:25:52 PM (11 years ago)
Author:
Antti Koivisto
Message:

Avoid unnecessary style recalcs on class attribute mutation
https://bugs.webkit.org/show_bug.cgi?id=100776

Reviewed by Andreas Kling.

There is no need to invalidate element style on class attribute change if neither the added
or removed classes featured in any active stylesheet.

  • css/RuleFeature.cpp:

(WebCore::RuleFeatureSet::add):
(WebCore::RuleFeatureSet::clear):
(WebCore::RuleFeatureSet::reportMemoryUsage):

  • css/RuleFeature.h:

(RuleFeatureSet):

  • css/RuleSet.cpp:

(WebCore::collectFeaturesFromSelector):

Collect classes mentioned in CSS selectors the same way ids and attribute names are
already collected.

  • css/StyleResolver.cpp:

(WebCore::StyleResolver::hasSelectorForClass):

Add a method to test if a given class name is mentioned anywhere in stylehseets.

(WebCore):

  • css/StyleResolver.h:
  • css/StyleScopeResolver.h:

(WebCore):

  • dom/Element.cpp:

(WebCore::collectAddedAndRemovedClasses):
(WebCore):
(WebCore::Element::classAttributeChanged):

Figure out which classes were added and removed. Test if they are present in any style
rule and invalidate the style only if they are.

  • dom/SpaceSplitString.cpp:

(WebCore::SpaceSplitStringData::add):
(WebCore::SpaceSplitStringData::remove):
(WebCore::SpaceSplitString::add):
(WebCore::SpaceSplitString::remove):

Added bool return value to indicate if anything was actually removed. Reorganized
the code a bit to avoid unnecessary uniquing when nothing changes.

  • dom/SpaceSplitString.h:

(SpaceSplitStringData):
(SpaceSplitString):

Location:
trunk/Source/WebCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r132935 r132941  
     12012-10-30  Antti Koivisto  <antti@apple.com>
     2
     3        Avoid unnecessary style recalcs on class attribute mutation
     4        https://bugs.webkit.org/show_bug.cgi?id=100776
     5
     6        Reviewed by Andreas Kling.
     7
     8        There is no need to invalidate element style on class attribute change if neither the added
     9        or removed classes featured in any active stylesheet.
     10
     11        * css/RuleFeature.cpp:
     12        (WebCore::RuleFeatureSet::add):
     13        (WebCore::RuleFeatureSet::clear):
     14        (WebCore::RuleFeatureSet::reportMemoryUsage):
     15        * css/RuleFeature.h:
     16        (RuleFeatureSet):
     17        * css/RuleSet.cpp:
     18        (WebCore::collectFeaturesFromSelector):
     19       
     20            Collect classes mentioned in CSS selectors the same way ids and attribute names are
     21            already collected.
     22
     23        * css/StyleResolver.cpp:
     24        (WebCore::StyleResolver::hasSelectorForClass):
     25       
     26            Add a method to test if a given class name is mentioned anywhere in stylehseets.
     27
     28        (WebCore):
     29        * css/StyleResolver.h:
     30        * css/StyleScopeResolver.h:
     31        (WebCore):
     32        * dom/Element.cpp:
     33        (WebCore::collectAddedAndRemovedClasses):
     34        (WebCore):
     35        (WebCore::Element::classAttributeChanged):
     36       
     37            Figure out which classes were added and removed. Test if they are present in any style
     38            rule and invalidate the style only if they are.
     39
     40        * dom/SpaceSplitString.cpp:
     41        (WebCore::SpaceSplitStringData::add):
     42        (WebCore::SpaceSplitStringData::remove):
     43        (WebCore::SpaceSplitString::add):
     44        (WebCore::SpaceSplitString::remove):
     45       
     46            Added bool return value to indicate if anything was actually removed. Reorganized
     47            the code a bit to avoid unnecessary uniquing when nothing changes.
     48
     49        * dom/SpaceSplitString.h:
     50        (SpaceSplitStringData):
     51        (SpaceSplitString):
     52
    1532012-10-30  Robert Hogan  <robert@webkit.org>
    254
  • trunk/Source/WebCore/css/RuleFeature.cpp

    r130465 r132941  
    3939void RuleFeatureSet::add(const RuleFeatureSet& other)
    4040{
    41     HashSet<AtomicStringImpl*>::iterator end = other.idsInRules.end();
    42     for (HashSet<AtomicStringImpl*>::iterator it = other.idsInRules.begin(); it != end; ++it)
     41    HashSet<AtomicStringImpl*>::const_iterator end = other.idsInRules.end();
     42    for (HashSet<AtomicStringImpl*>::const_iterator it = other.idsInRules.begin(); it != end; ++it)
    4343        idsInRules.add(*it);
     44    end = other.classesInRules.end();
     45    for (HashSet<AtomicStringImpl*>::const_iterator it = other.classesInRules.begin(); it != end; ++it)
     46        classesInRules.add(*it);
    4447    end = other.attrsInRules.end();
    45     for (HashSet<AtomicStringImpl*>::iterator it = other.attrsInRules.begin(); it != end; ++it)
     48    for (HashSet<AtomicStringImpl*>::const_iterator it = other.attrsInRules.begin(); it != end; ++it)
    4649        attrsInRules.add(*it);
    4750    siblingRules.append(other.siblingRules);
     
    5457{
    5558    idsInRules.clear();
     59    classesInRules.clear();
    5660    attrsInRules.clear();
    5761    siblingRules.clear();
     
    6569    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
    6670    info.addMember(idsInRules);
     71    info.addMember(classesInRules);
    6772    info.addMember(attrsInRules);
    6873    info.addMember(siblingRules);
  • trunk/Source/WebCore/css/RuleFeature.h

    r130465 r132941  
    3232class StyleRule;
    3333
    34 class RuleFeature {
    35 public:
     34struct RuleFeature {
    3635    RuleFeature(StyleRule* rule, unsigned selectorIndex, bool hasDocumentSecurityOrigin)
    3736        : rule(rule)
     
    4544};
    4645
    47 class RuleFeatureSet {
    48 public:
     46struct RuleFeatureSet {
    4947    RuleFeatureSet()
    5048        : usesFirstLineRules(false)
     
    5654    void reportMemoryUsage(MemoryObjectInfo*) const;
    5755    HashSet<AtomicStringImpl*> idsInRules;
     56    HashSet<AtomicStringImpl*> classesInRules;
    5857    HashSet<AtomicStringImpl*> attrsInRules;
    5958    Vector<RuleFeature> siblingRules;
  • trunk/Source/WebCore/css/RuleSet.cpp

    r132618 r132941  
    162162    if (selector->m_match == CSSSelector::Id)
    163163        features.idsInRules.add(selector->value().impl());
    164     if (selector->isAttributeSelector())
     164    else if (selector->m_match == CSSSelector::Class)
     165        features.classesInRules.add(selector->value().impl());
     166    else if (selector->isAttributeSelector())
    165167        features.attrsInRules.add(selector->attribute().localName().impl());
    166168    switch (selector->pseudoType()) {
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r132927 r132941  
    42554255}
    42564256
     4257bool StyleResolver::hasSelectorForClass(const AtomicString& classValue) const
     4258{
     4259    if (classValue.isEmpty())
     4260        return false;
     4261    return m_features.classesInRules.contains(classValue.impl());
     4262}
     4263
    42574264bool StyleResolver::hasSelectorForId(const AtomicString& idValue) const
    42584265{
  • trunk/Source/WebCore/css/StyleResolver.h

    r132808 r132941  
    242242
    243243    bool hasSelectorForId(const AtomicString&) const;
     244    bool hasSelectorForClass(const AtomicString&) const;
    244245    bool hasSelectorForAttribute(const AtomicString&) const;
    245246
  • trunk/Source/WebCore/css/StyleScopeResolver.h

    r132618 r132941  
    4040class Element;
    4141class RuleSet;
    42 class RuleFeatureSet;
    4342class ShadowRoot;
    4443class StyleRuleHost;
     44struct RuleFeatureSet;
    4545
    4646#if ENABLE(STYLE_SCOPED) || ENABLE(SHADOW_DOM)
  • trunk/Source/WebCore/dom/Element.cpp

    r132774 r132941  
    766766}
    767767
     768static void collectAddedAndRemovedClasses(Vector<AtomicString, 4>& addedAndRemovedClasses, SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
     769{
     770    for (unsigned i = 0; i < newClasses.size(); ++i) {
     771        if (oldClasses.remove(newClasses[i]))
     772            continue;
     773        addedAndRemovedClasses.append(newClasses[i]);
     774    }
     775    for (unsigned i = 0; i < oldClasses.size(); ++i)
     776        addedAndRemovedClasses.append(oldClasses[i]);
     777}
     778
    768779void Element::classAttributeChanged(const AtomicString& newClassString)
    769780{
     781    bool shouldInvalidateStyle = attached() && document()->styleResolverIfExists();
     782    Vector<AtomicString, 4> addedAndRemovedClasses;
     783
    770784    if (classStringHasClassName(newClassString)) {
     785        const ElementAttributeData* attributeData = ensureAttributeData();
    771786        const bool shouldFoldCase = document()->inQuirksMode();
    772         ensureAttributeData()->setClass(newClassString, shouldFoldCase);
    773     } else if (attributeData())
     787        SpaceSplitString oldClasses = attributeData->classNames();
     788        attributeData->setClass(newClassString, shouldFoldCase);
     789        if (shouldInvalidateStyle)
     790            collectAddedAndRemovedClasses(addedAndRemovedClasses, oldClasses, mutableAttributeData()->classNames());
     791    } else if (attributeData()) {
     792        if (shouldInvalidateStyle) {
     793            const SpaceSplitString& oldClasses = attributeData()->classNames();
     794            for (unsigned i = 0; i < oldClasses.size(); ++i)
     795                addedAndRemovedClasses.append(oldClasses[i]);
     796        }
    774797        mutableAttributeData()->clearClass();
     798    }
    775799
    776800    if (DOMTokenList* classList = optionalClassList())
    777801        static_cast<ClassList*>(classList)->reset(newClassString);
    778802
    779     setNeedsStyleRecalc();
     803    if (!shouldInvalidateStyle)
     804        return;
     805    for (unsigned i = 0; i < addedAndRemovedClasses.size(); ++i) {
     806        if (document()->styleResolverIfExists()->hasSelectorForClass(addedAndRemovedClasses[i])) {
     807            setNeedsStyleRecalc();
     808            break;
     809        }
     810    }
    780811}
    781812
  • trunk/Source/WebCore/dom/SpaceSplitString.cpp

    r130612 r132941  
    108108{
    109109    ASSERT(hasOneRef());
     110    ASSERT(!contains(string));
     111    m_vector.append(string);
     112}
     113
     114void SpaceSplitStringData::remove(unsigned index)
     115{
     116    ASSERT(hasOneRef());
     117    m_vector.remove(index);
     118}
     119
     120void SpaceSplitString::add(const AtomicString& string)
     121{
     122    // FIXME: add() does not allow duplicates but createVector() does.
    110123    if (contains(string))
    111124        return;
    112 
    113     m_vector.append(string);
    114 }
    115 
    116 void SpaceSplitStringData::remove(const AtomicString& string)
    117 {
    118     ASSERT(hasOneRef());
    119     size_t position = 0;
    120     while (position < m_vector.size()) {
    121         if (m_vector[position] == string)
    122             m_vector.remove(position);
    123         else
    124             ++position;
    125     }
    126 }
    127 
    128 void SpaceSplitString::add(const AtomicString& string)
    129 {
    130125    ensureUnique();
    131126    if (m_data)
     
    133128}
    134129
    135 void SpaceSplitString::remove(const AtomicString& string)
    136 {
    137     ensureUnique();
    138     if (m_data)
    139         m_data->remove(string);
     130bool SpaceSplitString::remove(const AtomicString& string)
     131{
     132    if (!m_data)
     133        return false;
     134    unsigned i = 0;
     135    bool changed = false;
     136    while (i < m_data->size()) {
     137        if ((*m_data)[i] == string) {
     138            if (!changed)
     139                ensureUnique();
     140            m_data->remove(i);
     141            changed = true;
     142            continue;
     143        }
     144        ++i;
     145    }
     146    return changed;
    140147}
    141148
  • trunk/Source/WebCore/dom/SpaceSplitString.h

    r128694 r132941  
    4848
    4949        void add(const AtomicString&);
    50         void remove(const AtomicString&);
     50        void remove(unsigned index);
    5151
    5252        bool isUnique() const { return m_keyString.isNull(); }
     
    7777        bool containsAll(const SpaceSplitString& names) const { return !names.m_data || (m_data && m_data->containsAll(*names.m_data)); }
    7878        void add(const AtomicString&);
    79         void remove(const AtomicString&);
     79        bool remove(const AtomicString&);
    8080
    8181        size_t size() const { return m_data ? m_data->size() : 0; }
Note: See TracChangeset for help on using the changeset viewer.