Move property cascade out of StyleResolver
https://bugs.webkit.org/show_bug.cgi?id=203361

Reviewed by Zalan Bujtas.

Rename StyleResolver::CascadedProperties -> Style::PropertyCascade and move it into a file of its own.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::styleForKeyframe):
(WebCore::StyleResolver::styleForPage):
(WebCore::StyleResolver::applyMatchedProperties):
(WebCore::StyleResolver::cascadedPropertiesForRollback):
(WebCore::StyleResolver::applyProperty):
(WebCore::StyleResolver::applyCascadedPropertiesImpl):
(WebCore::shouldApplyPropertyInParseOrder): Deleted.
(WebCore::isValidMarkerStyleProperty): Deleted.
(WebCore::isValidCueStyleProperty): Deleted.
(WebCore::StyleResolver::CascadedProperties::CascadedProperties): Deleted.
(WebCore::StyleResolver::CascadedProperties::hasProperty const): Deleted.
(WebCore::StyleResolver::CascadedProperties::property): Deleted.
(WebCore::StyleResolver::CascadedProperties::hasCustomProperty const): Deleted.
(WebCore::StyleResolver::CascadedProperties::customProperty const): Deleted.
(WebCore::StyleResolver::CascadedProperties::setPropertyInternal): Deleted.
(WebCore::StyleResolver::CascadedProperties::set): Deleted.
(WebCore::StyleResolver::CascadedProperties::setDeferred): Deleted.
(WebCore::StyleResolver::CascadedProperties::addMatch): Deleted.
(WebCore::declarationsForCascadeLevel): Deleted.
(WebCore::StyleResolver::CascadedProperties::addNormalMatches): Deleted.
(WebCore::hasImportantProperties): Deleted.
(WebCore::StyleResolver::CascadedProperties::addImportantMatches): Deleted.
(WebCore::StyleResolver::CascadedProperties::applyDeferredProperties): Deleted.
(WebCore::StyleResolver::CascadedProperties::Property::apply): Deleted.
* css/StyleResolver.h:
(WebCore::StyleResolver::State::authorRollback const):
(WebCore::StyleResolver::State::userRollback const):
(WebCore::StyleResolver::State::setAuthorRollback):
(WebCore::StyleResolver::State::setUserRollback):
(WebCore::StyleResolver::CascadedProperties::customProperties): Deleted.
(WebCore::StyleResolver::cascadeLevel const): Deleted.
(WebCore::StyleResolver::setCascadeLevel): Deleted.
* style/PropertyCascade.cpp: Added.
(WebCore::Style::shouldApplyPropertyInParseOrder):
(WebCore::Style::isValidMarkerStyleProperty):
(WebCore::Style::isValidCueStyleProperty):
(WebCore::Style::PropertyCascade::PropertyCascade):
(WebCore::Style::PropertyCascade::setPropertyInternal):
(WebCore::Style::PropertyCascade::set):
(WebCore::Style::PropertyCascade::setDeferred):
(WebCore::Style::PropertyCascade::addMatch):
(WebCore::Style::declarationsForCascadeLevel):
(WebCore::Style::PropertyCascade::addNormalMatches):
(WebCore::Style::hasImportantProperties):
(WebCore::Style::PropertyCascade::addImportantMatches):
(WebCore::Style::PropertyCascade::applyDeferredProperties):
(WebCore::Style::PropertyCascade::Property::apply):
* style/PropertyCascade.h: Added.
(WebCore::Style::PropertyCascade::customProperties):
(WebCore::Style::PropertyCascade::hasProperty const):
(WebCore::Style::PropertyCascade::property):
(WebCore::Style::PropertyCascade::hasCustomProperty const):
(WebCore::Style::PropertyCascade::customProperty const):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251540 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 8f50c46..ab44921 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,69 @@
+2019-10-24  Antti Koivisto  <antti@apple.com>
+
+        Move property cascade out of StyleResolver
+        https://bugs.webkit.org/show_bug.cgi?id=203361
+
+        Reviewed by Zalan Bujtas.
+
+        Rename StyleResolver::CascadedProperties -> Style::PropertyCascade and move it into a file of its own.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::styleForKeyframe):
+        (WebCore::StyleResolver::styleForPage):
+        (WebCore::StyleResolver::applyMatchedProperties):
+        (WebCore::StyleResolver::cascadedPropertiesForRollback):
+        (WebCore::StyleResolver::applyProperty):
+        (WebCore::StyleResolver::applyCascadedPropertiesImpl):
+        (WebCore::shouldApplyPropertyInParseOrder): Deleted.
+        (WebCore::isValidMarkerStyleProperty): Deleted.
+        (WebCore::isValidCueStyleProperty): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::CascadedProperties): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::hasProperty const): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::property): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::hasCustomProperty const): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::customProperty const): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::setPropertyInternal): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::set): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::setDeferred): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::addMatch): Deleted.
+        (WebCore::declarationsForCascadeLevel): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::addNormalMatches): Deleted.
+        (WebCore::hasImportantProperties): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::addImportantMatches): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::applyDeferredProperties): Deleted.
+        (WebCore::StyleResolver::CascadedProperties::Property::apply): Deleted.
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::State::authorRollback const):
+        (WebCore::StyleResolver::State::userRollback const):
+        (WebCore::StyleResolver::State::setAuthorRollback):
+        (WebCore::StyleResolver::State::setUserRollback):
+        (WebCore::StyleResolver::CascadedProperties::customProperties): Deleted.
+        (WebCore::StyleResolver::cascadeLevel const): Deleted.
+        (WebCore::StyleResolver::setCascadeLevel): Deleted.
+        * style/PropertyCascade.cpp: Added.
+        (WebCore::Style::shouldApplyPropertyInParseOrder):
+        (WebCore::Style::isValidMarkerStyleProperty):
+        (WebCore::Style::isValidCueStyleProperty):
+        (WebCore::Style::PropertyCascade::PropertyCascade):
+        (WebCore::Style::PropertyCascade::setPropertyInternal):
+        (WebCore::Style::PropertyCascade::set):
+        (WebCore::Style::PropertyCascade::setDeferred):
+        (WebCore::Style::PropertyCascade::addMatch):
+        (WebCore::Style::declarationsForCascadeLevel):
+        (WebCore::Style::PropertyCascade::addNormalMatches):
+        (WebCore::Style::hasImportantProperties):
+        (WebCore::Style::PropertyCascade::addImportantMatches):
+        (WebCore::Style::PropertyCascade::applyDeferredProperties):
+        (WebCore::Style::PropertyCascade::Property::apply):
+        * style/PropertyCascade.h: Added.
+        (WebCore::Style::PropertyCascade::customProperties):
+        (WebCore::Style::PropertyCascade::hasProperty const):
+        (WebCore::Style::PropertyCascade::property):
+        (WebCore::Style::PropertyCascade::hasCustomProperty const):
+        (WebCore::Style::PropertyCascade::customProperty const):
+
 2019-10-24  Chris Dumez  <cdumez@apple.com>
 
         AudioContext should not prevent entering the back/forward cache
diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt
index 6b62211..edb630d 100644
--- a/Source/WebCore/Sources.txt
+++ b/Source/WebCore/Sources.txt
@@ -2337,6 +2337,7 @@
 style/ClassChangeInvalidation.cpp
 style/IdChangeInvalidation.cpp
 style/InlineTextBoxStyle.cpp
+style/PropertyCascade.cpp
 style/StyleChange.cpp
 style/StyleFontSizeFunctions.cpp
 style/StyleInvalidator.cpp
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index 129a20f..39cebec 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -4832,6 +4832,7 @@
 		E4A814DA1C70E10D00BF85AC /* AttributeChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A814D91C70E10D00BF85AC /* AttributeChangeInvalidation.h */; };
 		E4A814E01C7338EB00BF85AC /* IdChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A814DF1C7338EB00BF85AC /* IdChangeInvalidation.h */; };
 		E4A8D21622578DB700A8463C /* EventRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A8D21422578DA000A8463C /* EventRegion.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E4ABABE42361A32900FA4345 /* PropertyCascade.h in Headers */ = {isa = PBXBuildFile; fileRef = E4ABABE22361A32900FA4345 /* PropertyCascade.h */; };
 		E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1517D1BB950009FB31 /* ElementIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E4AFCFA50DAF29A300F5F55C /* UnitBezier.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */; };
@@ -15141,6 +15142,8 @@
 		E4A814DF1C7338EB00BF85AC /* IdChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdChangeInvalidation.h; sourceTree = "<group>"; };
 		E4A8D21422578DA000A8463C /* EventRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventRegion.h; sourceTree = "<group>"; };
 		E4A8D21522578DA000A8463C /* EventRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventRegion.cpp; sourceTree = "<group>"; };
+		E4ABABE22361A32900FA4345 /* PropertyCascade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyCascade.h; sourceTree = "<group>"; };
+		E4ABABE52361A34200FA4345 /* PropertyCascade.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyCascade.cpp; sourceTree = "<group>"; };
 		E4AE7C1517D1BB950009FB31 /* ElementIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIterator.h; sourceTree = "<group>"; };
 		E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAncestorIterator.h; sourceTree = "<group>"; };
 		E4AFCFA40DAF29A300F5F55C /* UnitBezier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnitBezier.h; sourceTree = "<group>"; };
@@ -26872,6 +26875,8 @@
 				E4A814DF1C7338EB00BF85AC /* IdChangeInvalidation.h */,
 				1C0106FE192594DF008A4201 /* InlineTextBoxStyle.cpp */,
 				1C0106FF192594DF008A4201 /* InlineTextBoxStyle.h */,
+				E4ABABE52361A34200FA4345 /* PropertyCascade.cpp */,
+				E4ABABE22361A32900FA4345 /* PropertyCascade.h */,
 				E401E0A51C3C0CF700F34D10 /* StyleChange.cpp */,
 				E401E0A31C3C0B8300F34D10 /* StyleChange.h */,
 				E4D58EB617B4ED8900CBDCA8 /* StyleFontSizeFunctions.cpp */,
@@ -29045,6 +29050,7 @@
 				759CB837192DA9190012BC64 /* ControlStates.h in Headers */,
 				FD31602912B0267600C1A359 /* ConvolverNode.h in Headers */,
 				D8B6152F1032495100C8554A /* Cookie.h in Headers */,
+				E4ABABE42361A32900FA4345 /* PropertyCascade.h in Headers */,
 				E1424C94164B52C800F32D40 /* CookieJar.h in Headers */,
 				7A5699702086C619000E0433 /* CookieRequestHeaderFieldProxy.h in Headers */,
 				33D0212D131DB37B004091A8 /* CookieStorage.h in Headers */,
diff --git a/Source/WebCore/css/StyleResolver.cpp b/Source/WebCore/css/StyleResolver.cpp
index 15434a0..fe6b6d9 100644
--- a/Source/WebCore/css/StyleResolver.cpp
+++ b/Source/WebCore/css/StyleResolver.cpp
@@ -373,8 +373,8 @@
 
     // 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.
-    CascadedProperties cascade(direction, writingMode);
-    cascade.addNormalMatches(result, CascadeLevel::AuthorLevel);
+    Style::PropertyCascade cascade(direction, writingMode);
+    cascade.addNormalMatches(result, Style::CascadeLevel::Author);
 
     ApplyCascadedPropertyState applyState { this, &cascade, &result };
     applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
@@ -579,8 +579,8 @@
     WritingMode writingMode;
     extractDirectionAndWritingMode(*m_state.style(), result, direction, writingMode);
 
-    CascadedProperties cascade(direction, writingMode);
-    cascade.addNormalMatches(result, CascadeLevel::AuthorLevel);
+    Style::PropertyCascade cascade(direction, writingMode);
+    cascade.addNormalMatches(result, Style::CascadeLevel::Author);
 
     ApplyCascadedPropertyState applyState { this, &cascade, &result };
     applyCascadedProperties(firstCSSProperty, lastHighPriorityProperty, applyState);
@@ -1224,39 +1224,6 @@
     return collector.matchedRuleList();
 }
 
-static bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
-{
-    switch (propertyID) {
-    case CSSPropertyWebkitBackgroundClip:
-    case CSSPropertyBackgroundClip:
-    case CSSPropertyWebkitBackgroundOrigin:
-    case CSSPropertyBackgroundOrigin:
-    case CSSPropertyWebkitBackgroundSize:
-    case CSSPropertyBackgroundSize:
-    case CSSPropertyWebkitBorderImage:
-    case CSSPropertyBorderImage:
-    case CSSPropertyBorderImageSlice:
-    case CSSPropertyBorderImageSource:
-    case CSSPropertyBorderImageOutset:
-    case CSSPropertyBorderImageRepeat:
-    case CSSPropertyBorderImageWidth:
-    case CSSPropertyWebkitBoxShadow:
-    case CSSPropertyBoxShadow:
-    case CSSPropertyWebkitTextDecoration:
-    case CSSPropertyTextDecorationLine:
-    case CSSPropertyTextDecorationStyle:
-    case CSSPropertyTextDecorationColor:
-    case CSSPropertyTextDecorationSkip:
-    case CSSPropertyTextUnderlinePosition:
-    case CSSPropertyTextUnderlineOffset:
-    case CSSPropertyTextDecorationThickness:
-    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
@@ -1415,9 +1382,9 @@
         // 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.
-        CascadedProperties cascade(direction, writingMode);
-        cascade.addNormalMatches(matchResult, CascadeLevel::UserAgentLevel, applyInheritedOnly);
-        cascade.addImportantMatches(matchResult, CascadeLevel::UserAgentLevel, applyInheritedOnly);
+        Style::PropertyCascade cascade(direction, writingMode);
+        cascade.addNormalMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
+        cascade.addImportantMatches(matchResult, Style::CascadeLevel::UserAgent, applyInheritedOnly);
 
         ApplyCascadedPropertyState applyState { this, &cascade, &matchResult };
 
@@ -1442,13 +1409,13 @@
         state.cacheBorderAndBackground();
     }
 
-    CascadedProperties cascade(direction, writingMode);
-    cascade.addNormalMatches(matchResult, CascadeLevel::UserAgentLevel, applyInheritedOnly);
-    cascade.addNormalMatches(matchResult, CascadeLevel::UserLevel, applyInheritedOnly);
-    cascade.addNormalMatches(matchResult, CascadeLevel::AuthorLevel, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, CascadeLevel::AuthorLevel, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, CascadeLevel::UserLevel, applyInheritedOnly);
-    cascade.addImportantMatches(matchResult, CascadeLevel::UserAgentLevel, applyInheritedOnly);
+    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 };
 
@@ -1534,81 +1501,6 @@
     return false;
 }
 
-// https://www.w3.org/TR/css-pseudo-4/#marker-pseudo (Editor's Draft, 25 July 2017)
-static inline bool isValidMarkerStyleProperty(CSSPropertyID id)
-{
-    switch (id) {
-    case CSSPropertyColor:
-    case CSSPropertyFontFamily:
-    case CSSPropertyFontFeatureSettings:
-    case CSSPropertyFontSize:
-    case CSSPropertyFontStretch:
-    case CSSPropertyFontStyle:
-    case CSSPropertyFontSynthesis:
-    case CSSPropertyFontVariantAlternates:
-    case CSSPropertyFontVariantCaps:
-    case CSSPropertyFontVariantEastAsian:
-    case CSSPropertyFontVariantLigatures:
-    case CSSPropertyFontVariantNumeric:
-    case CSSPropertyFontVariantPosition:
-    case CSSPropertyFontWeight:
-#if ENABLE(VARIATION_FONTS)
-    case CSSPropertyFontOpticalSizing:
-    case CSSPropertyFontVariationSettings:
-#endif
-        return true;
-    default:
-        break;
-    }
-    return false;
-}
-
-#if ENABLE(VIDEO_TRACK)
-static inline bool isValidCueStyleProperty(CSSPropertyID id)
-{
-    switch (id) {
-    case CSSPropertyBackground:
-    case CSSPropertyBackgroundAttachment:
-    case CSSPropertyBackgroundClip:
-    case CSSPropertyBackgroundColor:
-    case CSSPropertyBackgroundImage:
-    case CSSPropertyBackgroundOrigin:
-    case CSSPropertyBackgroundPosition:
-    case CSSPropertyBackgroundPositionX:
-    case CSSPropertyBackgroundPositionY:
-    case CSSPropertyBackgroundRepeat:
-    case CSSPropertyBackgroundSize:
-    case CSSPropertyColor:
-    case CSSPropertyFont:
-    case CSSPropertyFontFamily:
-    case CSSPropertyFontSize:
-    case CSSPropertyFontStyle:
-    case CSSPropertyFontVariantCaps:
-    case CSSPropertyFontWeight:
-    case CSSPropertyLineHeight:
-    case CSSPropertyOpacity:
-    case CSSPropertyOutline:
-    case CSSPropertyOutlineColor:
-    case CSSPropertyOutlineOffset:
-    case CSSPropertyOutlineStyle:
-    case CSSPropertyOutlineWidth:
-    case CSSPropertyVisibility:
-    case CSSPropertyWhiteSpace:
-    case CSSPropertyTextDecoration:
-    case CSSPropertyTextShadow:
-    case CSSPropertyBorderStyle:
-    case CSSPropertyPaintOrder:
-    case CSSPropertyStrokeLinejoin:
-    case CSSPropertyStrokeLinecap:
-    case CSSPropertyStrokeColor:
-    case CSSPropertyStrokeWidth:
-        return true;
-    default:
-        break;
-    }
-    return false;
-}
-#endif
 // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
 // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
 // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
@@ -1628,46 +1520,49 @@
     return is<SVGElement>(m_state.element()) && !(is<SVGSVGElement>(*m_state.element()) && m_state.element()->parentNode());
 }
 
-StyleResolver::CascadedProperties* StyleResolver::cascadedPropertiesForRollback(const MatchResult& matchResult)
+Style::PropertyCascade* StyleResolver::cascadedPropertiesForRollback(const MatchResult& matchResult)
 {
-    ASSERT(cascadeLevel() != CascadeLevel::UserAgentLevel);
-
     TextDirection direction;
     WritingMode writingMode;
     extractDirectionAndWritingMode(*state().style(), matchResult, direction, writingMode);
 
-    if (cascadeLevel() == CascadeLevel::AuthorLevel) {
-        CascadedProperties* authorRollback = state().authorRollback();
+    switch (state().cascadeLevel()) {
+    case Style::CascadeLevel::Author: {
+        auto* authorRollback = state().authorRollback();
         if (authorRollback)
             return authorRollback;
 
-        auto newAuthorRollback(makeUnique<CascadedProperties>(direction, writingMode));
+        auto newAuthorRollback = makeUnique<Style::PropertyCascade>(direction, writingMode);
 
         // This special rollback cascade contains UA rules and user rules but no author rules.
-        newAuthorRollback->addNormalMatches(matchResult, CascadeLevel::UserAgentLevel, false);
-        newAuthorRollback->addNormalMatches(matchResult, CascadeLevel::UserLevel, false);
-        newAuthorRollback->addImportantMatches(matchResult, CascadeLevel::UserLevel, false);
-        newAuthorRollback->addImportantMatches(matchResult, CascadeLevel::UserAgentLevel, false);
+        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();
     }
 
-    if (cascadeLevel() == CascadeLevel::UserLevel) {
-        CascadedProperties* userRollback = state().userRollback();
+    case Style::CascadeLevel::User: {
+        auto* userRollback = state().userRollback();
         if (userRollback)
             return userRollback;
 
-        auto newUserRollback(makeUnique<CascadedProperties>(direction, writingMode));
+        auto newUserRollback = makeUnique<Style::PropertyCascade>(direction, writingMode);
 
         // This special rollback cascade contains only UA rules.
-        newUserRollback->addNormalMatches(matchResult, CascadeLevel::UserAgentLevel, false);
-        newUserRollback->addImportantMatches(matchResult, CascadeLevel::UserAgentLevel, false);
+        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;
 }
 
@@ -1718,7 +1613,7 @@
     bool isRevert = valueToCheckForInheritInitial->isRevertValue() || customPropertyValueID == CSSValueRevert;
 
     if (isRevert) {
-        if (cascadeLevel() == CascadeLevel::UserAgentLevel || !matchResult)
+        if (state.cascadeLevel() == Style::CascadeLevel::UserAgent || !matchResult)
             isUnset = true;
         else {
             // Fetch the correct rollback object from the state, building it if necessary.
@@ -2135,225 +2030,6 @@
     return true;
 }
 
-StyleResolver::CascadedProperties::CascadedProperties(TextDirection direction, WritingMode writingMode)
-    : m_direction(direction)
-    , m_writingMode(writingMode)
-{
-}
-
-inline bool StyleResolver::CascadedProperties::hasProperty(CSSPropertyID id) const
-{
-    ASSERT(id < m_propertyIsPresent.size());
-    return m_propertyIsPresent[id];
-}
-
-inline StyleResolver::CascadedProperties::Property& StyleResolver::CascadedProperties::property(CSSPropertyID id)
-{
-    return m_properties[id];
-}
-
-inline bool StyleResolver::CascadedProperties::hasCustomProperty(const String& name) const
-{
-    return m_customProperties.contains(name);
-}
-
-inline StyleResolver::CascadedProperties::Property StyleResolver::CascadedProperties::customProperty(const String& name) const
-{
-    return m_customProperties.get(name);
-}
-
-void StyleResolver::CascadedProperties::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
-{
-    ASSERT(linkMatchType <= SelectorChecker::MatchAll);
-    property.id = id;
-    property.level = cascadeLevel;
-    property.styleScopeOrdinal = styleScopeOrdinal;
-    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, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
-{
-    if (CSSProperty::isDirectionAwareProperty(id))
-        id = CSSProperty::resolveDirectionAwareProperty(id, m_direction, m_writingMode);
-
-    ASSERT(!shouldApplyPropertyInParseOrder(id));
-
-    auto& property = m_properties[id];
-    ASSERT(id < m_propertyIsPresent.size());
-    if (id == CSSPropertyCustom) {
-        m_propertyIsPresent.set(id);
-        const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
-        bool hasValue = 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);
-        } else {
-            Property property = customProperties().get(customValue.name());
-            setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
-            customProperties().set(customValue.name(), property);
-        }
-        return;
-    }
-
-    if (!m_propertyIsPresent[id])
-        memset(property.cssValue, 0, sizeof(property.cssValue));
-    m_propertyIsPresent.set(id);
-    setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
-}
-
-void StyleResolver::CascadedProperties::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, Style::ScopeOrdinal styleScopeOrdinal)
-{
-    ASSERT(!CSSProperty::isDirectionAwareProperty(id));
-    ASSERT(shouldApplyPropertyInParseOrder(id));
-
-    Property property;
-    memset(property.cssValue, 0, sizeof(property.cssValue));
-    setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
-    m_deferredProperties.append(property);
-}
-
-
-void StyleResolver::CascadedProperties::addMatch(const MatchedProperties& matchedProperties, CascadeLevel cascadeLevel, bool isImportant, bool inheritedOnly)
-{
-    auto& styleProperties = *matchedProperties.properties;
-    auto propertyWhitelistType = static_cast<PropertyWhitelistType>(matchedProperties.whitelistType);
-
-    for (unsigned i = 0, count = styleProperties.propertyCount(); i < count; ++i) {
-        auto current = styleProperties.propertyAt(i);
-        if (isImportant != current.isImportant())
-            continue;
-        if (inheritedOnly && !current.isInherited()) {
-            // We apply the inherited properties only when using the property cache.
-            // A match with a value that is explicitely inherited should never have been cached.
-            ASSERT(!current.value()->isInheritedValue());
-            continue;
-        }
-        CSSPropertyID propertyID = current.id();
-
-#if ENABLE(VIDEO_TRACK)
-        if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(propertyID))
-            continue;
-#endif
-        if (propertyWhitelistType == PropertyWhitelistMarker && !isValidMarkerStyleProperty(propertyID))
-            continue;
-
-        if (shouldApplyPropertyInParseOrder(propertyID))
-            setDeferred(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
-        else
-            set(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
-    }
-}
-
-
-static auto& declarationsForCascadeLevel(const MatchResult& matchResult, CascadeLevel cascadeLevel)
-{
-    switch (cascadeLevel) {
-    case CascadeLevel::UserAgentLevel: return matchResult.userAgentDeclarations;
-    case CascadeLevel::UserLevel: return matchResult.userDeclarations;
-    case CascadeLevel::AuthorLevel: return matchResult.authorDeclarations;
-    }
-    ASSERT_NOT_REACHED();
-    return matchResult.authorDeclarations;
-}
-
-void StyleResolver::CascadedProperties::addNormalMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
-{
-    for (auto& matchedDeclarations : declarationsForCascadeLevel(matchResult, cascadeLevel))
-        addMatch(matchedDeclarations, cascadeLevel, false, inheritedOnly);
-}
-
-static bool hasImportantProperties(const StyleProperties& properties)
-{
-    for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
-        if (properties.propertyAt(i).isImportant())
-            return true;
-    }
-    return false;
-}
-
-void StyleResolver::CascadedProperties::addImportantMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
-{
-    struct IndexAndOrdinal {
-        unsigned index;
-        Style::ScopeOrdinal ordinal;
-    };
-    Vector<IndexAndOrdinal> importantMatches;
-    bool hasMatchesFromOtherScopes = false;
-
-    auto& matchedDeclarations = declarationsForCascadeLevel(matchResult, cascadeLevel);
-
-    for (unsigned i = 0; i < matchedDeclarations.size(); ++i) {
-        const MatchedProperties& matchedProperties = matchedDeclarations[i];
-
-        if (!hasImportantProperties(*matchedProperties.properties))
-            continue;
-
-        importantMatches.append({ i, matchedProperties.styleScopeOrdinal });
-
-        if (matchedProperties.styleScopeOrdinal != Style::ScopeOrdinal::Element)
-            hasMatchesFromOtherScopes = true;
-    }
-
-    if (importantMatches.isEmpty())
-        return;
-
-    if (hasMatchesFromOtherScopes) {
-        // For !important properties a later shadow tree wins.
-        // Match results are sorted in reverse tree context order so this is not needed for normal properties.
-        std::stable_sort(importantMatches.begin(), importantMatches.end(), [] (const IndexAndOrdinal& a, const IndexAndOrdinal& b) {
-            return a.ordinal < b.ordinal;
-        });
-    }
-
-    for (auto& match : importantMatches)
-        addMatch(matchedDeclarations[match.index], cascadeLevel, true, inheritedOnly);
-}
-
-void StyleResolver::CascadedProperties::applyDeferredProperties(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
-{
-    for (auto& property : m_deferredProperties)
-        property.apply(resolver, applyState);
-}
-
-void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
-{
-    State& state = resolver.state();
-    state.setCascadeLevel(level);
-    state.setStyleScopeOrdinal(styleScopeOrdinal);
-
-    if (cssValue[SelectorChecker::MatchDefault]) {
-        state.setApplyPropertyToRegularStyle(true);
-        state.setApplyPropertyToVisitedLinkStyle(false);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], applyState, SelectorChecker::MatchDefault);
-    }
-
-    if (state.style()->insideLink() == InsideLink::NotInside)
-        return;
-
-    if (cssValue[SelectorChecker::MatchLink]) {
-        state.setApplyPropertyToRegularStyle(true);
-        state.setApplyPropertyToVisitedLinkStyle(false);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], applyState, SelectorChecker::MatchLink);
-    }
-
-    if (cssValue[SelectorChecker::MatchVisited]) {
-        state.setApplyPropertyToRegularStyle(false);
-        state.setApplyPropertyToVisitedLinkStyle(true);
-        resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], applyState, SelectorChecker::MatchVisited);
-    }
-
-    state.setApplyPropertyToRegularStyle(true);
-    state.setApplyPropertyToVisitedLinkStyle(false);
-}
-
 void StyleResolver::applyCascadedCustomProperty(const String& name, ApplyCascadedPropertyState& state)
 {
     if (state.appliedCustomProperties.contains(name) || !state.cascade->customProperties().contains(name))
@@ -2442,7 +2118,6 @@
             continue;
         ASSERT(propertyID != CSSPropertyCustom);
         auto& property = state.cascade->property(propertyID);
-        ASSERT(!shouldApplyPropertyInParseOrder(propertyID));
 
         if (TrackCycles == CustomPropertyCycleTracking::Disabled) {
             // If we don't have any custom properties, then there can't be any cycles.
diff --git a/Source/WebCore/css/StyleResolver.h b/Source/WebCore/css/StyleResolver.h
index 905d2a3..fdc5fb3 100644
--- a/Source/WebCore/css/StyleResolver.h
+++ b/Source/WebCore/css/StyleResolver.h
@@ -28,6 +28,7 @@
 #include "ElementRuleCollector.h"
 #include "InspectorCSSOMWrappers.h"
 #include "MediaQueryEvaluator.h"
+#include "PropertyCascade.h"
 #include "RenderStyle.h"
 #include "RuleSet.h"
 #include "SelectorChecker.h"
@@ -94,12 +95,6 @@
     MatchOnlyUserAgentRules,
 };
 
-enum class CascadeLevel: uint8_t {
-    UserAgentLevel,
-    AuthorLevel,
-    UserLevel
-};
-
 struct ElementStyle {
     ElementStyle(std::unique_ptr<RenderStyle> renderStyle, std::unique_ptr<Style::Relations> relations = { })
         : renderStyle(WTFMove(renderStyle))
@@ -151,7 +146,6 @@
     std::unique_ptr<RenderStyle> styleForKeyframe(const RenderStyle*, const StyleRuleKeyframe*, KeyframeValue&);
     bool isAnimationNameValid(const String&);
 
-public:
     // These methods will give back the set of rules that matched for a given element (or a pseudo-element).
     enum CSSRuleFilter {
         UAAndUserCSSRules   = 1 << 1,
@@ -163,7 +157,6 @@
     Vector<RefPtr<StyleRule>> styleRulesForElement(const Element*, unsigned rulesToInclude = AllButEmptyCSSRules);
     Vector<RefPtr<StyleRule>> pseudoStyleRulesForElement(const Element*, PseudoId, unsigned rulesToInclude = AllButEmptyCSSRules);
 
-public:
     void applyPropertyToStyle(CSSPropertyID, CSSValue*, std::unique_ptr<RenderStyle>);
     void applyPropertyToCurrentStyle(CSSPropertyID, CSSValue*);
 
@@ -172,7 +165,6 @@
 
     void setFontSize(FontCascadeDescription&, float size);
 
-public:
     bool useSVGZoomRules() const;
     bool useSVGZoomRulesForLength() const;
 
@@ -208,48 +200,6 @@
     void clearCachedPropertiesAffectedByViewportUnits();
 
     bool createFilterOperations(const CSSValue& inValue, FilterOperations& outOperations);
-    
-    class CascadedProperties {
-        WTF_MAKE_FAST_ALLOCATED;
-    public:
-        CascadedProperties(TextDirection, WritingMode);
-
-        struct Property {
-            void apply(StyleResolver&, ApplyCascadedPropertyState&);
-
-            CSSPropertyID id;
-            CascadeLevel level;
-            Style::ScopeOrdinal styleScopeOrdinal;
-            CSSValue* cssValue[3];
-        };
-
-        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;
-        
-    private:
-        void addMatch(const MatchedProperties&, CascadeLevel, bool isImportant, bool inheritedOnly);
-        void set(CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, Style::ScopeOrdinal);
-        void setDeferred(CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, Style::ScopeOrdinal);
-        static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel, Style::ScopeOrdinal);
-
-        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;
-    };
 
     void applyCascadedProperties(int firstProperty, int lastProperty, ApplyCascadedPropertyState&);
     void applyCascadedCustomProperty(const String& name, ApplyCascadedPropertyState&);
@@ -278,7 +228,7 @@
     template<CustomPropertyCycleTracking>
     inline void applyCascadedPropertiesImpl(int firstProperty, int lastProperty, ApplyCascadedPropertyState&);
 
-    void cascadeMatches(CascadedProperties&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
+    void cascadeMatches(Style::PropertyCascade&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
 
     DocumentRuleSets m_ruleSets;
 
@@ -336,16 +286,16 @@
 
         const CSSToLengthConversionData& cssToLengthConversionData() const { return m_cssToLengthConversionData; }
 
-        CascadeLevel cascadeLevel() const { return m_cascadeLevel; }
-        void setCascadeLevel(CascadeLevel level) { m_cascadeLevel = level; }
+        Style::CascadeLevel cascadeLevel() const { return m_cascadeLevel; }
+        void setCascadeLevel(Style::CascadeLevel level) { m_cascadeLevel = level; }
         Style::ScopeOrdinal styleScopeOrdinal() const { return m_styleScopeOrdinal; }
         void setStyleScopeOrdinal(Style::ScopeOrdinal styleScopeOrdinal) { m_styleScopeOrdinal = styleScopeOrdinal; }
 
-        CascadedProperties* authorRollback() const { return m_authorRollback.get(); }
-        CascadedProperties* userRollback() const { return m_userRollback.get(); }
+        Style::PropertyCascade* authorRollback() const { return m_authorRollback.get(); }
+        Style::PropertyCascade* userRollback() const { return m_userRollback.get(); }
         
-        void setAuthorRollback(std::unique_ptr<CascadedProperties>& rollback) { m_authorRollback = WTFMove(rollback); }
-        void setUserRollback(std::unique_ptr<CascadedProperties>& rollback) { m_userRollback = WTFMove(rollback); }
+        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; }
         
@@ -357,8 +307,8 @@
         const RenderStyle* m_parentStyle { nullptr };
         std::unique_ptr<RenderStyle> m_ownedParentStyle;
         const RenderStyle* m_rootElementStyle { nullptr };
-        std::unique_ptr<CascadedProperties> m_authorRollback;
-        std::unique_ptr<CascadedProperties> m_userRollback;
+        std::unique_ptr<Style::PropertyCascade> m_authorRollback;
+        std::unique_ptr<Style::PropertyCascade> m_userRollback;
 
         const SelectorFilter* m_selectorFilter { nullptr };
 
@@ -371,7 +321,7 @@
         Style::ScopeOrdinal m_styleScopeOrdinal { Style::ScopeOrdinal::Element };
 
         InsideLink m_elementLinkState { InsideLink::NotInside };
-        CascadeLevel m_cascadeLevel { CascadeLevel::UserAgentLevel };
+        Style::CascadeLevel m_cascadeLevel { Style::CascadeLevel::UserAgent };
 
         bool m_applyPropertyToRegularStyle { true };
         bool m_applyPropertyToVisitedLinkStyle { false };
@@ -388,10 +338,7 @@
     bool applyPropertyToRegularStyle() const { return m_state.applyPropertyToRegularStyle(); }
     bool applyPropertyToVisitedLinkStyle() const { return m_state.applyPropertyToVisitedLinkStyle(); }
 
-    CascadeLevel cascadeLevel() const { return m_state.cascadeLevel(); }
-    void setCascadeLevel(CascadeLevel level) { m_state.setCascadeLevel(level); }
-    
-    CascadedProperties* cascadedPropertiesForRollback(const MatchResult&);
+    Style::PropertyCascade* cascadedPropertiesForRollback(const MatchResult&);
 
     CSSToStyleMap* styleMap() { return &m_styleMap; }
     InspectorCSSOMWrappers& inspectorCSSOMWrappers() { return m_inspectorCSSOMWrappers; }
@@ -407,11 +354,11 @@
 
     bool adjustRenderStyleForTextAutosizing(RenderStyle&, const Element&);
 
+    void applyProperty(CSSPropertyID, CSSValue*, ApplyCascadedPropertyState&, SelectorChecker::LinkMatchMask = SelectorChecker::MatchDefault);
+
 private:
     void cacheBorderAndBackground();
 
-    void applyProperty(CSSPropertyID, CSSValue*, ApplyCascadedPropertyState&, SelectorChecker::LinkMatchMask = SelectorChecker::MatchDefault);
-
     void applySVGProperty(CSSPropertyID, CSSValue*);
 
     static unsigned computeMatchedPropertiesHash(const MatchResult&);
@@ -476,7 +423,7 @@
 // properties have been resolved.
 struct ApplyCascadedPropertyState {
     StyleResolver* styleResolver;
-    StyleResolver::CascadedProperties* cascade;
+    Style::PropertyCascade* cascade;
     const MatchResult* matchResult;
     Bitmap<numCSSProperties> appliedProperties = { };
     HashSet<String> appliedCustomProperties = { };
@@ -484,7 +431,6 @@
     HashSet<String> inProgressPropertiesCustom = { };
 };
 
-
 inline bool StyleResolver::hasSelectorForAttribute(const Element& element, const AtomString &attributeName) const
 {
     ASSERT(!attributeName.isEmpty());
diff --git a/Source/WebCore/style/PropertyCascade.cpp b/Source/WebCore/style/PropertyCascade.cpp
new file mode 100644
index 0000000..53cd601
--- /dev/null
+++ b/Source/WebCore/style/PropertyCascade.cpp
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PropertyCascade.h"
+
+#include "StyleResolver.h"
+
+namespace WebCore {
+namespace Style {
+
+static inline bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
+{
+    switch (propertyID) {
+    case CSSPropertyWebkitBackgroundClip:
+    case CSSPropertyBackgroundClip:
+    case CSSPropertyWebkitBackgroundOrigin:
+    case CSSPropertyBackgroundOrigin:
+    case CSSPropertyWebkitBackgroundSize:
+    case CSSPropertyBackgroundSize:
+    case CSSPropertyWebkitBorderImage:
+    case CSSPropertyBorderImage:
+    case CSSPropertyBorderImageSlice:
+    case CSSPropertyBorderImageSource:
+    case CSSPropertyBorderImageOutset:
+    case CSSPropertyBorderImageRepeat:
+    case CSSPropertyBorderImageWidth:
+    case CSSPropertyWebkitBoxShadow:
+    case CSSPropertyBoxShadow:
+    case CSSPropertyWebkitTextDecoration:
+    case CSSPropertyTextDecorationLine:
+    case CSSPropertyTextDecorationStyle:
+    case CSSPropertyTextDecorationColor:
+    case CSSPropertyTextDecorationSkip:
+    case CSSPropertyTextUnderlinePosition:
+    case CSSPropertyTextUnderlineOffset:
+    case CSSPropertyTextDecorationThickness:
+    case CSSPropertyTextDecoration:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// https://www.w3.org/TR/css-pseudo-4/#marker-pseudo (Editor's Draft, 25 July 2017)
+static inline bool isValidMarkerStyleProperty(CSSPropertyID id)
+{
+    switch (id) {
+    case CSSPropertyColor:
+    case CSSPropertyFontFamily:
+    case CSSPropertyFontFeatureSettings:
+    case CSSPropertyFontSize:
+    case CSSPropertyFontStretch:
+    case CSSPropertyFontStyle:
+    case CSSPropertyFontSynthesis:
+    case CSSPropertyFontVariantAlternates:
+    case CSSPropertyFontVariantCaps:
+    case CSSPropertyFontVariantEastAsian:
+    case CSSPropertyFontVariantLigatures:
+    case CSSPropertyFontVariantNumeric:
+    case CSSPropertyFontVariantPosition:
+    case CSSPropertyFontWeight:
+#if ENABLE(VARIATION_FONTS)
+    case CSSPropertyFontOpticalSizing:
+    case CSSPropertyFontVariationSettings:
+#endif
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+#if ENABLE(VIDEO_TRACK)
+static inline bool isValidCueStyleProperty(CSSPropertyID id)
+{
+    switch (id) {
+    case CSSPropertyBackground:
+    case CSSPropertyBackgroundAttachment:
+    case CSSPropertyBackgroundClip:
+    case CSSPropertyBackgroundColor:
+    case CSSPropertyBackgroundImage:
+    case CSSPropertyBackgroundOrigin:
+    case CSSPropertyBackgroundPosition:
+    case CSSPropertyBackgroundPositionX:
+    case CSSPropertyBackgroundPositionY:
+    case CSSPropertyBackgroundRepeat:
+    case CSSPropertyBackgroundSize:
+    case CSSPropertyColor:
+    case CSSPropertyFont:
+    case CSSPropertyFontFamily:
+    case CSSPropertyFontSize:
+    case CSSPropertyFontStyle:
+    case CSSPropertyFontVariantCaps:
+    case CSSPropertyFontWeight:
+    case CSSPropertyLineHeight:
+    case CSSPropertyOpacity:
+    case CSSPropertyOutline:
+    case CSSPropertyOutlineColor:
+    case CSSPropertyOutlineOffset:
+    case CSSPropertyOutlineStyle:
+    case CSSPropertyOutlineWidth:
+    case CSSPropertyVisibility:
+    case CSSPropertyWhiteSpace:
+    case CSSPropertyTextDecoration:
+    case CSSPropertyTextShadow:
+    case CSSPropertyBorderStyle:
+    case CSSPropertyPaintOrder:
+    case CSSPropertyStrokeLinejoin:
+    case CSSPropertyStrokeLinecap:
+    case CSSPropertyStrokeColor:
+    case CSSPropertyStrokeWidth:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+#endif
+
+PropertyCascade::PropertyCascade(TextDirection direction, WritingMode writingMode)
+    : m_direction(direction)
+    , m_writingMode(writingMode)
+{
+}
+
+PropertyCascade::~PropertyCascade() = default;
+
+void PropertyCascade::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, ScopeOrdinal styleScopeOrdinal)
+{
+    ASSERT(linkMatchType <= SelectorChecker::MatchAll);
+    property.id = id;
+    property.level = cascadeLevel;
+    property.styleScopeOrdinal = styleScopeOrdinal;
+    if (linkMatchType == SelectorChecker::MatchAll) {
+        property.cssValue[0] = &cssValue;
+        property.cssValue[SelectorChecker::MatchLink] = &cssValue;
+        property.cssValue[SelectorChecker::MatchVisited] = &cssValue;
+    } else
+        property.cssValue[linkMatchType] = &cssValue;
+}
+
+void PropertyCascade::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, ScopeOrdinal styleScopeOrdinal)
+{
+    if (CSSProperty::isDirectionAwareProperty(id))
+        id = CSSProperty::resolveDirectionAwareProperty(id, m_direction, m_writingMode);
+
+    ASSERT(!shouldApplyPropertyInParseOrder(id));
+
+    auto& property = m_properties[id];
+    ASSERT(id < m_propertyIsPresent.size());
+    if (id == CSSPropertyCustom) {
+        m_propertyIsPresent.set(id);
+        const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
+        bool hasValue = 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);
+        } else {
+            Property property = customProperties().get(customValue.name());
+            setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
+            customProperties().set(customValue.name(), property);
+        }
+        return;
+    }
+
+    if (!m_propertyIsPresent[id])
+        memset(property.cssValue, 0, sizeof(property.cssValue));
+    m_propertyIsPresent.set(id);
+    setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
+}
+
+void PropertyCascade::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel, ScopeOrdinal styleScopeOrdinal)
+{
+    ASSERT(!CSSProperty::isDirectionAwareProperty(id));
+    ASSERT(shouldApplyPropertyInParseOrder(id));
+
+    Property property;
+    memset(property.cssValue, 0, sizeof(property.cssValue));
+    setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel, styleScopeOrdinal);
+    m_deferredProperties.append(property);
+}
+
+
+void PropertyCascade::addMatch(const MatchedProperties& matchedProperties, CascadeLevel cascadeLevel, bool isImportant, bool inheritedOnly)
+{
+    auto& styleProperties = *matchedProperties.properties;
+    auto propertyWhitelistType = static_cast<PropertyWhitelistType>(matchedProperties.whitelistType);
+
+    for (unsigned i = 0, count = styleProperties.propertyCount(); i < count; ++i) {
+        auto current = styleProperties.propertyAt(i);
+        if (isImportant != current.isImportant())
+            continue;
+        if (inheritedOnly && !current.isInherited()) {
+            // Inherited only mode is used after matched properties cache hit.
+            // A match with a value that is explicitly inherited should never have been cached.
+            ASSERT(!current.value()->isInheritedValue());
+            continue;
+        }
+        CSSPropertyID propertyID = current.id();
+
+#if ENABLE(VIDEO_TRACK)
+        if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(propertyID))
+            continue;
+#endif
+        if (propertyWhitelistType == PropertyWhitelistMarker && !isValidMarkerStyleProperty(propertyID))
+            continue;
+
+        if (shouldApplyPropertyInParseOrder(propertyID))
+            setDeferred(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
+        else
+            set(propertyID, *current.value(), matchedProperties.linkMatchType, cascadeLevel, matchedProperties.styleScopeOrdinal);
+    }
+}
+
+static auto& declarationsForCascadeLevel(const MatchResult& matchResult, CascadeLevel cascadeLevel)
+{
+    switch (cascadeLevel) {
+    case CascadeLevel::UserAgent: return matchResult.userAgentDeclarations;
+    case CascadeLevel::User: return matchResult.userDeclarations;
+    case CascadeLevel::Author: return matchResult.authorDeclarations;
+    }
+    ASSERT_NOT_REACHED();
+    return matchResult.authorDeclarations;
+}
+
+void PropertyCascade::addNormalMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
+{
+    for (auto& matchedDeclarations : declarationsForCascadeLevel(matchResult, cascadeLevel))
+        addMatch(matchedDeclarations, cascadeLevel, false, inheritedOnly);
+}
+
+static bool hasImportantProperties(const StyleProperties& properties)
+{
+    for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
+        if (properties.propertyAt(i).isImportant())
+            return true;
+    }
+    return false;
+}
+
+void PropertyCascade::addImportantMatches(const MatchResult& matchResult, CascadeLevel cascadeLevel, bool inheritedOnly)
+{
+    struct IndexAndOrdinal {
+        unsigned index;
+        ScopeOrdinal ordinal;
+    };
+    Vector<IndexAndOrdinal> importantMatches;
+    bool hasMatchesFromOtherScopes = false;
+
+    auto& matchedDeclarations = declarationsForCascadeLevel(matchResult, cascadeLevel);
+
+    for (unsigned i = 0; i < matchedDeclarations.size(); ++i) {
+        const MatchedProperties& matchedProperties = matchedDeclarations[i];
+
+        if (!hasImportantProperties(*matchedProperties.properties))
+            continue;
+
+        importantMatches.append({ i, matchedProperties.styleScopeOrdinal });
+
+        if (matchedProperties.styleScopeOrdinal != ScopeOrdinal::Element)
+            hasMatchesFromOtherScopes = true;
+    }
+
+    if (importantMatches.isEmpty())
+        return;
+
+    if (hasMatchesFromOtherScopes) {
+        // For !important properties a later shadow tree wins.
+        // Match results are sorted in reverse tree context order so this is not needed for normal properties.
+        std::stable_sort(importantMatches.begin(), importantMatches.end(), [] (const IndexAndOrdinal& a, const IndexAndOrdinal& b) {
+            return a.ordinal < b.ordinal;
+        });
+    }
+
+    for (auto& match : importantMatches)
+        addMatch(matchedDeclarations[match.index], cascadeLevel, true, inheritedOnly);
+}
+
+void PropertyCascade::applyDeferredProperties(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
+{
+    for (auto& property : m_deferredProperties)
+        property.apply(resolver, applyState);
+}
+
+void PropertyCascade::Property::apply(StyleResolver& resolver, ApplyCascadedPropertyState& applyState)
+{
+    StyleResolver::State& state = resolver.state();
+    state.setCascadeLevel(level);
+    state.setStyleScopeOrdinal(styleScopeOrdinal);
+
+    if (cssValue[SelectorChecker::MatchDefault]) {
+        state.setApplyPropertyToRegularStyle(true);
+        state.setApplyPropertyToVisitedLinkStyle(false);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], applyState, SelectorChecker::MatchDefault);
+    }
+
+    if (state.style()->insideLink() == InsideLink::NotInside)
+        return;
+
+    if (cssValue[SelectorChecker::MatchLink]) {
+        state.setApplyPropertyToRegularStyle(true);
+        state.setApplyPropertyToVisitedLinkStyle(false);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], applyState, SelectorChecker::MatchLink);
+    }
+
+    if (cssValue[SelectorChecker::MatchVisited]) {
+        state.setApplyPropertyToRegularStyle(false);
+        state.setApplyPropertyToVisitedLinkStyle(true);
+        resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], applyState, SelectorChecker::MatchVisited);
+    }
+
+    state.setApplyPropertyToRegularStyle(true);
+    state.setApplyPropertyToVisitedLinkStyle(false);
+}
+
+}
+}
diff --git a/Source/WebCore/style/PropertyCascade.h b/Source/WebCore/style/PropertyCascade.h
new file mode 100644
index 0000000..4e9d62a
--- /dev/null
+++ b/Source/WebCore/style/PropertyCascade.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ElementRuleCollector.h"
+#include <bitset>
+#include <wtf/Bitmap.h>
+
+namespace WebCore {
+
+class StyleResolver;
+struct ApplyCascadedPropertyState;
+
+namespace Style {
+
+enum class CascadeLevel : uint8_t {
+    UserAgent,
+    User,
+    Author
+};
+
+class PropertyCascade {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    PropertyCascade(TextDirection, WritingMode);
+    ~PropertyCascade();
+
+    struct Property {
+        void apply(StyleResolver&, ApplyCascadedPropertyState&);
+
+        CSSPropertyID id;
+        CascadeLevel level;
+        ScopeOrdinal styleScopeOrdinal;
+        CSSValue* cssValue[3];
+    };
+
+    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;
+
+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);
+
+    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;
+};
+
+inline bool PropertyCascade::hasProperty(CSSPropertyID id) const
+{
+    ASSERT(id < m_propertyIsPresent.size());
+    return m_propertyIsPresent[id];
+}
+
+inline PropertyCascade::Property& PropertyCascade::property(CSSPropertyID id)
+{
+    return m_properties[id];
+}
+
+inline bool PropertyCascade::hasCustomProperty(const String& name) const
+{
+    return m_customProperties.contains(name);
+}
+
+inline PropertyCascade::Property PropertyCascade::customProperty(const String& name) const
+{
+    return m_customProperties.get(name);
+}
+
+}
+}