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

Unified Diff: Source/core/css/resolver/StyleResolver.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/StyleResolver.h ('k') | Source/core/css/resolver/StyleResolverState.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/css/resolver/StyleResolver.cpp
diff --git a/Source/core/css/resolver/StyleResolver.cpp b/Source/core/css/resolver/StyleResolver.cpp
index def181eac3c036c4beab0c9f3e919080452af308..7d204bfe79270ec7c1393e80e3457d81ea7f8adc 100644
--- a/Source/core/css/resolver/StyleResolver.cpp
+++ b/Source/core/css/resolver/StyleResolver.cpp
@@ -31,7 +31,6 @@
#include "core/CSSPropertyNames.h"
#include "core/HTMLNames.h"
-#include "core/StylePropertyShorthand.h"
#include "core/animation/ActiveAnimations.h"
#include "core/animation/Animation.h"
#include "core/animation/AnimationTimeline.h"
@@ -59,6 +58,7 @@
#include "core/css/StyleSheetContents.h"
#include "core/css/parser/BisonCSSParser.h"
#include "core/css/resolver/AnimatedStyleBuilder.h"
+#include "core/css/resolver/CascadedValues.h"
#include "core/css/resolver/MatchResult.h"
#include "core/css/resolver/MediaQueryResult.h"
#include "core/css/resolver/SharedStyleFinder.h"
@@ -97,6 +97,18 @@ void setAnimationUpdateIfNeeded(StyleResolverState& state, Element& element)
element.ensureActiveAnimations().cssAnimations().setPendingUpdate(state.takeAnimationUpdate());
}
+static bool elementTypeHasAppearanceFromUAStyle(const Element& element)
+{
+ // These elements have -webkit-appearance specified in html.css
+ const AtomicString& localName = element.localName();
+ return localName == HTMLNames::inputTag
+ || localName == HTMLNames::textareaTag
+ || localName == HTMLNames::buttonTag
+ || localName == HTMLNames::progressTag
+ || localName == HTMLNames::selectTag
+ || localName == HTMLNames::meterTag;
+}
+
} // namespace
namespace blink {
@@ -679,6 +691,38 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
return state.takeStyle();
}
+// FIXME: Consider refactoring to create a new class which owns the following
+// first/last/range properties.
+// c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in.
+
+template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>()
+{
+ COMPILE_ASSERT(CSSPropertyColor == CSSPropertyWebkitWritingMode + 1, CSS_color_is_first_high_priority_property);
+ return CSSPropertyColor;
+}
+
+template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>()
+{
+ return CSSPropertyZoom;
+}
+
+template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>()
+{
+ COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyZoom + 1, CSS_background_is_first_low_priority_property);
+ return CSSPropertyBackground;
+}
+
+template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>()
+{
+ return convertToCSSPropertyID(lastCSSProperty);
+}
+
+template <StyleResolver::StyleApplicationPass pass>
+bool StyleResolver::isPropertyForPass(CSSPropertyID property)
+{
+ return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
+}
+
PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const RenderStyle& elementStyle, RenderStyle* parentStyle, const StyleKeyframe* keyframe, const AtomicString& animationName)
{
ASSERT(document().frame());
@@ -689,34 +733,24 @@ PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const
resetDirectionAndWritingModeOnDocument(document());
StyleResolverState state(document(), element, parentStyle);
- MatchResult result;
- result.addMatchedProperties(&keyframe->properties());
+ MatchResult matchResult;
+ matchResult.addMatchedProperties(&keyframe->properties());
ASSERT(!state.style());
// Create the style
state.setStyle(RenderStyle::clone(&elementStyle));
- state.setLineHeightValue(0);
state.fontBuilder().initForStyleResolve(state.document(), state.style());
- // 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.
- // We also don't need to bother with animation properties since the only
- // relevant one is animation-timing-function and we special-case that in
- // CSSAnimations.cpp
- bool inheritedOnly = false;
- applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
+ CascadedValues cascadedValues(state, matchResult);
+
+ cascadedValues.applyValues(firstCSSPropertyId<HighPriorityProperties>(), lastCSSPropertyId<HighPriorityProperties>());
// If our font got dirtied, go ahead and update it now.
updateFont(state);
- // Line-height is set when we are sure we decided on the font-size
- if (state.lineHeightValue())
- StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
-
- // Now do rest of the properties.
- applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
+ cascadedValues.applyValues(firstCSSPropertyId<LowPriorityProperties>(), lastCSSPropertyId<LowPriorityProperties>());
loadPendingResources(state);
@@ -883,20 +917,15 @@ PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
if (ScopedStyleResolver* scopedResolver = document().scopedStyleResolver())
scopedResolver->matchPageRules(collector);
- state.setLineHeightValue(0);
- bool inheritedOnly = false;
+ MatchResult& matchResult = collector.matchedResult();
+ CascadedValues cascadedValues(state, matchResult);
- MatchResult& result = collector.matchedResult();
- applyMatchedProperties<HighPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
+ cascadedValues.applyValues(firstCSSPropertyId<HighPriorityProperties>(), lastCSSPropertyId<HighPriorityProperties>());
// If our font got dirtied, go ahead and update it now.
updateFont(state);
- // Line-height is set when we are sure we decided on the font-size.
- if (state.lineHeightValue())
- StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
-
- applyMatchedProperties<LowPriorityProperties>(state, result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
+ cascadedValues.applyValues(firstCSSPropertyId<LowPriorityProperties>(), lastCSSPropertyId<LowPriorityProperties>());
addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
@@ -931,7 +960,6 @@ PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
state.setStyle(RenderStyle::create());
state.fontBuilder().initForStyleResolve(document(), state.style());
state.style()->setLineHeight(RenderStyle::initialLineHeight());
- state.setLineHeightValue(0);
state.fontBuilder().setInitial(state.style()->effectiveZoom());
state.style()->font().update(document().styleEngine()->fontSelector());
return state.takeStyle();
@@ -1015,6 +1043,9 @@ bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, Element*
const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations = state.animationUpdate()->activeInterpolationsForAnimations();
const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions = state.animationUpdate()->activeInterpolationsForTransitions();
+
+ // FIXME: Is it possible to use CascadedValues here or is it too expensive to
+ // convert from Interpolations to CSSValues?
applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForAnimations);
applyAnimatedProperties<HighPriorityProperties>(state, activeInterpolationsForTransitions);
@@ -1089,7 +1120,7 @@ void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const Wil
}
}
-static inline bool isValidCueStyleProperty(CSSPropertyID id)
+bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
{
switch (id) {
case CSSPropertyBackground:
@@ -1138,7 +1169,7 @@ static inline bool isValidCueStyleProperty(CSSPropertyID id)
return false;
}
-static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
+bool StyleResolver::isValidFirstLetterStyleProperty(CSSPropertyID id)
{
switch (id) {
// Valid ::first-letter properties listed in spec:
@@ -1259,154 +1290,6 @@ static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id)
}
}
-// FIXME: Consider refactoring to create a new class which owns the following
-// first/last/range properties.
-// This method returns the first CSSPropertyId of high priority properties.
-// Other properties can depend on high priority properties. For example,
-// border-color property with currentColor value depends on color property.
-// All high priority properties are obtained by using
-// firstCSSPropertyId<HighPriorityProperties> and
-// lastCSSPropertyId<HighPriorityProperties>.
-template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::HighPriorityProperties>()
-{
- COMPILE_ASSERT(CSSPropertyColor == firstCSSProperty, CSS_color_is_first_high_priority_property);
- return CSSPropertyColor;
-}
-
-// This method returns the last CSSPropertyId of high priority properties.
-template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::HighPriorityProperties>()
-{
- COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyColor + 18, CSS_line_height_is_end_of_high_prioity_property_range);
- COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyLineHeight - 1, CSS_zoom_is_before_line_height);
- return CSSPropertyLineHeight;
-}
-
-// This method returns the first CSSPropertyId of remaining properties,
-// i.e. low priority properties. No properties depend on low priority
-// properties. So we don't need to resolve such properties quickly.
-// All low priority properties are obtained by using
-// firstCSSPropertyId<LowPriorityProperties> and
-// lastCSSPropertyId<LowPriorityProperties>.
-template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::LowPriorityProperties>()
-{
- COMPILE_ASSERT(CSSPropertyBackground == CSSPropertyLineHeight + 1, CSS_background_is_first_low_priority_property);
- return CSSPropertyBackground;
-}
-
-// This method returns the last CSSPropertyId of low priority properties.
-template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::LowPriorityProperties>()
-{
- return static_cast<CSSPropertyID>(lastCSSProperty);
-}
-
-template <StyleResolver::StyleApplicationPass pass>
-bool StyleResolver::isPropertyForPass(CSSPropertyID property)
-{
- return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
-}
-
-// This method expands the 'all' shorthand property to longhand properties
-// and applies the expanded longhand properties.
-template <StyleResolver::StyleApplicationPass pass>
-void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue)
-{
- bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue();
- unsigned startCSSProperty = firstCSSPropertyId<pass>();
- unsigned endCSSProperty = lastCSSPropertyId<pass>();
-
- for (unsigned i = startCSSProperty; i <= endCSSProperty; ++i) {
- CSSPropertyID propertyId = static_cast<CSSPropertyID>(i);
-
- // StyleBuilder does not allow any expanded shorthands.
- if (isExpandedShorthandForAll(propertyId))
- continue;
-
- // all shorthand spec says:
- // The all property is a shorthand that resets all CSS properties
- // except direction and unicode-bidi.
- // c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand
- // We skip applyProperty when a given property is unicode-bidi or
- // direction.
- if (!CSSProperty::isAffectedByAllProperty(propertyId))
- continue;
-
- CSSValue* value;
- if (!isUnsetValue) {
- value = allValue;
- } else {
- if (CSSProperty::isInheritedProperty(propertyId))
- value = cssValuePool().createInheritedValue().get();
- else
- value = cssValuePool().createExplicitInitialValue().get();
- }
- StyleBuilder::applyProperty(propertyId, state, value);
- }
-}
-
-template <StyleResolver::StyleApplicationPass pass>
-void StyleResolver::applyProperties(StyleResolverState& state, const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
-{
- state.setCurrentRule(rule);
-
- 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 == CSSPropertyAll) {
- applyAllProperty<pass>(state, current.value());
- continue;
- }
-
- if (inheritedOnly && !current.isInherited()) {
- // If the property value is explicitly inherited, we need to apply further non-inherited properties
- // as they might override the value inherited here. For this reason we don't allow declarations with
- // explicitly inherited properties to be cached.
- ASSERT(!current.value()->isInheritedValue());
- continue;
- }
-
- if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
- continue;
- if (propertyWhitelistType == PropertyWhitelistFirstLetter && !isValidFirstLetterStyleProperty(property))
- continue;
- if (!isPropertyForPass<pass>(property))
- continue;
- if (pass == HighPriorityProperties && property == CSSPropertyLineHeight)
- state.setLineHeightValue(current.value());
- else
- StyleBuilder::applyProperty(current.id(), state, current.value());
- }
-}
-
-template <StyleResolver::StyleApplicationPass pass>
-void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
-{
- if (startIndex == -1)
- return;
-
- if (state.style()->insideLink() != NotInsideLink) {
- for (int i = startIndex; i <= endIndex; ++i) {
- const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
- unsigned linkMatchType = matchedProperties.m_types.linkMatchType;
- // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
- state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
- state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
-
- applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType));
- }
- state.setApplyPropertyToRegularStyle(true);
- state.setApplyPropertyToVisitedLinkStyle(false);
- return;
- }
- for (int i = startIndex; i <= endIndex; ++i) {
- const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
- applyProperties<pass>(state, matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType));
- }
-}
-
static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
{
return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
@@ -1456,15 +1339,8 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
applyInheritedOnly = true;
}
- // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
- // high-priority properties first, i.e., those properties that other properties depend on.
- // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
- // and (4) normal important.
- state.setLineHeightValue(0);
- applyMatchedProperties<HighPriorityProperties>(state, matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
- applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
- applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
- applyMatchedProperties<HighPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+ CascadedValues cascadedValues(state, matchResult);
+ cascadedValues.applyValues(firstCSSPropertyId<HighPriorityProperties>(), lastCSSPropertyId<HighPriorityProperties>(), applyInheritedOnly);
if (UNLIKELY(isSVGForeignObjectElement(element))) {
// RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again.
@@ -1485,25 +1361,22 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc
// If our font got dirtied, go ahead and update it now.
updateFont(state);
- // Line-height is set when we are sure we decided on the font-size.
- if (state.lineHeightValue())
- StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue());
-
// Many properties depend on the font. If it changes we just apply all properties.
if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription())
applyInheritedOnly = false;
- // Now do the normal priority UA properties.
- applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
-
- // Cache the UA properties to pass them to RenderTheme in adjustRenderStyle.
- state.cacheUserAgentBorderAndBackground();
+ // This code supports -webkit-appearance, for which we are interested
+ // in whether the user has specified border or background properties.
+ // FIXME: This is a bit of a mess, we should just compare CSSValues and
+ // store a single bit for this.
+ if (elementTypeHasAppearanceFromUAStyle(*element)) {
+ CascadedValues userAgentValues(state, matchResult, true);
+ // We only actually care about border and background properties here
+ userAgentValues.applyValues(firstCSSPropertyId<LowPriorityProperties>(), lastCSSPropertyId<LowPriorityProperties>(), applyInheritedOnly);
+ state.cacheUserAgentBorderAndBackground();
+ }
- // Now do the author and user normal priority properties and all the !important properties.
- applyMatchedProperties<LowPriorityProperties>(state, matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
- applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
- applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
- applyMatchedProperties<LowPriorityProperties>(state, matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+ cascadedValues.applyValues(firstCSSPropertyId<LowPriorityProperties>(), lastCSSPropertyId<LowPriorityProperties>(), applyInheritedOnly);
loadPendingResources(state);
« no previous file with comments | « Source/core/css/resolver/StyleResolver.h ('k') | Source/core/css/resolver/StyleResolverState.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698