Changeset 196629 in webkit


Ignore:
Timestamp:
Feb 16, 2016 12:20:58 AM (8 years ago)
Author:
Antti Koivisto
Message:

Optimize style invalidations for attribute selectors
https://bugs.webkit.org/show_bug.cgi?id=154242

Reviewed by Andreas Kling.

Source/WebCore:

Currently we invalidate the whole element subtree if there are any attribute selectors for the changed attribute.
This is slow as generally few if any elements are really affected. Using attribute selectors for dynamic styling
should be performant.

This patch implements optimization strategy for attributes similar to what we already have for classes:

  • Collect a map of all rules that contains descendant-affecting attribute selectors for a given attribute.
  • When an attribute value changes check if there are any such rules for it.
  • Check if the value change affects the results of any of the attribute selectors.
  • Only if it does invalidate the exact descendant elements affected by the rules.

Test: fast/css/style-invalidation-attribute-change-descendants.html

  • WebCore.xcodeproj/project.pbxproj:
  • css/DocumentRuleSets.cpp:

(WebCore::DocumentRuleSets::ancestorClassRules):
(WebCore::DocumentRuleSets::ancestorAttributeRulesForHTML):

Create optimization RuleSets when needed.

  • css/DocumentRuleSets.h:

(WebCore::DocumentRuleSets::uncommonAttribute):
(WebCore::DocumentRuleSets::features):

  • css/RuleFeature.cpp:

(WebCore::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
(WebCore::makeAttributeSelectorKey):
(WebCore::RuleFeatureSet::collectFeatures):

Collect rules with descendant affecting attribute selectors.

(WebCore::RuleFeatureSet::add):
(WebCore::RuleFeatureSet::clear):
(WebCore::RuleFeatureSet::shrinkToFit):

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

(WebCore::anyAttributeMatches):
(WebCore::SelectorChecker::attributeSelectorMatches):

Expose function for matching single attribute selectors.

(WebCore::canMatchHoverOrActiveInQuirksMode):

  • css/SelectorChecker.h:
  • dom/Attr.cpp:

(WebCore::Attr::setValue):
(WebCore::Attr::childrenChanged):

  • dom/Element.cpp:

(WebCore::Element::setAttributeInternal):
(WebCore::makeIdForStyleResolution):
(WebCore::Element::attributeChanged):
(WebCore::Element::removeAttributeInternal):
(WebCore::Element::addAttributeInternal):
(WebCore::Element::removeAttribute):

Add AttributeChangeInvalidation where needed.

(WebCore::Element::needsStyleInvalidation):

Move to Element from ClassChangeInvalidation.

(WebCore::Element::willModifyAttribute):

No more full style invalidation on attribute change.

  • style/AttributeChangeInvalidation.cpp: Added.

(WebCore::Style::AttributeChangeInvalidation::invalidateStyle):

Invalidate local style.
Check if we need to invalidate descendants by looking into ancestorAttributeRules.

(WebCore::Style::AttributeChangeInvalidation::invalidateDescendants):

Use StyleInvalidationAnalysis to invalidate the subtree for the relevant rules.

  • style/AttributeChangeInvalidation.h: Added.

(WebCore::Style::AttributeChangeInvalidation::needsInvalidation):
(WebCore::Style::AttributeChangeInvalidation::AttributeChangeInvalidation):
(WebCore::Style::AttributeChangeInvalidation::~AttributeChangeInvalidation):

If needed, invalidate descendants before and after attribute change to catch rules that start and stop applying.

LayoutTests:

  • fast/css/style-invalidation-attribute-change-descendants-expected.txt: Added.
  • fast/css/style-invalidation-attribute-change-descendants.html: Added.
Location:
trunk
Files:
4 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r196628 r196629  
     12016-02-15  Antti Koivisto  <antti@apple.com>
     2
     3        Optimize style invalidations for attribute selectors
     4        https://bugs.webkit.org/show_bug.cgi?id=154242
     5
     6        Reviewed by Andreas Kling.
     7
     8        * fast/css/style-invalidation-attribute-change-descendants-expected.txt: Added.
     9        * fast/css/style-invalidation-attribute-change-descendants.html: Added.
     10
    1112016-02-16  Chris Dumez  <cdumez@apple.com>
    212
  • trunk/Source/WebCore/CMakeLists.txt

    r196622 r196629  
    26312631    storage/StorageNamespaceProvider.cpp
    26322632
     2633    style/AttributeChangeInvalidation.cpp
    26332634    style/ClassChangeInvalidation.cpp
    26342635    style/InlineTextBoxStyle.cpp
  • trunk/Source/WebCore/ChangeLog

    r196628 r196629  
     12016-02-15  Antti Koivisto  <antti@apple.com>
     2
     3        Optimize style invalidations for attribute selectors
     4        https://bugs.webkit.org/show_bug.cgi?id=154242
     5
     6        Reviewed by Andreas Kling.
     7
     8        Currently we invalidate the whole element subtree if there are any attribute selectors for the changed attribute.
     9        This is slow as generally few if any elements are really affected. Using attribute selectors for dynamic styling
     10        should be performant.
     11
     12        This patch implements optimization strategy for attributes similar to what we already have for classes:
     13
     14        - Collect a map of all rules that contains descendant-affecting attribute selectors for a given attribute.
     15        - When an attribute value changes check if there are any such rules for it.
     16        - Check if the value change affects the results of any of the attribute selectors.
     17        - Only if it does invalidate the exact descendant elements affected by the rules.
     18
     19        Test: fast/css/style-invalidation-attribute-change-descendants.html
     20
     21        * WebCore.xcodeproj/project.pbxproj:
     22        * css/DocumentRuleSets.cpp:
     23        (WebCore::DocumentRuleSets::ancestorClassRules):
     24        (WebCore::DocumentRuleSets::ancestorAttributeRulesForHTML):
     25
     26            Create optimization RuleSets when needed.
     27
     28        * css/DocumentRuleSets.h:
     29        (WebCore::DocumentRuleSets::uncommonAttribute):
     30        (WebCore::DocumentRuleSets::features):
     31        * css/RuleFeature.cpp:
     32        (WebCore::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
     33        (WebCore::makeAttributeSelectorKey):
     34        (WebCore::RuleFeatureSet::collectFeatures):
     35
     36            Collect rules with descendant affecting attribute selectors.
     37
     38        (WebCore::RuleFeatureSet::add):
     39        (WebCore::RuleFeatureSet::clear):
     40        (WebCore::RuleFeatureSet::shrinkToFit):
     41        * css/RuleFeature.h:
     42        * css/SelectorChecker.cpp:
     43        (WebCore::anyAttributeMatches):
     44        (WebCore::SelectorChecker::attributeSelectorMatches):
     45
     46            Expose function for matching single attribute selectors.
     47
     48        (WebCore::canMatchHoverOrActiveInQuirksMode):
     49        * css/SelectorChecker.h:
     50        * dom/Attr.cpp:
     51        (WebCore::Attr::setValue):
     52        (WebCore::Attr::childrenChanged):
     53        * dom/Element.cpp:
     54        (WebCore::Element::setAttributeInternal):
     55        (WebCore::makeIdForStyleResolution):
     56        (WebCore::Element::attributeChanged):
     57        (WebCore::Element::removeAttributeInternal):
     58        (WebCore::Element::addAttributeInternal):
     59        (WebCore::Element::removeAttribute):
     60
     61            Add AttributeChangeInvalidation where needed.
     62
     63        (WebCore::Element::needsStyleInvalidation):
     64
     65            Move to Element from ClassChangeInvalidation.
     66
     67        (WebCore::Element::willModifyAttribute):
     68
     69            No more full style invalidation on attribute change.
     70
     71        * style/AttributeChangeInvalidation.cpp: Added.
     72        (WebCore::Style::AttributeChangeInvalidation::invalidateStyle):
     73
     74            Invalidate local style.
     75            Check if we need to invalidate descendants by looking into ancestorAttributeRules.
     76
     77        (WebCore::Style::AttributeChangeInvalidation::invalidateDescendants):
     78
     79            Use StyleInvalidationAnalysis to invalidate the subtree for the relevant rules.
     80
     81        * style/AttributeChangeInvalidation.h: Added.
     82        (WebCore::Style::AttributeChangeInvalidation::needsInvalidation):
     83        (WebCore::Style::AttributeChangeInvalidation::AttributeChangeInvalidation):
     84        (WebCore::Style::AttributeChangeInvalidation::~AttributeChangeInvalidation):
     85
     86            If needed, invalidate descendants before and after attribute change to catch rules that start and stop applying.
     87
    1882016-02-16  Chris Dumez  <cdumez@apple.com>
    289
  • trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj

    r196604 r196629  
    1929619296    <ClCompile Include="..\storage\StorageMap.cpp" />
    1929719297    <ClCompile Include="..\storage\StorageNamespaceProvider.cpp" />
     19298    <ClCompile Include="..\style\AttributeChangeInvalidation.cpp" />
    1929819299    <ClCompile Include="..\style\ClassChangeInvalidation.cpp" />
    1929919300    <ClCompile Include="..\style\InlineTextBoxStyle.cpp" />
     
    2286622867    <ClInclude Include="..\storage\StorageNamespace.h" />
    2286722868    <ClInclude Include="..\storage\StorageNamespaceProvider.h" />
     22869    <ClInclude Include="..\style\AttributeChangeInvalidation.h" />
    2286822870    <ClInclude Include="..\style\ClassChangeInvalidation.h" />
    2286922871    <ClInclude Include="..\style\InlineTextBoxStyle.h" />
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r196622 r196629  
    66386638                E4A814D41C6DEC4000BF85AC /* ClassChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A814D31C6DEC4000BF85AC /* ClassChangeInvalidation.h */; };
    66396639                E4A814D61C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A814D51C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp */; };
     6640                E4A814D81C70E10500BF85AC /* AttributeChangeInvalidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A814D71C70E10500BF85AC /* AttributeChangeInvalidation.cpp */; };
     6641                E4A814DA1C70E10D00BF85AC /* AttributeChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A814D91C70E10D00BF85AC /* AttributeChangeInvalidation.h */; };
    66406642                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1517D1BB950009FB31 /* ElementIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
    66416643                E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    1464414646                E4A814D31C6DEC4000BF85AC /* ClassChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassChangeInvalidation.h; sourceTree = "<group>"; };
    1464514647                E4A814D51C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassChangeInvalidation.cpp; sourceTree = "<group>"; };
     14648                E4A814D71C70E10500BF85AC /* AttributeChangeInvalidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttributeChangeInvalidation.cpp; sourceTree = "<group>"; };
     14649                E4A814D91C70E10D00BF85AC /* AttributeChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AttributeChangeInvalidation.h; sourceTree = "<group>"; };
    1464614650                E4AE7C1517D1BB950009FB31 /* ElementIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIterator.h; sourceTree = "<group>"; };
    1464714651                E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAncestorIterator.h; sourceTree = "<group>"; };
     
    2343423438                        isa = PBXGroup;
    2343523439                        children = (
     23440                                E4A814D71C70E10500BF85AC /* AttributeChangeInvalidation.cpp */,
     23441                                E4A814D91C70E10D00BF85AC /* AttributeChangeInvalidation.h */,
    2343623442                                E4A814D51C6DEE8D00BF85AC /* ClassChangeInvalidation.cpp */,
    2343723443                                E4A814D31C6DEC4000BF85AC /* ClassChangeInvalidation.h */,
     
    2591025916                                49ECEB6E1499790D00CDD3A4 /* FilterOperation.h in Headers */,
    2591125917                                49ECEB701499790D00CDD3A4 /* FilterOperations.h in Headers */,
     25918                                E4A814DA1C70E10D00BF85AC /* AttributeChangeInvalidation.h in Headers */,
    2591225919                                372C00D9129619F8005C9575 /* FindOptions.h in Headers */,
    2591325920                                A8CFF04F0A154F09000A4234 /* FixedTableLayout.h in Headers */,
     
    3044130448                                9BD4E9161C462872005065BC /* JSCustomElementInterface.cpp in Sources */,
    3044230449                                514C76380CE9225E007EF3CD /* JSSQLTransaction.cpp in Sources */,
     30450                                E4A814D81C70E10500BF85AC /* AttributeChangeInvalidation.cpp in Sources */,
    3044330451                                B59DD69E11902A42007E9684 /* JSSQLTransactionCallback.cpp in Sources */,
    3044430452                                1AD2316E0CD269E700C1F194 /* JSSQLTransactionCustom.cpp in Sources */,
  • trunk/Source/WebCore/css/DocumentRuleSets.cpp

    r196555 r196629  
    119119RuleSet* DocumentRuleSets::ancestorClassRules(AtomicStringImpl* className) const
    120120{
    121     auto addResult = m_ancestorClassRuleSet.add(className, nullptr);
     121    auto addResult = m_ancestorClassRuleSets.add(className, nullptr);
    122122    if (addResult.isNewEntry) {
    123123        if (auto* rules = m_features.ancestorClassRules.get(className))
     
    127127}
    128128
     129const DocumentRuleSets::AttributeRules* DocumentRuleSets::ancestorAttributeRulesForHTML(AtomicStringImpl* attributeName) const
     130{
     131    auto addResult = m_ancestorAttributeRuleSetsForHTML.add(attributeName, nullptr);
     132    auto& value = addResult.iterator->value;
     133    if (addResult.isNewEntry) {
     134        if (auto* rules = m_features.ancestorAttributeRulesForHTML.get(attributeName)) {
     135            value = std::make_unique<AttributeRules>();
     136            value->attributeSelectors.reserveCapacity(rules->selectors.size());
     137            for (auto* selector : rules->selectors.values())
     138                value->attributeSelectors.uncheckedAppend(selector);
     139            value->ruleSet = makeRuleSet(rules->features);
     140        }
     141    }
     142    return value.get();
     143}
     144
    129145} // namespace WebCore
  • trunk/Source/WebCore/css/DocumentRuleSets.h

    r196555 r196629  
    5353    RuleSet* ancestorClassRules(AtomicStringImpl* className) const;
    5454
     55    struct AttributeRules {
     56        Vector<const CSSSelector*> attributeSelectors;
     57        std::unique_ptr<RuleSet> ruleSet;
     58    };
     59    const AttributeRules* ancestorAttributeRulesForHTML(AtomicStringImpl*) const;
     60
    5561    void initUserStyle(ExtensionStyleSheets&, const MediaQueryEvaluator&, StyleResolver&);
    5662    void resetAuthorStyle();
     
    6874    mutable std::unique_ptr<RuleSet> m_siblingRuleSet;
    6975    mutable std::unique_ptr<RuleSet> m_uncommonAttributeRuleSet;
    70     mutable HashMap<AtomicStringImpl*, std::unique_ptr<RuleSet>> m_ancestorClassRuleSet;
     76    mutable HashMap<AtomicStringImpl*, std::unique_ptr<RuleSet>> m_ancestorClassRuleSets;
     77    mutable HashMap<AtomicStringImpl*, std::unique_ptr<AttributeRules>> m_ancestorAttributeRuleSetsForHTML;
    7178};
    7279
  • trunk/Source/WebCore/css/RuleFeature.cpp

    r196383 r196629  
    4747                selectorFeatures.classesMatchingAncestors.append(selector->value().impl());
    4848        } else if (selector->isAttributeSelector()) {
    49             attributeCanonicalLocalNamesInRules.add(selector->attributeCanonicalLocalName().impl());
    50             attributeLocalNamesInRules.add(selector->attribute().localName().impl());
     49            auto* canonicalLocalName = selector->attributeCanonicalLocalName().impl();
     50            auto* localName = selector->attribute().localName().impl();
     51            attributeCanonicalLocalNamesInRules.add(canonicalLocalName);
     52            attributeLocalNamesInRules.add(localName);
     53            if (matchesAncestor)
     54                selectorFeatures.attributeSelectorsMatchingAncestors.append(selector);
    5155        } else if (selector->match() == CSSSelector::PseudoElement) {
    5256            switch (selector->pseudoElementType()) {
     
    7983}
    8084
     85static std::pair<AtomicStringImpl*, unsigned> makeAttributeSelectorKey(const CSSSelector& selector)
     86{
     87    bool caseInsensitive = selector.attributeValueMatchingIsCaseInsensitive();
     88    unsigned matchAndCase = static_cast<unsigned>(selector.match()) << 1 | caseInsensitive;
     89    return std::make_pair(selector.attributeCanonicalLocalName().impl(), matchAndCase);
     90}
     91
    8192void RuleFeatureSet::collectFeatures(const RuleData& ruleData)
    8293{
     
    92103            addResult.iterator->value = std::make_unique<Vector<RuleFeature>>();
    93104        addResult.iterator->value->append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
     105    }
     106    for (auto* selector : selectorFeatures.attributeSelectorsMatchingAncestors) {
     107        // Hashing by attributeCanonicalLocalName makes this HTML specific.
     108        auto addResult = ancestorAttributeRulesForHTML.add(selector->attributeCanonicalLocalName().impl(), nullptr);
     109        if (addResult.isNewEntry)
     110            addResult.iterator->value = std::make_unique<AttributeRules>();
     111        auto& rules = *addResult.iterator->value;
     112        rules.features.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
     113        // Deduplicate selectors.
     114        rules.selectors.add(makeAttributeSelectorKey(*selector), selector);
    94115    }
    95116}
     
    110131            addResult.iterator->value->appendVector(*keyValuePair.value);
    111132    }
     133    for (auto& keyValuePair : other.ancestorAttributeRulesForHTML) {
     134        auto addResult = ancestorAttributeRulesForHTML.add(keyValuePair.key, nullptr);
     135        if (addResult.isNewEntry)
     136            addResult.iterator->value = std::make_unique<AttributeRules>();
     137        auto& rules = *addResult.iterator->value;
     138        rules.features.appendVector(keyValuePair.value->features);
     139        for (auto& selectorPair : keyValuePair.value->selectors)
     140            rules.selectors.add(selectorPair.key, selectorPair.value);
     141    }
    112142    usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules;
    113143    usesFirstLetterRules = usesFirstLetterRules || other.usesFirstLetterRules;
     
    123153    uncommonAttributeRules.clear();
    124154    ancestorClassRules.clear();
     155    ancestorAttributeRulesForHTML.clear();
    125156    usesFirstLineRules = false;
    126157    usesFirstLetterRules = false;
     
    133164    for (auto& rules : ancestorClassRules.values())
    134165        rules->shrinkToFit();
     166    for (auto& rules : ancestorAttributeRulesForHTML.values())
     167        rules->features.shrinkToFit();
    135168}
    136169
  • trunk/Source/WebCore/css/RuleFeature.h

    r196383 r196629  
    2323#define RuleFeature_h
    2424
     25#include "CSSSelector.h"
    2526#include <wtf/Forward.h>
    2627#include <wtf/HashMap.h>
     
    3031namespace WebCore {
    3132
    32 class CSSSelector;
    3333class RuleData;
    3434class StyleRule;
     
    5959    Vector<RuleFeature> uncommonAttributeRules;
    6060    HashMap<AtomicStringImpl*, std::unique_ptr<Vector<RuleFeature>>> ancestorClassRules;
     61
     62    struct AttributeRules {
     63        HashMap<std::pair<AtomicStringImpl*, unsigned>, const CSSSelector*> selectors;
     64        Vector<RuleFeature> features;
     65    };
     66    HashMap<AtomicStringImpl*, std::unique_ptr<AttributeRules>> ancestorAttributeRulesForHTML;
    6167    bool usesFirstLineRules { false };
    6268    bool usesFirstLetterRules { false };
     
    6672        bool hasSiblingSelector { false };
    6773        Vector<AtomicStringImpl*> classesMatchingAncestors;
     74        Vector<const CSSSelector*> attributeSelectorsMatchingAncestors;
    6875    };
    6976    void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, bool matchesAncestor = false);
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r195311 r196629  
    517517
    518518    return false;
     519}
     520
     521bool SelectorChecker::attributeSelectorMatches(const Element& element, const QualifiedName& attributeName, const AtomicString& attributeValue, const CSSSelector& selector)
     522{
     523    ASSERT(selector.isAttributeSelector());
     524    auto& selectorAttribute = selector.attribute();
     525    auto& selectorName = element.isHTMLElement() ? selector.attributeCanonicalLocalName() : selectorAttribute.localName();
     526    if (!Attribute::nameMatchesFilter(attributeName, selectorAttribute.prefix(), selectorName, selectorAttribute.namespaceURI()))
     527        return false;
     528    bool caseSensitive = true;
     529    if (selector.attributeValueMatchingIsCaseInsensitive())
     530        caseSensitive = false;
     531    else if (element.document().isHTMLDocument() && element.isHTMLElement() && !HTMLDocument::isCaseSensitiveAttribute(selector.attribute()))
     532        caseSensitive = false;
     533    return attributeValueMatches(Attribute(attributeName, attributeValue), selector.match(), selector.value(), caseSensitive);
    519534}
    520535
  • trunk/Source/WebCore/css/SelectorChecker.h

    r195311 r196629  
    120120    static bool isCommonPseudoClassSelector(const CSSSelector*);
    121121    static bool matchesFocusPseudoClass(const Element&);
     122    static bool attributeSelectorMatches(const Element&, const QualifiedName&, const AtomicString& attributeValue, const CSSSelector&);
    122123
    123124    enum LinkMatchMask { MatchDefault = 0, MatchLink = 1, MatchVisited = 2, MatchAll = MatchLink | MatchVisited };
  • trunk/Source/WebCore/dom/Attr.cpp

    r194496 r196629  
    2424#include "Attr.h"
    2525
     26#include "AttributeChangeInvalidation.h"
    2627#include "Event.h"
    2728#include "ExceptionCode.h"
     
    109110    m_ignoreChildrenChanged++;
    110111    removeChildren();
    111     if (m_element)
     112    if (m_element) {
     113        Style::AttributeChangeInvalidation styleInvalidation(*m_element, qualifiedName(), elementAttribute().value(), value);
    112114        elementAttribute().setValue(value);
    113     else
     115    } else
    114116        m_standaloneValue = value;
    115117    createTextChild();
     
    164166        m_element->willModifyAttribute(qualifiedName(), oldValue, newValue);
    165167
    166     if (m_element)
     168    if (m_element) {
     169        Style::AttributeChangeInvalidation styleInvalidation(*m_element, qualifiedName(), oldValue, newValue);
    167170        elementAttribute().setValue(newValue);
    168     else
     171    } else
    169172        m_standaloneValue = newValue;
    170173
  • trunk/Source/WebCore/dom/Element.cpp

    r196598 r196629  
    2929#include "AXObjectCache.h"
    3030#include "Attr.h"
     31#include "AttributeChangeInvalidation.h"
    3132#include "CSSParser.h"
    3233#include "Chrome.h"
     
    11831184    }
    11841185
     1186    if (inSynchronizationOfLazyAttribute) {
     1187        ensureUniqueElementData().attributeAt(index).setValue(newValue);
     1188        return;
     1189    }
     1190
    11851191    const Attribute& attribute = attributeAt(index);
     1192    QualifiedName attributeName = attribute.name();
    11861193    AtomicString oldValue = attribute.value();
    1187     bool valueChanged = newValue != oldValue;
    1188     QualifiedName attributeName = (!inSynchronizationOfLazyAttribute || valueChanged) ? attribute.name() : name;
    1189 
    1190     if (!inSynchronizationOfLazyAttribute)
    1191         willModifyAttribute(attributeName, oldValue, newValue);
    1192 
    1193     if (valueChanged) {
     1194
     1195    willModifyAttribute(attributeName, oldValue, newValue);
     1196
     1197    if (newValue != oldValue) {
    11941198        // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
    11951199        // will write into the ElementData.
    11961200        // FIXME: Refactor this so it makes some sense.
    1197         if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? nullptr : attrIfExists(attributeName))
     1201        if (RefPtr<Attr> attrNode = attrIfExists(attributeName))
    11981202            attrNode->setValue(newValue);
    1199         else
     1203        else {
     1204            Style::AttributeChangeInvalidation styleInvalidation(*this, name, oldValue, newValue);
    12001205            ensureUniqueElementData().attributeAt(index).setValue(newValue);
    1201     }
    1202 
    1203     if (!inSynchronizationOfLazyAttribute)
    1204         didModifyAttribute(attributeName, oldValue, newValue);
     1206        }
     1207    }
     1208
     1209    didModifyAttribute(attributeName, oldValue, newValue);
    12051210}
    12061211
     
    12691274    invalidateNodeListAndCollectionCachesInAncestors(&name, this);
    12701275
    1271     // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
    1272     shouldInvalidateStyle |= !styleResolver;
    1273 
    12741276    if (shouldInvalidateStyle)
    12751277        setNeedsStyleRecalc();
     
    20512053    AtomicString valueBeingRemoved = elementData.attributeAt(index).value();
    20522054
    2053     if (!inSynchronizationOfLazyAttribute) {
    2054         if (!valueBeingRemoved.isNull())
    2055             willModifyAttribute(name, valueBeingRemoved, nullAtom);
    2056     }
    2057 
    20582055    if (RefPtr<Attr> attrNode = attrIfExists(name))
    20592056        detachAttrNodeFromElementWithValue(attrNode.get(), elementData.attributeAt(index).value());
    20602057
    2061     elementData.removeAttribute(index);
    2062 
    2063     if (!inSynchronizationOfLazyAttribute)
    2064         didRemoveAttribute(name, valueBeingRemoved);
     2058    if (inSynchronizationOfLazyAttribute) {
     2059        elementData.removeAttribute(index);
     2060        return;
     2061    }
     2062
     2063    if (!valueBeingRemoved.isNull())
     2064        willModifyAttribute(name, valueBeingRemoved, nullAtom);
     2065
     2066    {
     2067        Style::AttributeChangeInvalidation styleInvalidation(*this, name, valueBeingRemoved, nullAtom);
     2068        elementData.removeAttribute(index);
     2069    }
     2070
     2071    didRemoveAttribute(name, valueBeingRemoved);
    20652072}
    20662073
    20672074void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
    20682075{
    2069     if (!inSynchronizationOfLazyAttribute)
    2070         willModifyAttribute(name, nullAtom, value);
    2071     ensureUniqueElementData().addAttribute(name, value);
    2072     if (!inSynchronizationOfLazyAttribute)
    2073         didAddAttribute(name, value);
     2076    if (inSynchronizationOfLazyAttribute) {
     2077        ensureUniqueElementData().addAttribute(name, value);
     2078        return;
     2079    }
     2080
     2081    willModifyAttribute(name, nullAtom, value);
     2082    {
     2083        Style::AttributeChangeInvalidation styleInvalidation(*this, name, nullAtom, value);
     2084        ensureUniqueElementData().addAttribute(name, value);
     2085    }
     2086    didAddAttribute(name, value);
    20742087}
    20752088
     
    24862499}
    24872500
     2501bool Element::needsStyleInvalidation() const
     2502{
     2503    if (!inRenderedDocument())
     2504        return false;
     2505    if (styleChangeType() >= FullStyleChange)
     2506        return false;
     2507    if (!document().styleResolverIfExists())
     2508        return false;
     2509
     2510    return true;
     2511}
     2512
    24882513void Element::setStyleAffectedByEmpty()
    24892514{
     
    30813106    }
    30823107
    3083     if (oldValue != newValue) {
    3084         auto styleResolver = document().styleResolverIfExists();
    3085         if (styleResolver && styleResolver->hasSelectorForAttribute(*this, name.localName()))
    3086             setNeedsStyleRecalc();
    3087     }
    3088 
    30893108    if (std::unique_ptr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
    30903109        recipients->enqueueMutationRecord(MutationRecord::createAttributes(*this, name, oldValue));
  • trunk/Source/WebCore/dom/Element.h

    r196598 r196629  
    280280    virtual RenderStyle* computedStyle(PseudoId = NOPSEUDO) override;
    281281
     282    bool needsStyleInvalidation() const;
     283
    282284    // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
    283285    bool styleAffectedByEmpty() const { return hasRareData() && rareDataStyleAffectedByEmpty(); }
  • trunk/Source/WebCore/style/ClassChangeInvalidation.h

    r196560 r196629  
    4747    using ClassChangeVector = Vector<AtomicStringImpl*, 4>;
    4848
    49     static bool needsInvalidation(const Element&);
    5049    void computeClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses);
    5150    void invalidateStyle(const ClassChangeVector&);
     
    6059};
    6160
    62 inline bool ClassChangeInvalidation::needsInvalidation(const Element& element)
    63 {
    64     if (!element.inRenderedDocument())
    65         return false;
    66     if (element.styleChangeType() >= FullStyleChange)
    67         return false;
    68     if (!element.document().styleResolverIfExists())
    69         return false;
    70     return true;
    71 }
    72 
    7361inline ClassChangeInvalidation::ClassChangeInvalidation(Element& element, const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses)
    74     : m_isEnabled(needsInvalidation(element))
     62    : m_isEnabled(element.needsStyleInvalidation())
    7563    , m_element(element)
    7664
Note: See TracChangeset for help on using the changeset viewer.