Commit 57ec1ec1 authored by tasak@google.com's avatar tasak@google.com

Implemented applyPropertyAll for applying all shorthand property.

applyPropertyAll expands all shorthand property to longhand properties,
and apply each longhand property according to all's value (e.g. if
all's value is initial, initial).

Spec: http://dev.w3.org/csswg/css-cascade/#all-shorthand

BUG=172051
TEST=fast/css/all-shorthand.html

Review URL: https://codereview.chromium.org/339163002

git-svn-id: svn://svn.chromium.org/blink/trunk@176396 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent c579b246
<!DOCTYPE html> <!DOCTYPE html>
<style> <style>
#target1 { color: red; background-color: currentColor; } #target1 { display: initial; color: green; background: initial; }
#target1 { color: green; }
#parent { color: green; } #parent { color: green; }
#target2 { color: red; background-color: currentColor; } #target2 { display: inherit; color: inherit; background: inherit; }
#target3 { color: green !important; } #target3 { display: initial; color: green; background: initial; }
#target4 { color: red !important; } #target4 { display: initial; color: initial; background: initial; }
#target4 { background-color: red; }
#target5 { background-color: red; } #target5 { display: initial; color: green; background: initial; }
#target5 { color: green !important; }
#target6 { color: red !important; } #target6 { display: initial; color: initial; background: initial; }
#target7 { direction: rtl; } #target7 { display: initial; direction: rtl; }
#target8 { direction: rtl !important; } #target8 { display: initial; direction: rtl; }
#parent9 { color: green; } #parent9 { color: green; }
#target9 { display: initial; color: inherit; }
</style> </style>
<div id='target1'>green color, green background-color</div> <div id='target1'>green color, no background-color</div>
<div id='parent'> <div id='parent'>
<div id='target2'>red color, red background-color</div> <div id='target2'>green color, no background-color</div>
</div> </div>
<div id='target3'>green color</div> <div id='target3'>green color</div>
<div id='target4'>red color, red background-color</div> <div id='target4'>not red color, no background-color</div>
<div id='target5'>green color, red background-color</div> <div id='target5'>green color, no background-color</div>
<div id='target6'>red color</div> <div id='target6'>not red color</div>
<div id='target7'>direction is rtl</div> <div id='target7'>direction is rtl</div>
......
...@@ -34,21 +34,19 @@ ...@@ -34,21 +34,19 @@
#target9 { all: unset; } #target9 { all: unset; }
</style> </style>
<!-- Test for crbug.com/172051: all shorthand property --> <!-- Test for crbug.com/172051: all shorthand property -->
<!-- The following tests describes current behavior, --> <div id='target1'>green color, no background-color</div>
<!-- i.e. before implementing all. -->
<div id='target1'>green color, green background-color</div>
<div id='parent'> <div id='parent'>
<div id='target2'>red color, red background-color</div> <div id='target2'>green color, no background-color</div>
</div> </div>
<div id='target3'>green color</div> <div id='target3'>green color</div>
<div id='target4'>red color, red background-color</div> <div id='target4'>not red color, no background-color</div>
<div id='target5'>green color, red background-color</div> <div id='target5'>green color, no background-color</div>
<div id='target6'>red color</div> <div id='target6'>not red color</div>
<div id='target7'>direction is rtl</div> <div id='target7'>direction is rtl</div>
......
...@@ -85,6 +85,8 @@ unsigned indexOfShorthandForLonghand(CSSPropertyID, const Vector<StylePropertySh ...@@ -85,6 +85,8 @@ unsigned indexOfShorthandForLonghand(CSSPropertyID, const Vector<StylePropertySh
bool isExpandedShorthand(CSSPropertyID); bool isExpandedShorthand(CSSPropertyID);
bool isExpandedShorthandForAll(CSSPropertyID);
} // namespace WebCore } // namespace WebCore
#endif // StylePropertyShorthand_h #endif // StylePropertyShorthand_h
...@@ -684,4 +684,18 @@ bool CSSProperty::isInheritedProperty(CSSPropertyID propertyID) ...@@ -684,4 +684,18 @@ bool CSSProperty::isInheritedProperty(CSSPropertyID propertyID)
return false; return false;
} }
bool CSSProperty::isAffectedByAllProperty(CSSPropertyID propertyID)
{
if (propertyID == CSSPropertyAll)
return false;
// all shorthand spec says:
// The all property is a shorthand that resets all CSS properties except
// direction and unicode-bidi. It only accepts the CSS-wide keywords.
// c.f. http://dev.w3.org/csswg/css-cascade/#all-shorthand
// So CSSPropertyUnicodeBidi and CSSPropertyDirection are not
// affected by all property.
return propertyID != CSSPropertyUnicodeBidi && propertyID != CSSPropertyDirection;
}
} // namespace WebCore } // namespace WebCore
...@@ -79,6 +79,7 @@ public: ...@@ -79,6 +79,7 @@ public:
static CSSPropertyID resolveDirectionAwareProperty(CSSPropertyID, TextDirection, WritingMode); static CSSPropertyID resolveDirectionAwareProperty(CSSPropertyID, TextDirection, WritingMode);
static bool isInheritedProperty(CSSPropertyID); static bool isInheritedProperty(CSSPropertyID);
static bool isAffectedByAllProperty(CSSPropertyID);
const StylePropertyMetadata& metadata() const { return m_metadata; } const StylePropertyMetadata& metadata() const { return m_metadata; }
......
...@@ -113,6 +113,22 @@ bool isExpandedShorthand(CSSPropertyID id) ...@@ -113,6 +113,22 @@ bool isExpandedShorthand(CSSPropertyID id)
return shorthandForProperty(id).length(); return shorthandForProperty(id).length();
} }
bool isExpandedShorthandForAll(CSSPropertyID propertyId)
{
// FIXME: isExpandedShorthand says "font" is not an expanded shorthand,
// but font is expanded to font-family, font-size, and so on.
// StylePropertySerializer::asText should not generate css text like
// "font: initial; font-family: initial;...". To avoid this, we need to
// treat "font" as an expanded shorthand.
// And while applying "all" property, we cannot apply "font" property
// directly. This causes ASSERT crash, because StyleBuilder assume that
// all given properties are not expanded shorthands.
// "marker" has the same issue.
if (propertyId == CSSPropertyMarker || propertyId == CSSPropertyFont)
return true;
return shorthandForProperty(propertyId).length();
}
unsigned indexOfShorthandForLonghand(CSSPropertyID shorthandID, const Vector<StylePropertyShorthand, 4>& shorthands) unsigned indexOfShorthandForLonghand(CSSPropertyID shorthandID, const Vector<StylePropertyShorthand, 4>& shorthands)
{ {
for (unsigned i = 0; i < shorthands.size(); ++i) { for (unsigned i = 0; i < shorthands.size(); ++i) {
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "core/css/CSSSelector.h" #include "core/css/CSSSelector.h"
#include "core/css/CSSStyleRule.h" #include "core/css/CSSStyleRule.h"
#include "core/css/CSSValueList.h" #include "core/css/CSSValueList.h"
#include "core/css/CSSValuePool.h"
#include "core/css/ElementRuleCollector.h" #include "core/css/ElementRuleCollector.h"
#include "core/css/FontFace.h" #include "core/css/FontFace.h"
#include "core/css/MediaQueryEvaluator.h" #include "core/css/MediaQueryEvaluator.h"
...@@ -1230,27 +1231,111 @@ static inline bool isValidFirstLetterStyleProperty(CSSPropertyID id) ...@@ -1230,27 +1231,111 @@ 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 properties which generate
// animations. All animation properties are obtained by using
// firstCSSPropertyId<AnimationProperties> and
// lastCSSPropertyId<AnimationProperties>.
// c.f. //src/third_party/WebKit/Source/core/css/CSSPropertyNames.in.
template<> CSSPropertyID StyleResolver::firstCSSPropertyId<StyleResolver::AnimationProperties>()
{
COMPILE_ASSERT(firstCSSProperty == CSSPropertyDisplay, CSS_first_animation_property_should_be_first_property);
return CSSPropertyDisplay;
}
// This method returns the first CSSPropertyId of properties which generate
// animations.
template<> CSSPropertyID StyleResolver::lastCSSPropertyId<StyleResolver::AnimationProperties>()
{
COMPILE_ASSERT(CSSPropertyTransitionTimingFunction == CSSPropertyColor - 1, CSS_transition_timing_is_last_animation_property);
return CSSPropertyTransitionTimingFunction;
}
// 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(CSSPropertyTransitionTimingFunction + 1 == CSSPropertyColor, 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 + 17, 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> template <StyleResolver::StyleApplicationPass pass>
bool StyleResolver::isPropertyForPass(CSSPropertyID property) bool StyleResolver::isPropertyForPass(CSSPropertyID property)
{ {
const CSSPropertyID firstAnimationProperty = CSSPropertyDisplay; return firstCSSPropertyId<pass>() <= property && property <= lastCSSPropertyId<pass>();
const CSSPropertyID lastAnimationProperty = CSSPropertyTransitionTimingFunction; }
COMPILE_ASSERT(firstCSSProperty == firstAnimationProperty, CSS_first_animation_property_should_be_first_property);
const CSSPropertyID firstHighPriorityProperty = CSSPropertyColor; // This method expands all shorthand property to longhand properties
const CSSPropertyID lastHighPriorityProperty = CSSPropertyLineHeight; // considering StyleApplicationPass, and apply each expanded longhand property.
COMPILE_ASSERT(lastAnimationProperty + 1 == firstHighPriorityProperty, CSS_color_is_first_high_priority_property); // For example, if StyleApplicationPass is AnimationProperties, all shorthand
COMPILE_ASSERT(CSSPropertyLineHeight == firstHighPriorityProperty + 17, CSS_line_height_is_end_of_high_prioity_property_range); // is expaneded to display, -webkit-animation, -webkit-animation-delay, ...,
COMPILE_ASSERT(CSSPropertyZoom == lastHighPriorityProperty - 1, CSS_zoom_is_before_line_height); // transition-timing-function. So each property's value will be applied
switch (pass) { // according to all's value (initial, inherit or unset).
case AnimationProperties: template <StyleResolver::StyleApplicationPass pass>
return property >= firstAnimationProperty && property <= lastAnimationProperty; void StyleResolver::applyAllProperty(StyleResolverState& state, CSSValue* allValue)
case HighPriorityProperties: {
return property >= firstHighPriorityProperty && property <= lastHighPriorityProperty; bool isUnsetValue = !allValue->isInitialValue() && !allValue->isInheritedValue();
case LowPriorityProperties: unsigned startCSSProperty = firstCSSPropertyId<pass>();
return property > lastHighPriorityProperty; 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);
} }
ASSERT_NOT_REACHED();
return false;
} }
template <StyleResolver::StyleApplicationPass pass> template <StyleResolver::StyleApplicationPass pass>
...@@ -1263,6 +1348,13 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper ...@@ -1263,6 +1348,13 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper
StylePropertySet::PropertyReference current = properties->propertyAt(i); StylePropertySet::PropertyReference current = properties->propertyAt(i);
if (isImportant != current.isImportant()) if (isImportant != current.isImportant())
continue; continue;
CSSPropertyID property = current.id();
if (property == CSSPropertyAll) {
applyAllProperty<pass>(state, current.value());
continue;
}
if (inheritedOnly && !current.isInherited()) { if (inheritedOnly && !current.isInherited()) {
// If the property value is explicitly inherited, we need to apply further non-inherited properties // 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 // as they might override the value inherited here. For this reason we don't allow declarations with
...@@ -1270,7 +1362,6 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper ...@@ -1270,7 +1362,6 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper
ASSERT(!current.value()->isInheritedValue()); ASSERT(!current.value()->isInheritedValue());
continue; continue;
} }
CSSPropertyID property = current.id();
if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property)) if (propertyWhitelistType == PropertyWhitelistCue && !isValidCueStyleProperty(property))
continue; continue;
......
...@@ -263,6 +263,10 @@ private: ...@@ -263,6 +263,10 @@ private:
LowPriorityProperties LowPriorityProperties
}; };
template <StyleResolver::StyleApplicationPass pass> template <StyleResolver::StyleApplicationPass pass>
static inline CSSPropertyID firstCSSPropertyId();
template <StyleResolver::StyleApplicationPass pass>
static inline CSSPropertyID lastCSSPropertyId();
template <StyleResolver::StyleApplicationPass pass>
static inline bool isPropertyForPass(CSSPropertyID); static inline bool isPropertyForPass(CSSPropertyID);
template <StyleApplicationPass pass> template <StyleApplicationPass pass>
void applyMatchedProperties(StyleResolverState&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly); void applyMatchedProperties(StyleResolverState&, const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly);
...@@ -270,6 +274,9 @@ private: ...@@ -270,6 +274,9 @@ private:
void applyProperties(StyleResolverState&, const StylePropertySet* properties, StyleRule*, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone); void applyProperties(StyleResolverState&, const StylePropertySet* properties, StyleRule*, bool isImportant, bool inheritedOnly, PropertyWhitelistType = PropertyWhitelistNone);
template <StyleApplicationPass pass> template <StyleApplicationPass pass>
void applyAnimatedProperties(StyleResolverState&, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >&); void applyAnimatedProperties(StyleResolverState&, const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >&);
template <StyleResolver::StyleApplicationPass pass>
void applyAllProperty(StyleResolverState&, CSSValue*);
void matchPageRules(MatchResult&, RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName); void matchPageRules(MatchResult&, RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName);
void matchPageRulesForList(WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >& matchedRules, const WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >&, bool isLeftPage, bool isFirstPage, const String& pageName); void matchPageRulesForList(WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >& matchedRules, const WillBeHeapVector<RawPtrWillBeMember<StyleRulePage> >&, bool isLeftPage, bool isFirstPage, const String& pageName);
void collectViewportRules(); void collectViewportRules();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment