CSS: Add a property cascading pass to style application.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Dec 2013 00:33:25 +0000 (00:33 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Dec 2013 00:33:25 +0000 (00:33 +0000)
<https://webkit.org/b/125213>

Add an intermediate pass to style application where we cascade all
style properties to figure out their final values before starting
to build RenderStyles.

This opens up various opportunities for further optimization.

Reviewed by Antti Koivisto.

* css/StyleResolver.cpp:
(WebCore::StyleResolver::CascadedProperties::Property::Property):
(WebCore::StyleResolver::CascadedProperties::CascadedProperties):
(WebCore::StyleResolver::CascadedProperties::property):
(WebCore::StyleResolver::CascadedProperties::set):
(WebCore::StyleResolver::CascadedProperties::addStyleProperties):
(WebCore::StyleResolver::CascadedProperties::addMatches):
(WebCore::StyleResolver::CascadedProperties::Property::apply):

    Added. CascadedProperties is something of a container class
    that takes CSS property/value/linkMatchType as input and boils
    them down to the final values that will actually be used.

    Most properties are poked into an unfancy array where latest
    is greatest (unless !important, of course.) Some properties are
    queued up to be applied in parse order, more on that below.

(WebCore::StyleResolver::applyCascadedProperties):
(WebCore::StyleResolver::applyMatchedProperties):

    The brains of this patch. applyMatchedProperties() now creates
    a CascadedProperties and uses it to figure out the final values
    and uses applyCascadedProperties() to apply them. Deferred
    properties (parse order) are applied last.

    We may discover during property application that we won't be
    able to use a matched properties cache item. This happens if
    the effective zoom or font changes. If that happens, we start
    the process over, now with the cache disabled. This may need
    some optimization work.

(WebCore::extractDirectionAndWritingMode):

    Directional properties ending in e.g -before or -after depend on
    the direction and writing mode in effect, so we must begin with
    resolving those properties before doing the full cascade.

    This is done by simply walking the set of matched properties and
    manually applying '-webkit-writing-mode' and 'direction'.

    If this starts showing up in profiles, we can easily cache some
    of the information in e.g RuleData to avoid the traversal here.

(WebCore::elementTypeHasAppearanceFromUAStyle):

    To determine whether a form element is styled beyond the default
    UA style sheet, StyleResolver caches the border and background
    values from RenderStyle after applying the UA style sheet.

    Those values are then compared against after all style is applied
    and if some (platform-dependent) values differ, the element is
    considered "styled."

    This really only affects elements with -webkit-appearance values
    in the default UA style sheet, so this function determines if an
    element should take the goofy slow path for this.

(WebCore::shouldApplyPropertyInParseOrder):
(WebCore::StyleResolver::CascadedProperties::setDeferred):
(WebCore::StyleResolver::CascadedProperties::applyDeferredProperties):

    Some CSS properties will write to the same RenderStyle fields when
    applied, so in order to maintain previous behavior, we must apply
    them in the order they were parsed.

    We accomplish this by keeping an ordered queue of such properties
    to apply separately after all the other properties.

(WebCore::StyleResolver::CascadedProperties::setPropertyInternal):

    Helper for poking values into a CascadedProperties::Property.

* css/StyleResolver.h:
(WebCore::StyleResolver::state):

    Expose the StyleResolver::State so CascadedProperties can access it.

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

Source/WebCore/ChangeLog
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h

index 421674548d6254d8c097ae3e20b8e80a2cba6d80..ad34b8aa712e0d239e249bd36b7b8ad28baef3f3 100644 (file)
@@ -1,3 +1,93 @@
+2013-12-18  Andreas Kling  <akling@apple.com>
+
+        CSS: Add a property cascading pass to style application.
+        <https://webkit.org/b/125213>
+
+        Add an intermediate pass to style application where we cascade all
+        style properties to figure out their final values before starting
+        to build RenderStyles.
+
+        This opens up various opportunities for further optimization.
+
+        Reviewed by Antti Koivisto.
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::CascadedProperties::Property::Property):
+        (WebCore::StyleResolver::CascadedProperties::CascadedProperties):
+        (WebCore::StyleResolver::CascadedProperties::property):
+        (WebCore::StyleResolver::CascadedProperties::set):
+        (WebCore::StyleResolver::CascadedProperties::addStyleProperties):
+        (WebCore::StyleResolver::CascadedProperties::addMatches):
+        (WebCore::StyleResolver::CascadedProperties::Property::apply):
+
+            Added. CascadedProperties is something of a container class
+            that takes CSS property/value/linkMatchType as input and boils
+            them down to the final values that will actually be used.
+
+            Most properties are poked into an unfancy array where latest
+            is greatest (unless !important, of course.) Some properties are
+            queued up to be applied in parse order, more on that below.
+
+        (WebCore::StyleResolver::applyCascadedProperties):
+        (WebCore::StyleResolver::applyMatchedProperties):
+
+            The brains of this patch. applyMatchedProperties() now creates
+            a CascadedProperties and uses it to figure out the final values
+            and uses applyCascadedProperties() to apply them. Deferred
+            properties (parse order) are applied last.
+
+            We may discover during property application that we won't be
+            able to use a matched properties cache item. This happens if
+            the effective zoom or font changes. If that happens, we start
+            the process over, now with the cache disabled. This may need
+            some optimization work.
+
+        (WebCore::extractDirectionAndWritingMode):
+
+            Directional properties ending in e.g -before or -after depend on
+            the direction and writing mode in effect, so we must begin with
+            resolving those properties before doing the full cascade.
+
+            This is done by simply walking the set of matched properties and
+            manually applying '-webkit-writing-mode' and 'direction'.
+
+            If this starts showing up in profiles, we can easily cache some
+            of the information in e.g RuleData to avoid the traversal here.
+
+        (WebCore::elementTypeHasAppearanceFromUAStyle):
+
+            To determine whether a form element is styled beyond the default
+            UA style sheet, StyleResolver caches the border and background
+            values from RenderStyle after applying the UA style sheet.
+
+            Those values are then compared against after all style is applied
+            and if some (platform-dependent) values differ, the element is
+            considered "styled."
+
+            This really only affects elements with -webkit-appearance values
+            in the default UA style sheet, so this function determines if an
+            element should take the goofy slow path for this.
+
+        (WebCore::shouldApplyPropertyInParseOrder):
+        (WebCore::StyleResolver::CascadedProperties::setDeferred):
+        (WebCore::StyleResolver::CascadedProperties::applyDeferredProperties):
+
+            Some CSS properties will write to the same RenderStyle fields when
+            applied, so in order to maintain previous behavior, we must apply
+            them in the order they were parsed.
+
+            We accomplish this by keeping an ordered queue of such properties
+            to apply separately after all the other properties.
+
+        (WebCore::StyleResolver::CascadedProperties::setPropertyInternal):
+
+            Helper for poking values into a CascadedProperties::Property.
+
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::state):
+
+            Expose the StyleResolver::State so CascadedProperties can access it.
+
 2013-12-16  Martin Robinson  <mrobinson@igalia.com>
 
         [GTK] [CMake] Add support for building WebKit1
index 81a5e71368115b89473f0ac1c7ab331ba0776db2..d79dd25fb05cde0ee8a3d7a7ba998be570c52b1c 100644 (file)
@@ -191,6 +191,38 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
+class StyleResolver::CascadedProperties {
+public:
+    CascadedProperties(TextDirection, WritingMode);
+
+    struct Property {
+        Property();
+        void apply(StyleResolver&);
+
+        CSSPropertyID id;
+        bool isPresent;
+        CSSValue* cssValue[3];
+    };
+
+    Property& property(CSSPropertyID);
+    void addMatches(const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
+
+    void set(CSSPropertyID, CSSValue&, unsigned linkMatchType);
+    void setDeferred(CSSPropertyID, CSSValue&, unsigned linkMatchType);
+
+    void applyDeferredProperties(StyleResolver&);
+
+private:
+    void addStyleProperties(const StyleProperties&, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType, unsigned linkMatchType);
+    static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType);
+
+    Property m_properties[numCSSProperties + 1];
+    Vector<Property> m_deferredProperties;
+
+    TextDirection m_direction;
+    WritingMode m_writingMode;
+};
+
 #define HANDLE_INHERIT(prop, Prop) \
 if (isInherit) { \
     m_state.style()->set##Prop(m_state.parentStyle()->prop()); \
@@ -1568,6 +1600,44 @@ void StyleResolver::applyProperties(const StyleProperties* properties, StyleRule
     InspectorInstrumentation::didProcessRule(cookie);
 }
 
+static bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
+{
+    switch (propertyID) {
+    case CSSPropertyWebkitBorderImage:
+    case CSSPropertyBorderImage:
+    case CSSPropertyBorderImageSlice:
+    case CSSPropertyBorderImageSource:
+    case CSSPropertyBorderImageOutset:
+    case CSSPropertyBorderImageRepeat:
+    case CSSPropertyBorderImageWidth:
+#if ENABLE(CSS3_TEXT_DECORATION)
+    case CSSPropertyWebkitTextDecoration:
+    case CSSPropertyWebkitTextDecorationLine:
+    case CSSPropertyWebkitTextDecorationStyle:
+    case CSSPropertyWebkitTextDecorationColor:
+    case CSSPropertyWebkitTextDecorationSkip:
+    case CSSPropertyWebkitTextUnderlinePosition:
+#endif
+    case CSSPropertyTextDecoration:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static bool elementTypeHasAppearanceFromUAStyle(const Element& element)
+{
+    // NOTE: This is just a hard-coded list of elements that have some -webkit-appearance value in html.css
+    const auto& localName = element.localName();
+    return localName == HTMLNames::inputTag
+        || localName == HTMLNames::textareaTag
+        || localName == HTMLNames::buttonTag
+        || localName == HTMLNames::progressTag
+        || localName == HTMLNames::selectTag
+        || localName == HTMLNames::meterTag
+        || localName == HTMLNames::isindexTag;
+}
+
 template <StyleResolver::StyleApplicationPass pass>
 void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
 {
@@ -1691,14 +1761,47 @@ static bool isCacheableInMatchedPropertiesCache(const Element* element, const Re
     return true;
 }
 
-void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element)
+static void extractDirectionAndWritingMode(const RenderStyle& style, const StyleResolver::MatchResult& matchResult, TextDirection& direction, WritingMode& writingMode)
+{
+    direction = style.direction();
+    writingMode = style.writingMode();
+
+    bool hadImportantWebkitWritingMode = false;
+    bool hadImportantDirection = false;
+
+    for (auto& matchedProperties : matchResult.matchedProperties) {
+        for (unsigned i = 0, count = matchedProperties.properties->propertyCount(); i < count; ++i) {
+            auto property = matchedProperties.properties->propertyAt(i);
+            if (!property.value()->isPrimitiveValue())
+                continue;
+            switch (property.id()) {
+            case CSSPropertyWebkitWritingMode:
+                if (!hadImportantWebkitWritingMode || property.isImportant()) {
+                    writingMode = toCSSPrimitiveValue(*property.value());
+                    hadImportantWebkitWritingMode = property.isImportant();
+                }
+                break;
+            case CSSPropertyDirection:
+                if (!hadImportantDirection || property.isImportant()) {
+                    direction = toCSSPrimitiveValue(*property.value());
+                    hadImportantDirection = property.isImportant();
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element, ShouldUseMatchedPropertiesCache shouldUseMatchedPropertiesCache)
 {
     ASSERT(element);
     State& state = m_state;
     unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
     bool applyInheritedOnly = false;
     const MatchedPropertiesCacheItem* cacheItem = 0;
-    if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) {
+    if (shouldUseMatchedPropertiesCache && cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) {
         // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
         // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 
         // element context. This is fast and saves memory by reusing the style data structures.
@@ -1716,21 +1819,44 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
         applyInheritedOnly = true; 
     }
 
-    // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
-    // high-priority properties first, i.e., those properties that other properties depend on.
-    // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
-    // and (4) normal important.
-    state.setLineHeightValue(0);
-    applyMatchedProperties<HighPriorityProperties>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
-    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
-    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
-    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
-
-    if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
-        state.setFontDirty(true);
-        applyInheritedOnly = false;
+    // Directional properties (*-before/after) are aliases that depend on the TextDirection and WritingMode.
+    // These must be resolved before we can begin the property cascade.
+    TextDirection direction;
+    WritingMode writingMode;
+    extractDirectionAndWritingMode(*state.style(), matchResult, direction, writingMode);
+
+    if (elementTypeHasAppearanceFromUAStyle(*state.element())) {
+        // FIXME: This is such a hack.
+        // 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.
+        state.setLineHeightValue(nullptr);
+        CascadedProperties cascade(direction, writingMode);
+        cascade.addMatches(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+        cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+
+        applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+        updateFont();
+        applyCascadedProperties(cascade, CSSPropertyBackground, lastCSSProperty);
+
+        state.cacheBorderAndBackground();
     }
 
+    CascadedProperties cascade(direction, writingMode);
+    cascade.addMatches(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
+    cascade.addMatches(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
+    cascade.addMatches(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
+    cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+
+    state.setLineHeightValue(nullptr);
+
+    // Start by applying properties that other properties may depend on.
+    applyCascadedProperties(cascade, firstCSSProperty, CSSPropertyLineHeight);
+
+    // If the effective zoom value changes, we can't use the matched properties cache. Start over.
+    if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom())
+        return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
+
     // If our font got dirtied, go ahead and update it now.
     updateFont();
 
@@ -1738,22 +1864,18 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
     if (state.lineHeightValue())
         applyProperty(CSSPropertyLineHeight, state.lineHeightValue());
 
-    // Many properties depend on the font. If it changes we just apply all properties.
+    // If the font changed, we can't use the matched properties cache. Start over.
     if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style()->fontDescription())
-        applyInheritedOnly = false;
+        return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
+
+    // Apply properties that no other properties depend on.
+    applyCascadedProperties(cascade, CSSPropertyBackground, 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);
 
-    // Now do the normal priority UA properties.
-    applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
-    
-    // Cache our border and background so that we can examine them later.
-    state.cacheBorderAndBackground();
-    
-    // Now do the author and user normal priority properties and all the !important properties.
-    applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
-    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
-    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
-    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
-   
     // Start loading resources referenced by this style.
     loadPendingResources();
     
@@ -4070,4 +4192,150 @@ int StyleResolver::viewportPercentageValue(CSSPrimitiveValue& unit, int percenta
     return 0;
 }
 
+StyleResolver::CascadedProperties::Property::Property()
+    : id(CSSPropertyInvalid)
+    , isPresent(false)
+{
+    memset(cssValue, 0, sizeof(cssValue));
+}
+
+StyleResolver::CascadedProperties::CascadedProperties(TextDirection direction, WritingMode writingMode)
+    : m_direction(direction)
+    , m_writingMode(writingMode)
+{
+    memset(&m_properties, 0, sizeof(m_properties));
+}
+
+inline StyleResolver::CascadedProperties::Property& StyleResolver::CascadedProperties::property(CSSPropertyID id)
+{
+    return m_properties[id];
+}
+
+void StyleResolver::CascadedProperties::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+{
+    ASSERT(linkMatchType <= SelectorChecker::MatchAll);
+    property.id = id;
+    property.isPresent = true;
+    if (linkMatchType == SelectorChecker::MatchAll) {
+        property.cssValue[0] = &cssValue;
+        property.cssValue[SelectorChecker::MatchLink] = &cssValue;
+        property.cssValue[SelectorChecker::MatchVisited] = &cssValue;
+    } else
+        property.cssValue[linkMatchType] = &cssValue;
+}
+
+void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+{
+    if (CSSProperty::isDirectionAwareProperty(id))
+        id = CSSProperty::resolveDirectionAwareProperty(id, m_direction, m_writingMode);
+
+    ASSERT(!shouldApplyPropertyInParseOrder(id));
+
+    auto& property = m_properties[id];
+    setPropertyInternal(property, id, cssValue, linkMatchType);
+}
+
+void StyleResolver::CascadedProperties::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType)
+{
+    ASSERT(!CSSProperty::isDirectionAwareProperty(id));
+    ASSERT(shouldApplyPropertyInParseOrder(id));
+
+    Property property;
+    setPropertyInternal(property, id, cssValue, linkMatchType);
+    m_deferredProperties.append(property);
+}
+
+void StyleResolver::CascadedProperties::addStyleProperties(const StyleProperties& properties, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType, unsigned linkMatchType)
+{
+    for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
+        auto current = properties.propertyAt(i);
+        if (isImportant != current.isImportant())
+            continue;
+        if (inheritedOnly && !current.isInherited()) {
+            // If the property value is explicitly inherited, we need to apply further non-inherited properties
+            // as they might override the value inherited here. For this reason we don't allow declarations with
+            // explicitly inherited properties to be cached.
+            ASSERT(!current.value()->isInheritedValue());
+            continue;
+        }
+        CSSPropertyID propertyID = current.id();
+
+        if (propertyWhitelistType == PropertyWhitelistRegion && !StyleResolver::isValidRegionStyleProperty(propertyID))
+            continue;
+#if ENABLE(VIDEO_TRACK)
+        if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(propertyID))
+            continue;
+#endif
+
+        if (shouldApplyPropertyInParseOrder(propertyID))
+            setDeferred(propertyID, *current.value(), linkMatchType);
+        else
+            set(propertyID, *current.value(), linkMatchType);
+    }
+}
+
+void StyleResolver::CascadedProperties::addMatches(const MatchResult& matchResult, bool important, int startIndex, int endIndex, bool inheritedOnly)
+{
+    if (startIndex == -1)
+        return;
+
+    for (int i = startIndex; i <= endIndex; ++i) {
+        const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
+        addStyleProperties(*matchedProperties.properties, *matchResult.matchedRules[i], important, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType), matchedProperties.linkMatchType);
+    }
+}
+
+void StyleResolver::CascadedProperties::applyDeferredProperties(StyleResolver& resolver)
+{
+    for (auto& property : m_deferredProperties)
+        property.apply(resolver);
+}
+
+void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver)
+{
+    State& state = resolver.state();
+
+    // FIXME: It would be nice if line-height were less of a special snowflake.
+    if (id == CSSPropertyLineHeight) {
+        if (cssValue[0])
+            state.setLineHeightValue(cssValue[0]);
+        return;
+    }
+
+    if (cssValue[0]) {
+        state.setApplyPropertyToRegularStyle(true);
+        state.setApplyPropertyToVisitedLinkStyle(false);
+        resolver.applyProperty(id, cssValue[0]);
+    }
+
+    if (state.style()->insideLink() == NotInsideLink)
+        return;
+
+    if (cssValue[SelectorChecker::MatchLink]) {
+        state.setApplyPropertyToRegularStyle(true);
+        state.setApplyPropertyToVisitedLinkStyle(false);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink]);
+    }
+
+    if (cssValue[SelectorChecker::MatchVisited]) {
+        state.setApplyPropertyToRegularStyle(false);
+        state.setApplyPropertyToVisitedLinkStyle(true);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited]);
+    }
+
+    state.setApplyPropertyToRegularStyle(true);
+    state.setApplyPropertyToVisitedLinkStyle(false);
+}
+
+void StyleResolver::applyCascadedProperties(CascadedProperties& cascade, int firstProperty, int lastProperty)
+{
+    for (int id = firstProperty; id <= lastProperty; ++id) {
+        auto& property = cascade.property(static_cast<CSSPropertyID>(id));
+        if (!property.isPresent)
+            continue;
+        ASSERT(!shouldApplyPropertyInParseOrder(property.id));
+        property.apply(*this);
+    }
+}
+
 } // namespace WebCore
index f57f956cf70de9322e95b62d26aa28a270c6c45d..2b4528323561abaf68390732050130b466050886 100644 (file)
@@ -350,12 +350,19 @@ private:
 
     bool fastRejectSelector(const RuleData&) const;
 
-    void applyMatchedProperties(const MatchResult&, const Element*);
+    enum ShouldUseMatchedPropertiesCache { DoNotUseMatchedPropertiesCache = 0, UseMatchedPropertiesCache };
+    void applyMatchedProperties(const MatchResult&, const Element*, ShouldUseMatchedPropertiesCache = UseMatchedPropertiesCache);
 
     enum StyleApplicationPass {
         HighPriorityProperties,
         LowPriorityProperties
     };
+
+    class CascadedProperties;
+
+    void applyCascadedProperties(CascadedProperties&, int firstProperty, int lastProperty);
+    void cascadeMatches(CascadedProperties&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
+
     template <StyleApplicationPass pass>
     void applyMatchedProperties(const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
     template <StyleApplicationPass pass>
@@ -499,6 +506,8 @@ public:
         Color m_backgroundColor;
     };
 
+    State& state() { return m_state; }
+
     static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; }
 
     PassRefPtr<StyleImage> styleImage(CSSPropertyID, CSSValue*);