Index: Source/core/css/resolver/CascadedValues.cpp |
diff --git a/Source/core/css/resolver/CascadedValues.cpp b/Source/core/css/resolver/CascadedValues.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6249a4c204feea346c5640dba702f780d41195d6 |
--- /dev/null |
+++ b/Source/core/css/resolver/CascadedValues.cpp |
@@ -0,0 +1,256 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/css/resolver/CascadedValues.h" |
+ |
+#include "core/css/CSSValuePool.h" |
+#include "core/css/StylePropertySet.h" |
+#include "core/css/resolver/MatchResult.h" |
+#include "core/css/resolver/StyleBuilder.h" |
+#include "core/css/resolver/StyleResolver.h" |
+#include "core/css/resolver/StyleResolverState.h" |
+#include <algorithm> |
+ |
+namespace blink { |
+ |
+// We want properties in their prefixed and non-prefixed variants to cascade |
+// together, so we map them to the same property before adding to the cascade. |
+static CSSPropertyID resolveProperty(CSSPropertyID property, TextDirection direction, WritingMode writingMode) |
+{ |
+ switch (property) { |
+ case CSSPropertyWebkitBorderEndColor: |
+ case CSSPropertyWebkitBorderBeforeStyle: |
+ case CSSPropertyWebkitBorderEndStyle: |
+ case CSSPropertyWebkitPaddingStart: |
+ case CSSPropertyWebkitBorderStartWidth: |
+ case CSSPropertyWebkitMaxLogicalWidth: |
+ case CSSPropertyWebkitLogicalHeight: |
+ case CSSPropertyWebkitMinLogicalWidth: |
+ case CSSPropertyWebkitBorderBeforeWidth: |
+ case CSSPropertyWebkitPaddingBefore: |
+ case CSSPropertyWebkitBorderBeforeColor: |
+ case CSSPropertyWebkitMarginEnd: |
+ case CSSPropertyWebkitBorderAfterWidth: |
+ case CSSPropertyWebkitMinLogicalHeight: |
+ case CSSPropertyWebkitBorderEndWidth: |
+ case CSSPropertyWebkitPaddingEnd: |
+ case CSSPropertyWebkitLogicalWidth: |
+ case CSSPropertyWebkitBorderAfterColor: |
+ case CSSPropertyWebkitMaxLogicalHeight: |
+ case CSSPropertyWebkitBorderStartColor: |
+ case CSSPropertyWebkitBorderAfterStyle: |
+ case CSSPropertyWebkitPaddingAfter: |
+ case CSSPropertyWebkitBorderStartStyle: |
+ case CSSPropertyWebkitMarginBefore: |
+ case CSSPropertyWebkitMarginStart: |
+ case CSSPropertyWebkitMarginAfter: |
+ return CSSProperty::resolveDirectionAwareProperty(property, direction, writingMode); |
+ case CSSPropertyWebkitBackfaceVisibility: |
+ return CSSPropertyBackfaceVisibility; |
+ case CSSPropertyWebkitBackgroundClip: |
+ return CSSPropertyBackgroundClip; |
+ case CSSPropertyWebkitBackgroundOrigin: |
+ return CSSPropertyBackgroundOrigin; |
+ case CSSPropertyWebkitBackgroundSize: |
+ return CSSPropertyBackgroundSize; |
+ case CSSPropertyWebkitBoxShadow: |
+ return CSSPropertyBoxShadow; |
+ case CSSPropertyWebkitTransform: |
+ return CSSPropertyTransform; |
+ case CSSPropertyWebkitTransformStyle: |
+ return CSSPropertyTransformStyle; |
+ case CSSPropertyWebkitPerspective: |
+ return CSSPropertyPerspective; |
+ case CSSPropertyWebkitPerspectiveOrigin: |
+ return CSSPropertyPerspectiveOrigin; |
+ // Used by editing when the css3 text decorations flag is off |
+ case CSSPropertyTextDecoration: |
+ ASSERT(!RuntimeEnabledFeatures::css3TextDecorationsEnabled()); |
+ return CSSPropertyTextDecorationLine; |
+ // As per css3-text, word-wrap is an alias for overflow-wrap |
+ case CSSPropertyWordWrap: |
+ return CSSPropertyOverflowWrap; |
+ default: |
+ return property; |
+ } |
+} |
+ |
+CascadedValues::CascadedValues(StyleResolverState& state, const MatchResult& matchResult, bool onlyAddUARules) |
+ : m_state(state) |
+{ |
+ memset(m_values, 0, sizeof(m_values)); |
+ if (m_state.style()->insideLink()) |
+ memset(m_visitedLinkValues, 0, sizeof(m_visitedLinkValues)); |
+ |
+ // The MatchResult has rules in UA - User - Author order, although we only |
+ // use user rules for callback selectors. |
+ addMatchResult(matchResult, CSSPropertyDirection, CSSPropertyWebkitWritingMode); |
+ applyValues(CSSPropertyDirection, CSSPropertyWebkitWritingMode); |
+ m_direction = state.style()->direction(); |
+ m_writingMode = state.style()->writingMode(); |
+ |
+ COMPILE_ASSERT(CSSPropertyColor == CSSPropertyWebkitWritingMode + 1, CSS_color_is_after_super_high_priority); |
+ if (onlyAddUARules) { |
+ addMatchResultRange(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, CSSPropertyColor, convertToCSSPropertyID(lastCSSProperty)); |
+ } else { |
+ addMatchResult(matchResult, CSSPropertyColor, convertToCSSPropertyID(lastCSSProperty)); |
+ } |
+ |
+ std::sort(setProperties.begin(), setProperties.end()); |
+ std::sort(setVisitedProperties.begin(), setVisitedProperties.end()); |
+} |
+ |
+void CascadedValues::addMatchResult(const MatchResult& matchResult, CSSPropertyID firstId, CSSPropertyID lastId) |
+{ |
+ addMatchResultRange(matchResult, false, 0, matchResult.matchedProperties.size() - 1, firstId, lastId); |
+ addMatchResultRange(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, firstId, lastId); |
+ addMatchResultRange(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, firstId, lastId); |
+} |
+ |
+void CascadedValues::addMatchResultRange(const MatchResult& matchResult, bool isImportant, int firstIndex, int lastIndex, CSSPropertyID firstId, CSSPropertyID lastId) |
+{ |
+ if (firstIndex == -1) |
+ return; |
+ |
+ for (int i = firstIndex; i <= lastIndex; ++i) { |
+ const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; |
+ SelectorChecker::LinkMatchMask linkMatchType = SelectorChecker::MatchLink; |
+ if (m_state.style()->insideLink()) |
+ linkMatchType = static_cast<SelectorChecker::LinkMatchMask>(matchedProperties.m_types.linkMatchType); |
+ addStylePropertySet(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, firstId, lastId, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType), linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::addStylePropertySet(const StylePropertySet* properties, const StyleRule* rule, bool isImportant, CSSPropertyID first, CSSPropertyID last, PropertyWhitelistType propertyWhitelistType, SelectorChecker::LinkMatchMask linkMatchType) |
+{ |
+ unsigned propertyCount = properties->propertyCount(); |
+ for (unsigned i = 0; i < propertyCount; ++i) { |
+ StylePropertySet::PropertyReference current = properties->propertyAt(i); |
+ if (isImportant != current.isImportant()) |
+ continue; |
+ |
+ CSSPropertyID property = current.id(); |
+ if (property < first || property > last) |
+ continue; |
+ |
+ // FIXME: We should check the whitelist, otherwise we might run into |
+ // problems with e.g. foo:first-letter { all: inherit; } |
+ if (property == CSSPropertyAll) { |
+ addAllProperty(current.value(), linkMatchType); |
+ continue; |
+ } |
+ |
+ if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(property)) |
+ continue; |
+ if (propertyWhitelistType == PropertyWhitelistFirstLetter && !StyleResolver::isValidFirstLetterStyleProperty(property)) |
+ continue; |
+ addValue(current.id(), current.value(), rule, linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::addValue(CSSPropertyID property, CSSValue* value, const StyleRule* rule, SelectorChecker::LinkMatchMask linkMatchType) |
+{ |
+ property = resolveProperty(property, m_direction, m_writingMode); |
+ |
+ if (property == CSSPropertyInternalCallback) { |
+ ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueInternalPresence); |
+ m_state.style()->addCallbackSelector(rule->selectorList().selectorsText()); |
+ return; |
+ } |
+ |
+ // Shorthands that are not expanded in the parser need special handling here. |
+ // The shorthand property occurs earlier in CSSPropertyNames.in than its |
+ // longhands so we can cascade properly. If a longhand value is explicitly |
+ // set, with higher priority than the shorthand, then the value computed |
+ // from the shorthand will be overriden. |
+ |
+ // FIXME: font should always be expanded by the parser; crbug.com/353932 |
+ if (property == CSSPropertyFont) { |
+ clearCascadedValue(CSSPropertyLineHeight); |
+ clearCascadedValue(CSSPropertyFontStyle); |
+ clearCascadedValue(CSSPropertyFontFamily); |
+ clearCascadedValue(CSSPropertyFontVariant); |
+ clearCascadedValue(CSSPropertyFontWeight); |
+ clearCascadedValue(CSSPropertyFontStretch); |
+ clearCascadedValue(CSSPropertyFontSize); |
+ } |
+ |
+ // -webkit-border-image sometimes also sets border-*-width, but properly |
+ // cascading this requires too much effort |
+ if (property == CSSPropertyWebkitBorderImage) { |
+ clearCascadedValue(CSSPropertyBorderImageSource); |
+ clearCascadedValue(CSSPropertyBorderImageSlice); |
+ clearCascadedValue(CSSPropertyBorderImageWidth); |
+ clearCascadedValue(CSSPropertyBorderImageOutset); |
+ clearCascadedValue(CSSPropertyBorderImageRepeat); |
+ } |
+ |
+ if (linkMatchType & SelectorChecker::MatchLink) |
+ setCascadedValue(property, value); |
+ if (linkMatchType & SelectorChecker::MatchVisited) |
+ setCascadedVisitedLinkValue(property, value); |
+} |
+ |
+void CascadedValues::addAllProperty(CSSValue* value, SelectorChecker::LinkMatchMask linkMatchType) |
+{ |
+ if (!value->isInitialValue() && !value->isInheritedValue()) { |
+ ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueUnset); |
+ value = nullptr; |
+ } |
+ |
+ for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) { |
+ CSSPropertyID property = convertToCSSPropertyID(i); |
+ if (CSSProperty::isAffectedByAllProperty(property)) |
+ addValue(property, value, nullptr, linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::setCascadedValue(CSSPropertyID id, CSSValue* value) |
+{ |
+ if (!m_values[id - firstCSSProperty]) |
+ setProperties.append(id); |
+ m_values[id - firstCSSProperty] = value; |
+} |
+ |
+void CascadedValues::setCascadedVisitedLinkValue(CSSPropertyID id, CSSValue* value) |
+{ |
+ ASSERT(m_state.style()->insideLink()); |
+ if (!m_visitedLinkValues[id - firstCSSProperty]) |
+ setVisitedProperties.append(id); |
+ m_visitedLinkValues[id - firstCSSProperty] = value; |
+} |
+ |
+void CascadedValues::applyValues(CSSPropertyID first, CSSPropertyID last, bool inheritedOnly) |
+{ |
+ for (size_t i = 0; i < setProperties.size(); i++) { |
+ CSSPropertyID property = setProperties[i]; |
+ if (property < first || property > last) |
+ continue; |
+ // We might not have a value due to the shorthand special-cases in addValue |
+ if (!cascadedValue(property)) |
+ continue; |
+ if (!inheritedOnly || CSSProperty::isInheritedProperty(property)) |
+ StyleBuilder::applyProperty(property, m_state, cascadedValue(property)); |
+ } |
+ |
+ if (!m_state.style()->insideLink()) |
+ return; |
+ |
+ m_state.setApplyPropertyToRegularStyle(false); |
+ m_state.setApplyPropertyToVisitedLinkStyle(true); |
+ for (size_t i = 0; i < setVisitedProperties.size(); i++) { |
+ CSSPropertyID property = setVisitedProperties[i]; |
+ if (property < first || property > last) |
+ continue; |
+ ASSERT(cascadedVisitedLinkValue(property)); |
+ if (!inheritedOnly || CSSProperty::isInheritedProperty(property)) |
+ StyleBuilder::applyProperty(property, m_state, cascadedVisitedLinkValue(property)); |
+ } |
+ m_state.setApplyPropertyToRegularStyle(true); |
+ m_state.setApplyPropertyToVisitedLinkStyle(false); |
+} |
+ |
+ |
+} // namespace blink |