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..63ce8de4e74e5a692411c77abd63a56a018a0ace |
--- /dev/null |
+++ b/Source/core/css/resolver/CascadedValues.cpp |
@@ -0,0 +1,394 @@ |
+// 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/StyleResolverState.h" |
+ |
+namespace WebCore { |
+ |
+namespace { |
+ |
+bool isValidCueStyleProperty(CSSPropertyID property) |
+{ |
+ switch (property) { |
+ case CSSPropertyBackground: |
+ case CSSPropertyBackgroundAttachment: |
+ case CSSPropertyBackgroundClip: |
+ case CSSPropertyBackgroundColor: |
+ case CSSPropertyBackgroundImage: |
+ case CSSPropertyBackgroundOrigin: |
+ case CSSPropertyBackgroundPosition: |
+ case CSSPropertyBackgroundPositionX: |
+ case CSSPropertyBackgroundPositionY: |
+ case CSSPropertyBackgroundRepeat: |
+ case CSSPropertyBackgroundRepeatX: |
+ case CSSPropertyBackgroundRepeatY: |
+ case CSSPropertyBackgroundSize: |
+ case CSSPropertyColor: |
+ case CSSPropertyFont: |
+ case CSSPropertyFontFamily: |
+ case CSSPropertyFontSize: |
+ case CSSPropertyFontStyle: |
+ case CSSPropertyFontVariant: |
+ case CSSPropertyFontWeight: |
+ case CSSPropertyLineHeight: |
+ case CSSPropertyOpacity: |
+ case CSSPropertyOutline: |
+ case CSSPropertyOutlineColor: |
+ case CSSPropertyOutlineOffset: |
+ case CSSPropertyOutlineStyle: |
+ case CSSPropertyOutlineWidth: |
+ case CSSPropertyVisibility: |
+ case CSSPropertyWhiteSpace: |
+ // FIXME: 'text-decoration' shorthand to be handled when available. |
+ // See https://chromiumcodereview.appspot.com/19516002 for details. |
+ case CSSPropertyTextDecoration: |
+ case CSSPropertyTextShadow: |
+ case CSSPropertyBorderStyle: |
+ return true; |
+ case CSSPropertyTextDecorationLine: |
+ case CSSPropertyTextDecorationStyle: |
+ case CSSPropertyTextDecorationColor: |
+ return RuntimeEnabledFeatures::css3TextDecorationsEnabled(); |
+ default: |
+ break; |
+ } |
+ return false; |
+} |
+ |
+bool isValidFirstLetterStyleProperty(CSSPropertyID property) |
+{ |
+ switch (property) { |
+ // Valid ::first-letter properties listed in spec: |
+ // http://www.w3.org/TR/css3-selectors/#application-in-css |
+ case CSSPropertyBackgroundAttachment: |
+ case CSSPropertyBackgroundBlendMode: |
+ case CSSPropertyBackgroundClip: |
+ case CSSPropertyBackgroundColor: |
+ case CSSPropertyBackgroundImage: |
+ case CSSPropertyBackgroundOrigin: |
+ case CSSPropertyBackgroundPosition: |
+ case CSSPropertyBackgroundPositionX: |
+ case CSSPropertyBackgroundPositionY: |
+ case CSSPropertyBackgroundRepeat: |
+ case CSSPropertyBackgroundRepeatX: |
+ case CSSPropertyBackgroundRepeatY: |
+ case CSSPropertyBackgroundSize: |
+ case CSSPropertyBorderBottomColor: |
+ case CSSPropertyBorderBottomLeftRadius: |
+ case CSSPropertyBorderBottomRightRadius: |
+ case CSSPropertyBorderBottomStyle: |
+ case CSSPropertyBorderBottomWidth: |
+ case CSSPropertyBorderImageOutset: |
+ case CSSPropertyBorderImageRepeat: |
+ case CSSPropertyBorderImageSlice: |
+ case CSSPropertyBorderImageSource: |
+ case CSSPropertyBorderImageWidth: |
+ case CSSPropertyBorderLeftColor: |
+ case CSSPropertyBorderLeftStyle: |
+ case CSSPropertyBorderLeftWidth: |
+ case CSSPropertyBorderRightColor: |
+ case CSSPropertyBorderRightStyle: |
+ case CSSPropertyBorderRightWidth: |
+ case CSSPropertyBorderTopColor: |
+ case CSSPropertyBorderTopLeftRadius: |
+ case CSSPropertyBorderTopRightRadius: |
+ case CSSPropertyBorderTopStyle: |
+ case CSSPropertyBorderTopWidth: |
+ case CSSPropertyColor: |
+ case CSSPropertyFloat: |
+ case CSSPropertyFont: |
+ case CSSPropertyFontFamily: |
+ case CSSPropertyFontKerning: |
+ case CSSPropertyFontSize: |
+ case CSSPropertyFontStretch: |
+ case CSSPropertyFontStyle: |
+ case CSSPropertyFontVariant: |
+ case CSSPropertyFontVariantLigatures: |
+ case CSSPropertyFontWeight: |
+ case CSSPropertyLetterSpacing: |
+ case CSSPropertyLineHeight: |
+ case CSSPropertyMarginBottom: |
+ case CSSPropertyMarginLeft: |
+ case CSSPropertyMarginRight: |
+ case CSSPropertyMarginTop: |
+ case CSSPropertyPaddingBottom: |
+ case CSSPropertyPaddingLeft: |
+ case CSSPropertyPaddingRight: |
+ case CSSPropertyPaddingTop: |
+ case CSSPropertyTextTransform: |
+ case CSSPropertyVerticalAlign: |
+ case CSSPropertyWebkitBackgroundClip: |
+ case CSSPropertyWebkitBackgroundComposite: |
+ case CSSPropertyWebkitBackgroundOrigin: |
+ case CSSPropertyWebkitBackgroundSize: |
+ case CSSPropertyWebkitBorderAfter: |
+ case CSSPropertyWebkitBorderAfterColor: |
+ case CSSPropertyWebkitBorderAfterStyle: |
+ case CSSPropertyWebkitBorderAfterWidth: |
+ case CSSPropertyWebkitBorderBefore: |
+ case CSSPropertyWebkitBorderBeforeColor: |
+ case CSSPropertyWebkitBorderBeforeStyle: |
+ case CSSPropertyWebkitBorderBeforeWidth: |
+ case CSSPropertyWebkitBorderEnd: |
+ case CSSPropertyWebkitBorderEndColor: |
+ case CSSPropertyWebkitBorderEndStyle: |
+ case CSSPropertyWebkitBorderEndWidth: |
+ case CSSPropertyWebkitBorderFit: |
+ case CSSPropertyWebkitBorderHorizontalSpacing: |
+ case CSSPropertyWebkitBorderImage: |
+ case CSSPropertyWebkitBorderRadius: |
+ case CSSPropertyWebkitBorderStart: |
+ case CSSPropertyWebkitBorderStartColor: |
+ case CSSPropertyWebkitBorderStartStyle: |
+ case CSSPropertyWebkitBorderStartWidth: |
+ case CSSPropertyWebkitBorderVerticalSpacing: |
+ case CSSPropertyWebkitFontSmoothing: |
+ case CSSPropertyWebkitMarginAfter: |
+ case CSSPropertyWebkitMarginAfterCollapse: |
+ case CSSPropertyWebkitMarginBefore: |
+ case CSSPropertyWebkitMarginBeforeCollapse: |
+ case CSSPropertyWebkitMarginBottomCollapse: |
+ case CSSPropertyWebkitMarginCollapse: |
+ case CSSPropertyWebkitMarginEnd: |
+ case CSSPropertyWebkitMarginStart: |
+ case CSSPropertyWebkitMarginTopCollapse: |
+ case CSSPropertyWordSpacing: |
+ return true; |
+ case CSSPropertyTextDecorationColor: |
+ case CSSPropertyTextDecorationLine: |
+ case CSSPropertyTextDecorationStyle: |
+ return RuntimeEnabledFeatures::css3TextDecorationsEnabled(); |
+ |
+ // text-shadow added in text decoration spec: |
+ // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property |
+ case CSSPropertyTextShadow: |
+ // box-shadox added in CSS3 backgrounds spec: |
+ // http://www.w3.org/TR/css3-background/#placement |
+ case CSSPropertyBoxShadow: |
+ case CSSPropertyWebkitBoxShadow: |
+ // Properties that we currently support outside of spec. |
+ case CSSPropertyWebkitLineBoxContain: |
+ case CSSPropertyVisibility: |
+ return true; |
+ |
+ default: |
+ return false; |
+ } |
+} |
+ |
+// 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. |
+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; |
+ } |
+} |
+ |
+} // namespace |
+ |
+CascadedValues::CascadedValues(StyleResolverState& state, const MatchResult& matchResult) |
+ : state(state) |
+{ |
+ memset(values, 0, sizeof(values)); |
+ memset(visitedLinkValues, 0, sizeof(visitedLinkValues)); |
+ |
+ bool seenImportantDirection = false; |
+ bool seenImportantWritingMode = false; |
+ for (size_t i = 0; i < matchResult.matchedProperties.size(); ++i) { |
andersr
2014/07/17 12:15:38
This code *seems* annoyingly redundant, since it d
Timothy Loh
2014/07/21 06:05:59
Done.
|
+ const StylePropertySet& properties = *matchResult.matchedProperties[i].properties; |
+ unsigned propertyCount = properties.propertyCount(); |
+ for (size_t j = 0; j < propertyCount; ++j) { |
+ StylePropertySet::PropertyReference current = properties.propertyAt(j); |
+ if (current.id() == CSSPropertyDirection) { |
+ if (seenImportantDirection && !current.isImportant()) |
+ continue; |
+ seenImportantDirection = current.isImportant(); |
+ } else if (current.id() == CSSPropertyWebkitWritingMode) { |
+ if (seenImportantWritingMode && !current.isImportant()) |
+ continue; |
+ seenImportantWritingMode = current.isImportant(); |
+ } else { |
+ continue; |
+ } |
+ StyleBuilder::applyProperty(current.id(), state, current.value()); |
+ } |
+ } |
+ |
+ direction = state.style()->direction(); |
+ writingMode = state.style()->writingMode(); |
+} |
+ |
+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 = static_cast<CSSPropertyID>(i); |
+ if (CSSProperty::isAffectedByAllProperty(property)) |
+ addValue(property, value, nullptr, linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::addValue(CSSPropertyID property, CSSValue* value, const StyleRule* rule, SelectorChecker::LinkMatchMask linkMatchType) |
+{ |
+ property = resolveProperty(property, direction, writingMode); |
+ |
+ if (property == CSSPropertyInternalCallback) { |
+ ASSERT(value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueInternalPresence); |
+ state.style()->addCallbackSelector(rule->selectorList().selectorsText()); |
+ return; |
+ } |
+ |
+ // FIXME: font is a shorthand but system fonts are not currently expanded (crbug.com/353932). |
+ // For now, we explicitly clear the properties for which font is a shorthand |
+ // and rely on font having a lower CSSPropertyID than these other properties. |
+ if (property == CSSPropertyFont) { |
+ values[CSSPropertyLineHeight - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontStyle - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontFamily - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontVariant - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontWeight - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontStyle - firstCSSProperty] = nullptr; |
+ values[CSSPropertyFontSize - firstCSSProperty] = nullptr; |
+ } |
+ |
+ // -webkit-border-image is a shorthand for the below properties but not |
+ // expanded in the parser. It sometimes also sets border-*-width, but |
+ // we'll not try too hard to support legacy properties |
+ if (property == CSSPropertyWebkitBorderImage) { |
+ values[CSSPropertyBorderImageSource - firstCSSProperty] = nullptr; |
+ values[CSSPropertyBorderImageSlice - firstCSSProperty] = nullptr; |
+ values[CSSPropertyBorderImageWidth - firstCSSProperty] = nullptr; |
+ values[CSSPropertyBorderImageOutset - firstCSSProperty] = nullptr; |
+ values[CSSPropertyBorderImageRepeat - firstCSSProperty] = nullptr; |
+ } |
+ |
+ if (linkMatchType & SelectorChecker::MatchLink) |
+ values[property - firstCSSProperty] = value; |
+ if (linkMatchType & SelectorChecker::MatchVisited) |
+ visitedLinkValues[property - firstCSSProperty] = value; |
+} |
+ |
+void CascadedValues::addValues(const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex) |
+{ |
+ if (startIndex == -1) |
+ return; |
+ |
+ for (int i = startIndex; i <= endIndex; ++i) { |
+ const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; |
+ SelectorChecker::LinkMatchMask linkMatchType = SelectorChecker::MatchLink; |
+ if (state.style()->insideLink()) |
+ linkMatchType = static_cast<SelectorChecker::LinkMatchMask>(matchedProperties.m_types.linkMatchType); |
+ addValues(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType), linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::addValues(const StylePropertySet* properties, const StyleRule* rule, bool isImportant, 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(); |
+ |
+ // 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 && !isValidCueStyleProperty(property)) |
+ continue; |
+ if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property)) |
+ continue; |
+ addValue(current.id(), current.value(), rule, linkMatchType); |
+ } |
+} |
+ |
+void CascadedValues::applyValues(CSSPropertyID start, CSSPropertyID end, bool inheritedOnly) |
andersr
2014/07/17 12:15:38
Is first/last more appropriate than start/end?
Timothy Loh
2014/07/21 06:05:59
Good idea; changed to first/last.
|
+{ |
+ for (int i = start - firstCSSProperty; i <= end - firstCSSProperty; i++) { |
+ CSSPropertyID property = static_cast<CSSPropertyID>(i + firstCSSProperty); |
+ if (inheritedOnly && !CSSProperty::isInheritedProperty(property)) |
+ continue; |
+ if (values[i]) |
+ StyleBuilder::applyProperty(property, state, values[i]); |
+ if (visitedLinkValues[i]) { |
+ state.setApplyPropertyToRegularStyle(false); |
+ state.setApplyPropertyToVisitedLinkStyle(true); |
+ StyleBuilder::applyProperty(property, state, visitedLinkValues[i]); |
+ state.setApplyPropertyToRegularStyle(true); |
+ state.setApplyPropertyToVisitedLinkStyle(false); |
+ } |
+ } |
+} |
+ |
+} // namespace WebCore |