Move more cascade related code from StyleResolver to PropertyCascade
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Oct 2019 23:22:51 +0000 (23:22 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Oct 2019 23:22:51 +0000 (23:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=203409

Reviewed by Zalan Bujtas.

- Move a bunch of StyleResolver member functions to PropertyCascade.
- Make ApplyCascadedPropertyState part of the PropertyCascade internal state.
- Pass around a reference to the PropertyCascade itself instead of the state object
  The state contained PropertyCascade member already so this is equivalent but simpler.

* css/CSSVariableReferenceValue.cpp:
(WebCore::resolveVariableFallback):
(WebCore::resolveVariableReference):
(WebCore::resolveTokenRange):
(WebCore::CSSVariableReferenceValue::resolveVariableReferences const):
* css/CSSVariableReferenceValue.h:
* css/ElementRuleCollector.h:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::styleForKeyframe):
(WebCore::StyleResolver::styleForPage):
(WebCore::StyleResolver::applyMatchedProperties):
(WebCore::StyleResolver::applyPropertyToCurrentStyle):
(WebCore::StyleResolver::applyProperty):
(WebCore::StyleResolver::resolvedVariableValue const):
(WebCore::StyleResolver::cascadedPropertiesForRollback): Deleted.
(WebCore::StyleResolver::applyCascadedCustomProperty): Deleted.
(WebCore::StyleResolver::applyCascadedProperties): Deleted.
(WebCore::StyleResolver::applyCascadedPropertiesImpl): Deleted.

These become PropertyCascade members.

* css/StyleResolver.h:
(WebCore::StyleResolver::State::authorRollback const): Deleted.
(WebCore::StyleResolver::State::userRollback const): Deleted.
(WebCore::StyleResolver::State::setAuthorRollback): Deleted.
(WebCore::StyleResolver::State::setUserRollback): Deleted.

Rollbacks are now owned by PropertyCascade.

* css/parser/CSSParser.cpp:
(WebCore::CSSParser::parseValueWithVariableReferences):
* css/parser/CSSParser.h:
* style/PropertyCascade.cpp:
(WebCore::Style::PropertyCascade::PropertyCascade):
(WebCore::Style::PropertyCascade::set):
(WebCore::Style::PropertyCascade::addNormalMatches):
(WebCore::Style::PropertyCascade::addImportantMatches):
(WebCore::Style::PropertyCascade::applyDeferredProperties):
(WebCore::Style::PropertyCascade::applyProperties):
(WebCore::Style::PropertyCascade::applyPropertiesImpl):
(WebCore::Style::PropertyCascade::applyCustomProperties):
(WebCore::Style::PropertyCascade::applyCustomProperty):
(WebCore::Style::PropertyCascade::propertyCascadeForRollback):
(WebCore::Style::PropertyCascade::Property::apply):
* style/PropertyCascade.h:
(WebCore::Style::PropertyCascade::styleResolver):
(WebCore::Style::PropertyCascade::hasAppliedProperty const):
(WebCore::Style::PropertyCascade::customProperties): Deleted.

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

Source/WebCore/ChangeLog
Source/WebCore/css/CSSVariableReferenceValue.cpp
Source/WebCore/css/CSSVariableReferenceValue.h
Source/WebCore/css/ElementRuleCollector.h
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/css/parser/CSSParser.cpp
Source/WebCore/css/parser/CSSParser.h
Source/WebCore/style/PropertyCascade.cpp
Source/WebCore/style/PropertyCascade.h

index c72271b..a2ba016 100644 (file)
@@ -1,3 +1,64 @@
+2019-10-25  Antti Koivisto  <antti@apple.com>
+
+        Move more cascade related code from StyleResolver to PropertyCascade
+        https://bugs.webkit.org/show_bug.cgi?id=203409
+
+        Reviewed by Zalan Bujtas.
+
+        - Move a bunch of StyleResolver member functions to PropertyCascade.
+        - Make ApplyCascadedPropertyState part of the PropertyCascade internal state.
+        - Pass around a reference to the PropertyCascade itself instead of the state object
+          The state contained PropertyCascade member already so this is equivalent but simpler.
+
+        * css/CSSVariableReferenceValue.cpp:
+        (WebCore::resolveVariableFallback):
+        (WebCore::resolveVariableReference):
+        (WebCore::resolveTokenRange):
+        (WebCore::CSSVariableReferenceValue::resolveVariableReferences const):
+        * css/CSSVariableReferenceValue.h:
+        * css/ElementRuleCollector.h:
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::styleForKeyframe):
+        (WebCore::StyleResolver::styleForPage):
+        (WebCore::StyleResolver::applyMatchedProperties):
+        (WebCore::StyleResolver::applyPropertyToCurrentStyle):
+        (WebCore::StyleResolver::applyProperty):
+        (WebCore::StyleResolver::resolvedVariableValue const):
+        (WebCore::StyleResolver::cascadedPropertiesForRollback): Deleted.
+        (WebCore::StyleResolver::applyCascadedCustomProperty): Deleted.
+        (WebCore::StyleResolver::applyCascadedProperties): Deleted.
+        (WebCore::StyleResolver::applyCascadedPropertiesImpl): Deleted.
+
+        These become PropertyCascade members.
+
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::State::authorRollback const): Deleted.
+        (WebCore::StyleResolver::State::userRollback const): Deleted.
+        (WebCore::StyleResolver::State::setAuthorRollback): Deleted.
+        (WebCore::StyleResolver::State::setUserRollback): Deleted.
+
+        Rollbacks are now owned by PropertyCascade.
+
+        * css/parser/CSSParser.cpp:
+        (WebCore::CSSParser::parseValueWithVariableReferences):
+        * css/parser/CSSParser.h:
+        * style/PropertyCascade.cpp:
+        (WebCore::Style::PropertyCascade::PropertyCascade):
+        (WebCore::Style::PropertyCascade::set):
+        (WebCore::Style::PropertyCascade::addNormalMatches):
+        (WebCore::Style::PropertyCascade::addImportantMatches):
+        (WebCore::Style::PropertyCascade::applyDeferredProperties):
+        (WebCore::Style::PropertyCascade::applyProperties):
+        (WebCore::Style::PropertyCascade::applyPropertiesImpl):
+        (WebCore::Style::PropertyCascade::applyCustomProperties):
+        (WebCore::Style::PropertyCascade::applyCustomProperty):
+        (WebCore::Style::PropertyCascade::propertyCascadeForRollback):
+        (WebCore::Style::PropertyCascade::Property::apply):
+        * style/PropertyCascade.h:
+        (WebCore::Style::PropertyCascade::styleResolver):
+        (WebCore::Style::PropertyCascade::hasAppliedProperty const):
+        (WebCore::Style::PropertyCascade::customProperties): Deleted.
+
 2019-10-25  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][IFC] Add support for no-wrap
index 94d63a3..f84b8b6 100644 (file)
@@ -30,6 +30,7 @@
 #include "config.h"
 #include "CSSVariableReferenceValue.h"
 
+#include "PropertyCascade.h"
 #include "RenderStyle.h"
 #include "StyleResolver.h"
 
@@ -44,21 +45,21 @@ String CSSVariableReferenceValue::customCSSText() const
     return m_stringValue;
 }
 
-static bool resolveTokenRange(CSSParserTokenRange, Vector<CSSParserToken>&, ApplyCascadedPropertyState&);
+static bool resolveTokenRange(CSSParserTokenRange, Vector<CSSParserToken>&, Style::PropertyCascade&);
 
-static bool resolveVariableFallback(CSSParserTokenRange range, Vector<CSSParserToken>& result, ApplyCascadedPropertyState& state)
+static bool resolveVariableFallback(CSSParserTokenRange range, Vector<CSSParserToken>& result, Style::PropertyCascade& cascade)
 {
     if (range.atEnd())
         return false;
     ASSERT(range.peek().type() == CommaToken);
     range.consume();
-    return resolveTokenRange(range, result, state);
+    return resolveTokenRange(range, result, cascade);
 }
 
-static bool resolveVariableReference(CSSParserTokenRange range, Vector<CSSParserToken>& result, ApplyCascadedPropertyState& state)
+static bool resolveVariableReference(CSSParserTokenRange range, Vector<CSSParserToken>& result, Style::PropertyCascade& cascade)
 {
-    auto& registeredProperties = state.styleResolver->document().getCSSRegisteredCustomPropertySet();
-    auto& style = *state.styleResolver->style();
+    auto& registeredProperties = cascade.styleResolver().document().getCSSRegisteredCustomPropertySet();
+    auto& style = *cascade.styleResolver().style();
 
     range.consumeWhitespace();
     ASSERT(range.peek().type() == IdentToken);
@@ -66,11 +67,11 @@ static bool resolveVariableReference(CSSParserTokenRange range, Vector<CSSParser
     ASSERT(range.atEnd() || (range.peek().type() == CommaToken));
 
     // Apply this variable first, in case it is still unresolved
-    state.styleResolver->applyCascadedCustomProperty(variableName, state);
+    cascade.applyCustomProperty(variableName);
 
     // Apply fallback to detect cycles
     Vector<CSSParserToken> fallbackResult;
-    bool fallbackReturn = resolveVariableFallback(CSSParserTokenRange(range), fallbackResult, state);
+    bool fallbackReturn = resolveVariableFallback(CSSParserTokenRange(range), fallbackResult, cascade);
 
     auto* property = style.getCustomProperty(variableName);
 
@@ -92,24 +93,24 @@ static bool resolveVariableReference(CSSParserTokenRange range, Vector<CSSParser
     return true;
 }
 
-static bool resolveTokenRange(CSSParserTokenRange range, Vector<CSSParserToken>& result, ApplyCascadedPropertyState& state)
+static bool resolveTokenRange(CSSParserTokenRange range, Vector<CSSParserToken>& result, Style::PropertyCascade& cascade)
 {
     bool success = true;
     while (!range.atEnd()) {
         if (range.peek().functionId() == CSSValueVar || range.peek().functionId() == CSSValueEnv)
-            success &= resolveVariableReference(range.consumeBlock(), result, state);
+            success &= resolveVariableReference(range.consumeBlock(), result, cascade);
         else
             result.append(range.consume());
     }
     return success;
 }
 
-RefPtr<CSSVariableData> CSSVariableReferenceValue::resolveVariableReferences(ApplyCascadedPropertyState& state) const
+RefPtr<CSSVariableData> CSSVariableReferenceValue::resolveVariableReferences(Style::PropertyCascade& cascade) const
 {
     Vector<CSSParserToken> resolvedTokens;
     CSSParserTokenRange range = m_data->tokenRange();
 
-    if (!resolveTokenRange(range, resolvedTokens, state))
+    if (!resolveTokenRange(range, resolvedTokens, cascade))
         return nullptr;
 
     return CSSVariableData::create(resolvedTokens);
index d70e327..9a120c3 100644 (file)
 
 namespace WebCore {
 
-struct ApplyCascadedPropertyState;
 class CSSParserTokenRange;
 
+namespace Style {
+class PropertyCascade;
+}
+
 class CSSVariableReferenceValue : public CSSValue {
 public:
     static Ref<CSSVariableReferenceValue> create(const CSSParserTokenRange& range)
@@ -52,7 +55,7 @@ public:
     bool equals(const CSSVariableReferenceValue& other) const { return m_data.get() == other.m_data.get(); }
     String customCSSText() const;
 
-    RefPtr<CSSVariableData> resolveVariableReferences(ApplyCascadedPropertyState&) const;
+    RefPtr<CSSVariableData> resolveVariableReferences(Style::PropertyCascade&) const;
 
 private:
     CSSVariableReferenceValue(Ref<CSSVariableData>&& data)
index 5e53531..dba8e95 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "MediaQueryEvaluator.h"
+#include "RuleSet.h"
 #include "SelectorChecker.h"
 #include "StyleScope.h"
 #include <memory>
@@ -32,8 +33,6 @@ namespace WebCore {
 
 class DocumentRuleSets;
 class MatchRequest;
-class RuleData;
-class RuleSet;
 class SelectorFilter;
 
 class PseudoStyleRequest {
index fe6b6d9..1f86bd7 100644 (file)
@@ -76,6 +76,7 @@
 #include "PageRuleCollector.h"
 #include "PaintWorkletGlobalScope.h"
 #include "Pair.h"
+#include "PropertyCascade.h"
 #include "Quirks.h"
 #include "RenderScrollbar.h"
 #include "RenderStyleConstants.h"
@@ -373,24 +374,23 @@ std::unique_ptr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle*
 
     // We don't need to bother with !important. Since there is only ever one
     // decl, there's nothing to override. So just add the first properties.
-    Style::PropertyCascade cascade(direction, writingMode);
-    cascade.addNormalMatches(result, Style::CascadeLevel::Author);
+    Style::PropertyCascade cascade(*this, result, direction, writingMode);
+    cascade.addNormalMatches(Style::CascadeLevel::Author);
 
-    ApplyCascadedPropertyState applyState { this, &cascade, &result };
-    applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
+    cascade.applyProperties(firstCSSProperty, lastHighPriorityProperty);
 
     // If our font got dirtied, update it now.
     updateFont();
 
     // Now resolve remaining custom properties and the rest, in any order
-    for (auto it = cascade.customProperties().begin(); it != cascade.customProperties().end(); ++it)
-        applyCascadedCustomProperty(it->key, applyState);
-    applyCascadedProperties(firstLowPriorityProperty, lastCSSProperty, applyState);
+    cascade.applyCustomProperties();
+
+    cascade.applyProperties(firstLowPriorityProperty, lastCSSProperty);
 
     // If our font got dirtied by one of the non-essential font props, update it a second time.
     updateFont();
 
-    cascade.applyDeferredProperties(*this, applyState);
+    cascade.applyDeferredProperties();
 
     adjustRenderStyle(*state.style(), *state.parentStyle(), nullptr, nullptr);
 
@@ -579,21 +579,20 @@ std::unique_ptr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
     WritingMode writingMode;
     extractDirectionAndWritingMode(*m_state.style(), result, direction, writingMode);
 
-    Style::PropertyCascade cascade(direction, writingMode);
-    cascade.addNormalMatches(result, Style::CascadeLevel::Author);
+    Style::PropertyCascade cascade(*this, result, direction, writingMode);
+    cascade.addNormalMatches(Style::CascadeLevel::Author);
 
-    ApplyCascadedPropertyState applyState { this, &cascade, &result };
-    applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
+    cascade.applyProperties(firstCSSProperty, lastHighPriorityProperty);
 
     // If our font got dirtied, update it now.
     updateFont();
 
     // Now resolve remaining custom properties and the rest, in any order
-    for (auto it = cascade.customProperties().begin(); it != cascade.customProperties().end(); ++it)
-        applyCascadedCustomProperty(it->key, applyState);
-    applyCascadedProperties(firstLowPriorityProperty, lastCSSProperty, applyState);
+    cascade.applyCustomProperties();
+
+    cascade.applyProperties(firstLowPriorityProperty, lastCSSProperty);
 
-    cascade.applyDeferredProperties(*this, applyState);
+    cascade.applyDeferredProperties();
 
     // Now return the style.
     return m_state.takeStyle();
@@ -1382,52 +1381,48 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
         // Find out if there's a -webkit-appearance property in effect from the UA sheet.
         // If so, we cache the border and background styles so that RenderTheme::adjustStyle()
         // can look at them later to figure out if this is a styled form control or not.
-        Style::PropertyCascade cascade(direction, writingMode);
-        cascade.addNormalMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
-        cascade.addImportantMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
-
-        ApplyCascadedPropertyState applyState { this, &cascade, &matchResult };
+        Style::PropertyCascade cascade(*this, matchResult, direction, writingMode);
+        cascade.addNormalMatches(Style::CascadeLevel::UserAgent, applyInheritedOnly);
+        cascade.addImportantMatches(Style::CascadeLevel::UserAgent, applyInheritedOnly);
 
-        applyCascadedProperties(CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, applyState);
+        cascade.applyProperties(CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition);
         adjustStyleForInterCharacterRuby();
 
 #if ENABLE(DARK_MODE_CSS)
         // Supported color schemes can affect resolved colors, so we need to apply that property before any color properties.
-        applyCascadedProperties(CSSPropertyColorScheme, CSSPropertyColorScheme, applyState);
+        cascade.applyProperties(CSSPropertyColorScheme, CSSPropertyColorScheme);
 #endif
 
-        applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
+        cascade.applyProperties(firstCSSProperty, lastHighPriorityProperty);
 
         // If our font got dirtied, update it now.
         updateFont();
 
         // Now resolve remaining custom properties and the rest, in any order
-        for (auto it = cascade.customProperties().begin(); it != cascade.customProperties().end(); ++it)
-            applyCascadedCustomProperty(it->key, applyState);
-        applyCascadedProperties(firstLowPriorityProperty, lastCSSProperty, applyState);
+        cascade.applyCustomProperties();
+
+        cascade.applyProperties(firstLowPriorityProperty, lastCSSProperty);
 
         state.cacheBorderAndBackground();
     }
 
-    Style::PropertyCascade cascade(direction, writingMode);
-    cascade.addNormalMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
-    cascade.addNormalMatches(matchResult, Style::CascadeLevel::User, applyInheritedOnly);
-    cascade.addNormalMatches(matchResult, Style::CascadeLevel::Author, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, Style::CascadeLevel::Author, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, Style::CascadeLevel::User, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
-
-    ApplyCascadedPropertyState applyState { this, &cascade, &matchResult };
+    Style::PropertyCascade cascade(*this, matchResult, direction, writingMode);
+    cascade.addNormalMatches(Style::CascadeLevel::UserAgent, applyInheritedOnly);
+    cascade.addNormalMatches(Style::CascadeLevel::User, applyInheritedOnly);
+    cascade.addNormalMatches(Style::CascadeLevel::Author, applyInheritedOnly);
+    cascade.addImportantMatches(Style::CascadeLevel::Author, applyInheritedOnly);
+    cascade.addImportantMatches(Style::CascadeLevel::User, applyInheritedOnly);
+    cascade.addImportantMatches(Style::CascadeLevel::UserAgent, applyInheritedOnly);
 
-    applyCascadedProperties(CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, applyState);
+    cascade.applyProperties(CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition);
     adjustStyleForInterCharacterRuby();
 
 #if ENABLE(DARK_MODE_CSS)
     // Supported color schemes can affect resolved colors, so we need to apply that property before any color properties.
-    applyCascadedProperties(CSSPropertyColorScheme, CSSPropertyColorScheme, applyState);
+    cascade.applyProperties(CSSPropertyColorScheme, CSSPropertyColorScheme);
 #endif
 
-    applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
+    cascade.applyProperties(firstCSSProperty, lastHighPriorityProperty);
 
     // If the effective zoom value changes, we can't use the matched properties cache. Start over.
     if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom())
@@ -1441,14 +1436,14 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
         return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
 
     // Now resolve remaining custom properties and the rest, in any order
-    for (auto it = cascade.customProperties().begin(); it != cascade.customProperties().end(); ++it)
-        applyCascadedCustomProperty(it->key, applyState);
-    applyCascadedProperties(firstLowPriorityProperty, lastCSSProperty, applyState);
+    cascade.applyCustomProperties();
+
+    cascade.applyProperties(firstLowPriorityProperty, lastCSSProperty);
 
     // Finally, some properties must be applied in the order they were parsed.
     // There are some CSS properties that affect the same RenderStyle values,
     // so to preserve behavior, we queue them up during cascade and flush here.
-    cascade.applyDeferredProperties(*this, applyState);
+    cascade.applyDeferredProperties();
 
     ASSERT(!state.fontDirty());
 
@@ -1469,9 +1464,10 @@ void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, std:
 
 void StyleResolver::applyPropertyToCurrentStyle(CSSPropertyID id, CSSValue* value)
 {
-    ApplyCascadedPropertyState applyState { this, nullptr, nullptr };
+    MatchResult matchResult;
+    Style::PropertyCascade cascade(*this, matchResult, { }, { });
     if (value)
-        applyProperty(id, value, applyState);
+        applyProperty(id, value, cascade);
 }
 
 inline bool isValidVisitedLinkProperty(CSSPropertyID id)
@@ -1520,64 +1516,17 @@ bool StyleResolver::useSVGZoomRulesForLength() const
     return is<SVGElement>(m_state.element()) && !(is<SVGSVGElement>(*m_state.element()) && m_state.element()->parentNode());
 }
 
-Style::PropertyCascade* StyleResolver::cascadedPropertiesForRollback(const MatchResult& matchResult)
-{
-    TextDirection direction;
-    WritingMode writingMode;
-    extractDirectionAndWritingMode(*state().style(), matchResult, direction, writingMode);
-
-    switch (state().cascadeLevel()) {
-    case Style::CascadeLevel::Author: {
-        auto* authorRollback = state().authorRollback();
-        if (authorRollback)
-            return authorRollback;
-
-        auto newAuthorRollback = makeUnique<Style::PropertyCascade>(direction, writingMode);
-
-        // This special rollback cascade contains UA rules and user rules but no author rules.
-        newAuthorRollback->addNormalMatches(matchResult, Style::CascadeLevel::UserAgent, false);
-        newAuthorRollback->addNormalMatches(matchResult, Style::CascadeLevel::User, false);
-        newAuthorRollback->addImportantMatches(matchResult, Style::CascadeLevel::User, false);
-        newAuthorRollback->addImportantMatches(matchResult, Style::CascadeLevel::UserAgent, false);
-
-        state().setAuthorRollback(newAuthorRollback);
-        return state().authorRollback();
-    }
-
-    case Style::CascadeLevel::User: {
-        auto* userRollback = state().userRollback();
-        if (userRollback)
-            return userRollback;
-
-        auto newUserRollback = makeUnique<Style::PropertyCascade>(direction, writingMode);
-
-        // This special rollback cascade contains only UA rules.
-        newUserRollback->addNormalMatches(matchResult, Style::CascadeLevel::UserAgent, false);
-        newUserRollback->addImportantMatches(matchResult, Style::CascadeLevel::UserAgent, false);
-
-        state().setUserRollback(newUserRollback);
-        return state().userRollback();
-    }
-
-    case Style::CascadeLevel::UserAgent:
-        break;
-    }
-    ASSERT_NOT_REACHED();
-    return nullptr;
-}
-
-void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, ApplyCascadedPropertyState& applyState, SelectorChecker::LinkMatchMask linkMatchMask)
+void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, Style::PropertyCascade& cascade, SelectorChecker::LinkMatchMask linkMatchMask)
 {
-    auto* matchResult = applyState.matchResult;
     ASSERT_WITH_MESSAGE(!isShorthandCSSProperty(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
 
     State& state = m_state;
 
     RefPtr<CSSValue> valueToApply = value;
     if (value->hasVariableReferences()) {
-        valueToApply = resolvedVariableValue(id, *value, applyState);
-        // If appliedProperties already has this id, then we detected a cycle, and this value should be unset.
-        if (!valueToApply || applyState.appliedProperties.get(id)) {
+        valueToApply = resolvedVariableValue(id, *value, cascade);
+        // If the cascade has already applied this id, then we detected a cycle, and this value should be unset.
+        if (!valueToApply || cascade.hasAppliedProperty(id)) {
             if (CSSProperty::isInheritedProperty(id))
                 valueToApply = CSSValuePool::singleton().createInheritedValue();
             else
@@ -1588,7 +1537,7 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, ApplyCascad
     if (CSSProperty::isDirectionAwareProperty(id)) {
         CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, state.style()->direction(), state.style()->writingMode());
         ASSERT(newId != id);
-        return applyProperty(newId, valueToApply.get(), applyState, linkMatchMask);
+        return applyProperty(newId, valueToApply.get(), cascade, linkMatchMask);
     }
 
     CSSValue* valueToCheckForInheritInitial = valueToApply.get();
@@ -1613,12 +1562,10 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, ApplyCascad
     bool isRevert = valueToCheckForInheritInitial->isRevertValue() || customPropertyValueID == CSSValueRevert;
 
     if (isRevert) {
-        if (state.cascadeLevel() == Style::CascadeLevel::UserAgent || !matchResult)
+        if (state.cascadeLevel() == Style::CascadeLevel::UserAgent)
             isUnset = true;
         else {
-            // Fetch the correct rollback object from the state, building it if necessary.
-            // This requires having the original MatchResult available.
-            auto* rollback = cascadedPropertiesForRollback(*matchResult);
+            auto* rollback = cascade.propertyCascadeForRollback(state.cascadeLevel());
             ASSERT(rollback);
 
             // With the cascade built, we need to obtain the property and apply it. If the property is
@@ -1628,13 +1575,13 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, ApplyCascad
                 if (customPropertyRegistered && customPropertyRegistered->inherits && rollback->hasCustomProperty(customPropertyValue->name())) {
                     auto property = rollback->customProperty(customPropertyValue->name());
                     if (property.cssValue[linkMatchMask])
-                        applyProperty(property.id, property.cssValue[linkMatchMask], applyState, linkMatchMask);
+                        applyProperty(property.id, property.cssValue[linkMatchMask], cascade, linkMatchMask);
                     return;
                 }
             } else if (rollback->hasProperty(id)) {
                 auto& property = rollback->property(id);
                 if (property.cssValue[linkMatchMask])
-                    applyProperty(property.id, property.cssValue[linkMatchMask], applyState, linkMatchMask);
+                    applyProperty(property.id, property.cssValue[linkMatchMask], cascade, linkMatchMask);
                 return;
             }
 
@@ -1676,10 +1623,10 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, ApplyCascad
     StyleBuilder::applyProperty(id, *this, *valueToApply, isInitial, isInherit, customPropertyRegistered);
 }
 
-RefPtr<CSSValue> StyleResolver::resolvedVariableValue(CSSPropertyID propID, const CSSValue& value, ApplyCascadedPropertyState& state) const
+RefPtr<CSSValue> StyleResolver::resolvedVariableValue(CSSPropertyID propID, const CSSValue& value, Style::PropertyCascade& cascade) const
 {
     CSSParser parser(document());
-    return parser.parseValueWithVariableReferences(propID, value, state);
+    return parser.parseValueWithVariableReferences(propID, value, cascade);
 }
 
 RefPtr<StyleImage> StyleResolver::styleImage(CSSValue& value)
@@ -2030,114 +1977,4 @@ bool StyleResolver::createFilterOperations(const CSSValue& inValue, FilterOperat
     return true;
 }
 
-void StyleResolver::applyCascadedCustomProperty(const String& name, ApplyCascadedPropertyState& state)
-{
-    if (state.appliedCustomProperties.contains(name) || !state.cascade->customProperties().contains(name))
-        return;
-
-    auto property = state.cascade->customProperties().get(name);
-    bool inCycle = state.inProgressPropertiesCustom.contains(name);
-
-    for (auto index : { SelectorChecker::MatchDefault, SelectorChecker::MatchLink, SelectorChecker::MatchVisited }) {
-        if (!property.cssValue[index])
-            continue;
-        if (index != SelectorChecker::MatchDefault && this->state().style()->insideLink() == InsideLink::NotInside)
-            continue;
-
-        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
-
-        if (inCycle) {
-            state.appliedCustomProperties.add(name); // Make sure we do not try to apply this property again while resolving it.
-            valueToApply = CSSCustomPropertyValue::createWithID(name, CSSValueInvalid);
-        }
-
-        state.inProgressPropertiesCustom.add(name);
-
-        if (WTF::holds_alternative<Ref<CSSVariableReferenceValue>>(valueToApply->value())) {
-            RefPtr<CSSValue> parsedValue = resolvedVariableValue(CSSPropertyCustom, valueToApply.get(), state);
-
-            if (state.appliedCustomProperties.contains(name))
-                return; // There was a cycle and the value was reset, so bail.
-
-            if (!parsedValue)
-                parsedValue = CSSCustomPropertyValue::createWithID(name, CSSValueUnset);
-
-            valueToApply = downcast<CSSCustomPropertyValue>(*parsedValue);
-        }
-
-        if (state.inProgressPropertiesCustom.contains(name)) {
-            if (index == SelectorChecker::MatchDefault) {
-                this->state().setApplyPropertyToRegularStyle(true);
-                this->state().setApplyPropertyToVisitedLinkStyle(false);
-            }
-
-            if (index == SelectorChecker::MatchLink) {
-                this->state().setApplyPropertyToRegularStyle(true);
-                this->state().setApplyPropertyToVisitedLinkStyle(false);
-            }
-
-            if (index == SelectorChecker::MatchVisited) {
-                this->state().setApplyPropertyToRegularStyle(false);
-                this->state().setApplyPropertyToVisitedLinkStyle(true);
-            }
-            applyProperty(CSSPropertyCustom, valueToApply.ptr(), state, index);
-        }
-    }
-
-    state.inProgressPropertiesCustom.remove(name);
-    state.appliedCustomProperties.add(name);
-
-    for (auto index : { SelectorChecker::MatchDefault, SelectorChecker::MatchLink, SelectorChecker::MatchVisited }) {
-        if (!property.cssValue[index])
-            continue;
-        if (index != SelectorChecker::MatchDefault && this->state().style()->insideLink() == InsideLink::NotInside)
-            continue;
-
-        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
-
-        if (inCycle && WTF::holds_alternative<Ref<CSSVariableReferenceValue>>(valueToApply->value())) {
-            // Resolve this value so that we reset its dependencies.
-            resolvedVariableValue(CSSPropertyCustom, valueToApply.get(), state);
-        }
-    }
-}
-
-void StyleResolver::applyCascadedProperties(int firstProperty, int lastProperty, ApplyCascadedPropertyState& state)
-{
-    if (LIKELY(state.cascade->customProperties().isEmpty()))
-        return applyCascadedPropertiesImpl<CustomPropertyCycleTracking::Disabled>(firstProperty, lastProperty, state);
-    return applyCascadedPropertiesImpl<CustomPropertyCycleTracking::Enabled>(firstProperty, lastProperty, state);
-}
-
-template<StyleResolver::CustomPropertyCycleTracking TrackCycles>
-inline void StyleResolver::applyCascadedPropertiesImpl(int firstProperty, int lastProperty, ApplyCascadedPropertyState& state)
-{
-    for (int id = firstProperty; id <= lastProperty; ++id) {
-        CSSPropertyID propertyID = static_cast<CSSPropertyID>(id);
-        if (!state.cascade->hasProperty(propertyID))
-            continue;
-        ASSERT(propertyID != CSSPropertyCustom);
-        auto& property = state.cascade->property(propertyID);
-
-        if (TrackCycles == CustomPropertyCycleTracking::Disabled) {
-            // If we don't have any custom properties, then there can't be any cycles.
-            property.apply(*this, state);
-        } else {
-            if (UNLIKELY(state.inProgressProperties.get(propertyID))) {
-                // We are in a cycle (eg. setting font size using registered custom property value containing em).
-                // So this value should be unset.
-                state.appliedProperties.set(propertyID);
-                // This property is in a cycle, and only the root of the call stack will have firstProperty != lastProperty.
-                ASSERT(firstProperty == lastProperty);
-                continue;
-            }
-
-            state.inProgressProperties.set(propertyID);
-            property.apply(*this, state);
-            state.appliedProperties.set(propertyID);
-            state.inProgressProperties.set(propertyID, false);
-        }
-    }
-}
-
 } // namespace WebCore
index fdc5fb3..c07c8ef 100644 (file)
@@ -201,9 +201,6 @@ public:
 
     bool createFilterOperations(const CSSValue& inValue, FilterOperations& outOperations);
 
-    void applyCascadedProperties(int firstProperty, int lastProperty, ApplyCascadedPropertyState&);
-    void applyCascadedCustomProperty(const String& name, ApplyCascadedPropertyState&);
-
 private:
     // This function fixes up the default font size if it detects that the current generic font family has changed. -dwh
     void checkForGenericFamilyChange(RenderStyle&, const RenderStyle* parentStyle);
@@ -214,22 +211,12 @@ private:
 
     void adjustRenderStyle(RenderStyle&, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const Element*);
     void adjustRenderStyleForSiteSpecificQuirks(RenderStyle&, const Element&);
-
-    std::unique_ptr<GridPosition> adjustNamedGridItemPosition(const NamedGridAreaMap&, const NamedGridLinesMap&, const GridPosition&, GridPositionSide) const;
     
     void adjustStyleForInterCharacterRuby();
     
-    bool fastRejectSelector(const RuleData&) const;
-
     enum ShouldUseMatchedPropertiesCache { DoNotUseMatchedPropertiesCache = 0, UseMatchedPropertiesCache };
     void applyMatchedProperties(const MatchResult&, const Element&, ShouldUseMatchedPropertiesCache = UseMatchedPropertiesCache);
 
-    enum CustomPropertyCycleTracking { Enabled = 0, Disabled };
-    template<CustomPropertyCycleTracking>
-    inline void applyCascadedPropertiesImpl(int firstProperty, int lastProperty, ApplyCascadedPropertyState&);
-
-    void cascadeMatches(Style::PropertyCascade&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
-
     DocumentRuleSets m_ruleSets;
 
     typedef HashMap<AtomStringImpl*, RefPtr<StyleRuleKeyframes>> KeyframesRuleMap;
@@ -291,12 +278,6 @@ public:
         Style::ScopeOrdinal styleScopeOrdinal() const { return m_styleScopeOrdinal; }
         void setStyleScopeOrdinal(Style::ScopeOrdinal styleScopeOrdinal) { m_styleScopeOrdinal = styleScopeOrdinal; }
 
-        Style::PropertyCascade* authorRollback() const { return m_authorRollback.get(); }
-        Style::PropertyCascade* userRollback() const { return m_userRollback.get(); }
-        
-        void setAuthorRollback(std::unique_ptr<Style::PropertyCascade>& rollback) { m_authorRollback = WTFMove(rollback); }
-        void setUserRollback(std::unique_ptr<Style::PropertyCascade>& rollback) { m_userRollback = WTFMove(rollback); }
-
         const SelectorFilter* selectorFilter() const { return m_selectorFilter; }
         
     private:
@@ -307,8 +288,6 @@ public:
         const RenderStyle* m_parentStyle { nullptr };
         std::unique_ptr<RenderStyle> m_ownedParentStyle;
         const RenderStyle* m_rootElementStyle { nullptr };
-        std::unique_ptr<Style::PropertyCascade> m_authorRollback;
-        std::unique_ptr<Style::PropertyCascade> m_userRollback;
 
         const SelectorFilter* m_selectorFilter { nullptr };
 
@@ -338,8 +317,6 @@ public:
     bool applyPropertyToRegularStyle() const { return m_state.applyPropertyToRegularStyle(); }
     bool applyPropertyToVisitedLinkStyle() const { return m_state.applyPropertyToVisitedLinkStyle(); }
 
-    Style::PropertyCascade* cascadedPropertiesForRollback(const MatchResult&);
-
     CSSToStyleMap* styleMap() { return &m_styleMap; }
     InspectorCSSOMWrappers& inspectorCSSOMWrappers() { return m_inspectorCSSOMWrappers; }
     const FontCascadeDescription& fontDescription() { return m_state.fontDescription(); }
@@ -350,11 +327,11 @@ public:
     void setWritingMode(WritingMode writingMode) { m_state.setWritingMode(writingMode); }
     void setTextOrientation(TextOrientation textOrientation) { m_state.setTextOrientation(textOrientation); }
 
-    RefPtr<CSSValue> resolvedVariableValue(CSSPropertyID, const CSSValue&, ApplyCascadedPropertyState&) const;
+    RefPtr<CSSValue> resolvedVariableValue(CSSPropertyID, const CSSValue&, Style::PropertyCascade&) const;
 
     bool adjustRenderStyleForTextAutosizing(RenderStyle&, const Element&);
 
-    void applyProperty(CSSPropertyID, CSSValue*, ApplyCascadedPropertyState&, SelectorChecker::LinkMatchMask = SelectorChecker::MatchDefault);
+    void applyProperty(CSSPropertyID, CSSValue*, Style::PropertyCascade&, SelectorChecker::LinkMatchMask = SelectorChecker::MatchDefault);
 
 private:
     void cacheBorderAndBackground();
@@ -419,18 +396,6 @@ private:
     bool m_isDeleted { false };
 };
 
-// State to use when applying properties, to keep track of which custom and high-priority
-// properties have been resolved.
-struct ApplyCascadedPropertyState {
-    StyleResolver* styleResolver;
-    Style::PropertyCascade* cascade;
-    const MatchResult* matchResult;
-    Bitmap<numCSSProperties> appliedProperties = { };
-    HashSet<String> appliedCustomProperties = { };
-    Bitmap<numCSSProperties> inProgressProperties = { };
-    HashSet<String> inProgressPropertiesCustom = { };
-};
-
 inline bool StyleResolver::hasSelectorForAttribute(const Element& element, const AtomString &attributeName) const
 {
     ASSERT(!attributeName.isEmpty());
index d64ffeb..cc9bd29 100644 (file)
@@ -42,6 +42,7 @@
 #include "Document.h"
 #include "Element.h"
 #include "Page.h"
+#include "PropertyCascade.h"
 #include "RenderStyle.h"
 #include "RenderTheme.h"
 #include "Settings.h"
@@ -176,10 +177,10 @@ void CSSParser::parseDeclarationForInspector(const CSSParserContext& context, co
     CSSParserImpl::parseDeclarationListForInspector(string, context, observer);
 }
 
-RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propID, const CSSValue& value, ApplyCascadedPropertyState& state)
+RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propID, const CSSValue& value, Style::PropertyCascade& cascade)
 {
     ASSERT((propID == CSSPropertyCustom && value.isCustomPropertyValue()) || (propID != CSSPropertyCustom && !value.isCustomPropertyValue()));
-    auto& style = *state.styleResolver->style();
+    auto& style = *cascade.styleResolver().style();
     auto direction = style.direction();
     auto writingMode = style.writingMode();
 
@@ -192,7 +193,7 @@ RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propI
             shorthandID = CSSProperty::resolveDirectionAwareProperty(shorthandID, direction, writingMode);
         CSSVariableReferenceValue* shorthandValue = pendingSubstitution.shorthandValue();
 
-        auto resolvedData = shorthandValue->resolveVariableReferences(state);
+        auto resolvedData = shorthandValue->resolveVariableReferences(cascade);
         if (!resolvedData)
             return nullptr;
         Vector<CSSParserToken> resolvedTokens = resolvedData->tokens();
@@ -211,7 +212,7 @@ RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propI
 
     if (value.isVariableReferenceValue()) {
         const CSSVariableReferenceValue& valueWithReferences = downcast<CSSVariableReferenceValue>(value);
-        auto resolvedData = valueWithReferences.resolveVariableReferences(state);
+        auto resolvedData = valueWithReferences.resolveVariableReferences(cascade);
         if (!resolvedData)
             return nullptr;
         return CSSPropertyParser::parseSingleValue(propID, resolvedData->tokens(), m_context);
@@ -221,9 +222,9 @@ RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propI
     const auto& valueWithReferences = WTF::get<Ref<CSSVariableReferenceValue>>(customPropValue.value()).get();
 
     auto& name = downcast<CSSCustomPropertyValue>(value).name();
-    auto* registered = state.styleResolver->document().getCSSRegisteredCustomPropertySet().get(name);
+    auto* registered = cascade.styleResolver().document().getCSSRegisteredCustomPropertySet().get(name);
     auto& syntax = registered ? registered->syntax : "*";
-    auto resolvedData = valueWithReferences.resolveVariableReferences(state);
+    auto resolvedData = valueWithReferences.resolveVariableReferences(cascade);
 
     if (!resolvedData)
         return nullptr;
@@ -233,9 +234,9 @@ RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propI
     CSSPropertyParser::collectParsedCustomPropertyValueDependencies(syntax, false, dependencies, resolvedData->tokens(), m_context);
 
     for (auto id : dependencies)
-        state.styleResolver->applyCascadedProperties(id, id, state);
+        cascade.applyProperties(id, id);
 
-    return CSSPropertyParser::parseTypedCustomPropertyValue(name, syntax, resolvedData->tokens(), *state.styleResolver, m_context);
+    return CSSPropertyParser::parseTypedCustomPropertyValue(name, syntax, resolvedData->tokens(), cascade.styleResolver(), m_context);
 }
 
 std::unique_ptr<Vector<double>> CSSParser::parseKeyframeKeyList(const String& selector)
index e330789..d269551 100644 (file)
@@ -30,7 +30,6 @@
 
 namespace WebCore {
 
-struct ApplyCascadedPropertyState;
 class CSSParserObserver;
 class CSSSelectorList;
 class Color;
@@ -42,6 +41,10 @@ class StyleRuleKeyframe;
 class StyleSheetContents;
 class RenderStyle;
 
+namespace Style {
+class PropertyCascade;
+}
+
 class CSSParser {
 public:
     enum class ParseResult {
@@ -78,7 +81,7 @@ public:
 
     void parseSelector(const String&, CSSSelectorList&);
 
-    RefPtr<CSSValue> parseValueWithVariableReferences(CSSPropertyID, const CSSValue&, ApplyCascadedPropertyState&);
+    RefPtr<CSSValue> parseValueWithVariableReferences(CSSPropertyID, const CSSValue&, Style::PropertyCascade&);
 
     static Color parseColor(const String&, bool strict = false);
     static Color parseSystemColor(const String&, const CSSParserContext*);
index 53cd601..715b0f1 100644 (file)
@@ -140,8 +140,10 @@ static inline bool isValidCueStyleProperty(CSSPropertyID id)
 }
 #endif
 
-PropertyCascade::PropertyCascade(TextDirection direction, WritingMode writingMode)
-    : m_direction(direction)
+PropertyCascade::PropertyCascade(StyleResolver& styleResolver, const MatchResult& matchResult, TextDirection direction, WritingMode writingMode)
+    : m_styleResolver(styleResolver)
+    , m_matchResult(matchResult)
+    , m_direction(direction)
     , m_writingMode(writingMode)
 {
 }
@@ -174,17 +176,17 @@ void PropertyCascade::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMat
     if (id == CSSPropertyCustom) {
         m_propertyIsPresent.set(id);
         const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
-        bool hasValue = customProperties().contains(customValue.name());
+        bool hasValue = m_customProperties.contains(customValue.name());
         if (!hasValue) {
             Property property;
             property.id = id;
             memset(property.cssValue, 0, sizeof(property.cssValue));
             setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
-            customProperties().set(customValue.name(), property);
+            m_customProperties.set(customValue.name(), property);
         } else {
-            Property property = customProperties().get(customValue.name());
+            Property property = customProperty(customValue.name());
             setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
-            customProperties().set(customValue.name(), property);
+            m_customProperties.set(customValue.name(), property);
         }
         return;
     }
@@ -249,9 +251,9 @@ static auto& declarationsForCascadeLevel(const MatchResult& matchResult, Cascade
     return matchResult.authorDeclarations;
 }
 
-void PropertyCascade::addNormalMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
+void PropertyCascade::addNormalMatches(CascadeLevel cascadeLevel, bool inheritedOnly)
 {
-    for (auto& matchedDeclarations : declarationsForCascadeLevel(matchResult, cascadeLevel))
+    for (auto& matchedDeclarations : declarationsForCascadeLevel(m_matchResult, cascadeLevel))
         addMatch(matchedDeclarations, cascadeLevel, false, inheritedOnly);
 }
 
@@ -264,7 +266,7 @@ static bool hasImportantProperties(const StyleProperties& properties)
     return false;
 }
 
-void PropertyCascade::addImportantMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
+void PropertyCascade::addImportantMatches(CascadeLevel cascadeLevel, bool inheritedOnly)
 {
     struct IndexAndOrdinal {
         unsigned index;
@@ -273,7 +275,7 @@ void PropertyCascade::addImportantMatches(const MatchResult& matchResult, Cascad
     Vector<IndexAndOrdinal> importantMatches;
     bool hasMatchesFromOtherScopes = false;
 
-    auto& matchedDeclarations = declarationsForCascadeLevel(matchResult, cascadeLevel);
+    auto& matchedDeclarations = declarationsForCascadeLevel(m_matchResult, cascadeLevel);
 
     for (unsigned i = 0; i < matchedDeclarations.size(); ++i) {
         const MatchedProperties& matchedProperties = matchedDeclarations[i];
@@ -302,14 +304,165 @@ void PropertyCascade::addImportantMatches(const MatchResult& matchResult, Cascad
         addMatch(matchedDeclarations[match.index], cascadeLevel, true, inheritedOnly);
 }
 
-void PropertyCascade::applyDeferredProperties(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
+void PropertyCascade::applyDeferredProperties()
 {
     for (auto& property : m_deferredProperties)
-        property.apply(resolver, applyState);
+        property.apply(*this);
 }
 
-void PropertyCascade::Property::apply(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
+void PropertyCascade::applyProperties(int firstProperty, int lastProperty)
 {
+    if (LIKELY(m_customProperties.isEmpty()))
+        return applyPropertiesImpl<CustomPropertyCycleTracking::Disabled>(firstProperty, lastProperty);
+
+    return applyPropertiesImpl<CustomPropertyCycleTracking::Enabled>(firstProperty, lastProperty);
+}
+
+template<PropertyCascade::CustomPropertyCycleTracking trackCycles>
+inline void PropertyCascade::applyPropertiesImpl(int firstProperty, int lastProperty)
+{
+    for (int id = firstProperty; id <= lastProperty; ++id) {
+        CSSPropertyID propertyID = static_cast<CSSPropertyID>(id);
+        if (!hasProperty(propertyID))
+            continue;
+        ASSERT(propertyID != CSSPropertyCustom);
+        auto& property = m_properties[propertyID];
+
+        if (trackCycles == CustomPropertyCycleTracking::Enabled) {
+            if (UNLIKELY(m_applyState.inProgressProperties.get(propertyID))) {
+                // We are in a cycle (eg. setting font size using registered custom property value containing em).
+                // So this value should be unset.
+                m_applyState.appliedProperties.set(propertyID);
+                // This property is in a cycle, and only the root of the call stack will have firstProperty != lastProperty.
+                ASSERT(firstProperty == lastProperty);
+                continue;
+            }
+
+            m_applyState.inProgressProperties.set(propertyID);
+            property.apply(*this);
+            m_applyState.appliedProperties.set(propertyID);
+            m_applyState.inProgressProperties.set(propertyID, false);
+            continue;
+        }
+
+        // If we don't have any custom properties, then there can't be any cycles.
+        property.apply(*this);
+    }
+}
+
+void PropertyCascade::applyCustomProperties()
+{
+    for (auto& name : m_customProperties.keys())
+        applyCustomProperty(name);
+}
+
+void PropertyCascade::applyCustomProperty(const String& name)
+{
+    if (m_applyState.appliedCustomProperties.contains(name) || !m_customProperties.contains(name))
+        return;
+
+    auto property = customProperty(name);
+    bool inCycle = m_applyState.inProgressPropertiesCustom.contains(name);
+
+    for (auto index : { SelectorChecker::MatchDefault, SelectorChecker::MatchLink, SelectorChecker::MatchVisited }) {
+        if (!property.cssValue[index])
+            continue;
+        if (index != SelectorChecker::MatchDefault && m_styleResolver.state().style()->insideLink() == InsideLink::NotInside)
+            continue;
+
+        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
+
+        if (inCycle) {
+            m_applyState.appliedCustomProperties.add(name); // Make sure we do not try to apply this property again while resolving it.
+            valueToApply = CSSCustomPropertyValue::createWithID(name, CSSValueInvalid);
+        }
+
+        m_applyState.inProgressPropertiesCustom.add(name);
+
+        if (WTF::holds_alternative<Ref<CSSVariableReferenceValue>>(valueToApply->value())) {
+            RefPtr<CSSValue> parsedValue = m_styleResolver.resolvedVariableValue(CSSPropertyCustom, valueToApply.get(), *this);
+
+            if (m_applyState.appliedCustomProperties.contains(name))
+                return; // There was a cycle and the value was reset, so bail.
+
+            if (!parsedValue)
+                parsedValue = CSSCustomPropertyValue::createWithID(name, CSSValueUnset);
+
+            valueToApply = downcast<CSSCustomPropertyValue>(*parsedValue);
+        }
+
+        if (m_applyState.inProgressPropertiesCustom.contains(name)) {
+            if (index == SelectorChecker::MatchDefault) {
+                m_styleResolver.state().setApplyPropertyToRegularStyle(true);
+                m_styleResolver.state().setApplyPropertyToVisitedLinkStyle(false);
+            }
+
+            if (index == SelectorChecker::MatchLink) {
+                m_styleResolver.state().setApplyPropertyToRegularStyle(true);
+                m_styleResolver.state().setApplyPropertyToVisitedLinkStyle(false);
+            }
+
+            if (index == SelectorChecker::MatchVisited) {
+                m_styleResolver.state().setApplyPropertyToRegularStyle(false);
+                m_styleResolver.state().setApplyPropertyToVisitedLinkStyle(true);
+            }
+            m_styleResolver.applyProperty(CSSPropertyCustom, valueToApply.ptr(), *this, index);
+        }
+    }
+
+    m_applyState.inProgressPropertiesCustom.remove(name);
+    m_applyState.appliedCustomProperties.add(name);
+
+    for (auto index : { SelectorChecker::MatchDefault, SelectorChecker::MatchLink, SelectorChecker::MatchVisited }) {
+        if (!property.cssValue[index])
+            continue;
+        if (index != SelectorChecker::MatchDefault && m_styleResolver.state().style()->insideLink() == InsideLink::NotInside)
+            continue;
+
+        Ref<CSSCustomPropertyValue> valueToApply = CSSCustomPropertyValue::create(downcast<CSSCustomPropertyValue>(*property.cssValue[index]));
+
+        if (inCycle && WTF::holds_alternative<Ref<CSSVariableReferenceValue>>(valueToApply->value())) {
+            // Resolve this value so that we reset its dependencies.
+            m_styleResolver.resolvedVariableValue(CSSPropertyCustom, valueToApply.get(), *this);
+        }
+    }
+}
+
+PropertyCascade* PropertyCascade::propertyCascadeForRollback(CascadeLevel cascadeLevel)
+{
+    switch (cascadeLevel) {
+    case CascadeLevel::Author:
+        if (!m_authorRollbackCascade) {
+            m_authorRollbackCascade = makeUnique<PropertyCascade>(m_styleResolver, m_matchResult, m_direction, m_writingMode);
+
+            // This special rollback cascade contains UA rules and user rules but no author rules.
+            m_authorRollbackCascade->addNormalMatches(CascadeLevel::UserAgent, false);
+            m_authorRollbackCascade->addNormalMatches(CascadeLevel::User, false);
+            m_authorRollbackCascade->addImportantMatches(CascadeLevel::User, false);
+            m_authorRollbackCascade->addImportantMatches(CascadeLevel::UserAgent, false);
+        }
+        return m_authorRollbackCascade.get();
+
+    case CascadeLevel::User:
+        if (!m_userRollbackCascade) {
+            m_userRollbackCascade = makeUnique<PropertyCascade>(m_styleResolver, m_matchResult, m_direction, m_writingMode);
+
+            // This special rollback cascade contains only UA rules.
+            m_userRollbackCascade->addNormalMatches(CascadeLevel::UserAgent, false);
+            m_userRollbackCascade->addImportantMatches(CascadeLevel::UserAgent, false);
+        }
+        return m_userRollbackCascade.get();
+
+    case CascadeLevel::UserAgent:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+void PropertyCascade::Property::apply(PropertyCascade& cascade)
+{
+    auto& resolver = cascade.styleResolver();
     StyleResolver::State& state = resolver.state();
     state.setCascadeLevel(level);
     state.setStyleScopeOrdinal(styleScopeOrdinal);
@@ -317,7 +470,7 @@ void PropertyCascade::Property::apply(StyleResolver& resolver, ApplyCascadedProp
     if (cssValue[SelectorChecker::MatchDefault]) {
         state.setApplyPropertyToRegularStyle(true);
         state.setApplyPropertyToVisitedLinkStyle(false);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], applyState, SelectorChecker::MatchDefault);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], cascade, SelectorChecker::MatchDefault);
     }
 
     if (state.style()->insideLink() == InsideLink::NotInside)
@@ -326,13 +479,13 @@ void PropertyCascade::Property::apply(StyleResolver& resolver, ApplyCascadedProp
     if (cssValue[SelectorChecker::MatchLink]) {
         state.setApplyPropertyToRegularStyle(true);
         state.setApplyPropertyToVisitedLinkStyle(false);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], applyState, SelectorChecker::MatchLink);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], cascade, SelectorChecker::MatchLink);
     }
 
     if (cssValue[SelectorChecker::MatchVisited]) {
         state.setApplyPropertyToRegularStyle(false);
         state.setApplyPropertyToVisitedLinkStyle(true);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], applyState, SelectorChecker::MatchVisited);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], cascade, SelectorChecker::MatchVisited);
     }
 
     state.setApplyPropertyToRegularStyle(true);
index 4e9d62a..bebc62f 100644 (file)
@@ -32,7 +32,6 @@
 namespace WebCore {
 
 class StyleResolver;
-struct ApplyCascadedPropertyState;
 
 namespace Style {
 
@@ -45,44 +44,74 @@ enum class CascadeLevel : uint8_t {
 class PropertyCascade {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    PropertyCascade(TextDirection, WritingMode);
+    PropertyCascade(StyleResolver&, const MatchResult&, TextDirection, WritingMode);
     ~PropertyCascade();
 
+    StyleResolver& styleResolver() { return m_styleResolver; }
+
     struct Property {
-        void apply(StyleResolver&, ApplyCascadedPropertyState&);
+        void apply(PropertyCascade&);
 
         CSSPropertyID id;
         CascadeLevel level;
         ScopeOrdinal styleScopeOrdinal;
-        CSSValue* cssValue[3];
+        CSSValue* cssValue[3]; // Values for link match states MatchDefault, MatchLink and MatchVisited
     };
 
     bool hasProperty(CSSPropertyID) const;
     Property& property(CSSPropertyID);
 
-    void addNormalMatches(const MatchResult&, CascadeLevel, bool inheritedOnly = false);
-    void addImportantMatches(const MatchResult&, CascadeLevel, bool inheritedOnly = false);
-
-    void applyDeferredProperties(StyleResolver&, ApplyCascadedPropertyState&);
-
-    HashMap<AtomString, Property>& customProperties() { return m_customProperties; }
     bool hasCustomProperty(const String&) const;
     Property customProperty(const String&) const;
 
+    void addNormalMatches(CascadeLevel, bool inheritedOnly = false);
+    void addImportantMatches(CascadeLevel, bool inheritedOnly = false);
+
+    bool hasAppliedProperty(CSSPropertyID) const;
+
+    void applyProperties(int firstProperty, int lastProperty);
+    void applyDeferredProperties();
+
+    void applyCustomProperties();
+    void applyCustomProperty(const String& name);
+
+    PropertyCascade* propertyCascadeForRollback(CascadeLevel);
+
 private:
     void addMatch(const MatchedProperties&, CascadeLevel, bool isImportant, bool inheritedOnly);
     void set(CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, ScopeOrdinal);
     void setDeferred(CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, ScopeOrdinal);
     static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, ScopeOrdinal);
 
+    enum CustomPropertyCycleTracking { Enabled = 0, Disabled };
+    template<CustomPropertyCycleTracking trackCycles>
+    void applyPropertiesImpl(int firstProperty, int lastProperty);
+
+    StyleResolver& m_styleResolver;
+    const MatchResult& m_matchResult;
+
+    TextDirection m_direction;
+    WritingMode m_writingMode;
+
     Property m_properties[numCSSProperties + 2];
     std::bitset<numCSSProperties + 2> m_propertyIsPresent;
 
     Vector<Property, 8> m_deferredProperties;
     HashMap<AtomString, Property> m_customProperties;
 
-    TextDirection m_direction;
-    WritingMode m_writingMode;
+    // State to use when applying properties, to keep track of which custom and high-priority
+    // properties have been resolved.
+    struct ApplyState {
+        Bitmap<numCSSProperties> appliedProperties = { };
+        HashSet<String> appliedCustomProperties = { };
+        Bitmap<numCSSProperties> inProgressProperties = { };
+        HashSet<String> inProgressPropertiesCustom = { };
+    };
+
+    ApplyState m_applyState;
+
+    std::unique_ptr<PropertyCascade> m_authorRollbackCascade;
+    std::unique_ptr<PropertyCascade> m_userRollbackCascade;
 };
 
 inline bool PropertyCascade::hasProperty(CSSPropertyID id) const
@@ -106,5 +135,10 @@ inline PropertyCascade::Property PropertyCascade::customProperty(const String& n
     return m_customProperties.get(name);
 }
 
+inline bool PropertyCascade::hasAppliedProperty(CSSPropertyID propertyID) const
+{
+    return m_applyState.appliedProperties.get(propertyID);
+}
+
 }
 }