Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Unified Diff: Source/core/css/resolver/CascadedValues.cpp

Issue 350333003: Cascade declared property values instead of applying values on top of each other (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebase Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/css/resolver/CascadedValues.h ('k') | Source/core/css/resolver/StyleBuilderCustom.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « Source/core/css/resolver/CascadedValues.h ('k') | Source/core/css/resolver/StyleBuilderCustom.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698