Bug 940842 - 1/3 - Add will-change CSS property - r=dbaron

The current spec draft is at:
http://tabatkins.github.io/specs/css-will-change/

This CSS property is disabled by default and can be enabled by toggling:
  layout.css.will-change.enabled
This commit is contained in:
Benoit Girard ext:(%20and%20Benoit%20Jacob%20%3Cbjacob%40mozilla.com%3E) 2013-11-22 11:48:27 -05:00
parent c578705bd5
commit 297226674b
11 changed files with 176 additions and 2 deletions

View File

@ -673,6 +673,7 @@ protected:
size_t aNumProperties);
bool ParseTransition();
bool ParseAnimation();
bool ParseWillChange();
bool ParsePaint(nsCSSProperty aPropID);
bool ParseDasharray();
@ -7829,6 +7830,8 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
return ParseSize();
case eCSSProperty_text_decoration:
return ParseTextDecoration();
case eCSSProperty_will_change:
return ParseWillChange();
case eCSSProperty_transform:
return ParseTransform(false);
case eCSSProperty__moz_transform:
@ -11453,6 +11456,61 @@ static bool GetFunctionParseInformation(nsCSSKeyword aToken,
return true;
}
bool CSSParserImpl::ParseWillChange()
{
nsCSSValue listValue;
nsCSSValueList* currentListValue = listValue.SetListValue();
bool first = true;
for (;;) {
const uint32_t variantMask = VARIANT_IDENTIFIER |
VARIANT_INHERIT |
VARIANT_NONE |
VARIANT_ALL |
VARIANT_AUTO;
nsCSSValue value;
if (!ParseVariant(value, variantMask, nullptr)) {
return false;
}
if (value.GetUnit() == eCSSUnit_None ||
value.GetUnit() == eCSSUnit_All)
{
return false;
}
if (value.GetUnit() != eCSSUnit_Ident) {
if (first) {
AppendValue(eCSSProperty_will_change, value);
return true;
} else {
return false;
}
}
nsString str;
value.GetStringValue(str);
if (str.LowerCaseEqualsLiteral("default")) {
return false;
}
currentListValue->mValue = value;
if (CheckEndProperty()) {
break;
}
if (!ExpectSymbol(',', true)) {
REPORT_UNEXPECTED_TOKEN(PEExpectedComma);
return false;
}
currentListValue->mNext = new nsCSSValueList;
currentListValue = currentListValue->mNext;
first = false;
}
AppendValue(eCSSProperty_will_change, listValue);
return true;
}
/* Reads a single transform function from the tokenizer stream, reporting an
* error if something goes wrong.
*/

View File

@ -39,12 +39,12 @@
whether the use is for internal use such as eCSSProperty_* or
nsRuleData::ValueFor* or external use such as exposing DOM properties.
-. 'flags', a bitfield containing CSS_PROPERTY_* flags.
-. 'pref' is the name of a pref that controls whether the property
is enabled. The property is enabled if 'pref' is an empty string,
or if the boolean property whose name is 'pref' is set to true.
-. 'flags', a bitfield containing CSS_PROPERTY_* flags.
-. 'parsevariant', to be passed to ParseVariant in the parser.
-. 'kwtable', which is either nullptr or the name of the appropriate
@ -3752,6 +3752,18 @@ CSS_PROP_SVGRESET(
offsetof(nsStyleSVGReset, mVectorEffect),
eStyleAnimType_EnumU8)
CSS_PROP_DISPLAY(
will-change,
will_change,
WillChange,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
"layout.css.will-change.enabled",
0,
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
// The shorthands below are essentially aliases, but they require different
// parsing rules, and are therefore implemented as shorthands.
CSS_PROP_SHORTHAND(

View File

@ -3699,6 +3699,28 @@ nsComputedDOMStyle::DoGetClip()
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetWillChange()
{
const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
if (willChange.IsEmpty()) {
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
val->SetIdent(eCSSKeyword_auto);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (size_t i = 0; i < willChange.Length(); i++) {
const nsString& willChangeIdentifier = willChange[i];
nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
valueList->AppendCSSValue(property);
property->SetString(willChangeIdentifier);
}
return valueList;
}
CSSValue*
nsComputedDOMStyle::DoGetOverflow()
{

View File

@ -392,6 +392,7 @@ private:
mozilla::dom::CSSValue* DoGetPosition();
mozilla::dom::CSSValue* DoGetClip();
mozilla::dom::CSSValue* DoGetImageOrientation();
mozilla::dom::CSSValue* DoGetWillChange();
mozilla::dom::CSSValue* DoGetOverflow();
mozilla::dom::CSSValue* DoGetOverflowX();
mozilla::dom::CSSValue* DoGetOverflowY();

View File

@ -206,6 +206,7 @@ COMPUTED_STYLE_PROP(visibility, Visibility)
COMPUTED_STYLE_PROP(white_space, WhiteSpace)
// COMPUTED_STYLE_PROP(widows, Widows)
COMPUTED_STYLE_PROP(width, Width)
COMPUTED_STYLE_PROP(will_change, WillChange)
COMPUTED_STYLE_PROP(word_break, WordBreak)
COMPUTED_STYLE_PROP(word_spacing, WordSpacing)
COMPUTED_STYLE_PROP(word_wrap, WordWrap)

View File

@ -5457,6 +5457,54 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
}
/* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
switch (willChangeValue->GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_List:
case eCSSUnit_ListDep: {
display->mWillChange.Clear();
display->mWillChangeBitField = 0;
for (const nsCSSValueList* item = willChangeValue->GetListValue();
item; item = item->mNext)
{
if (item->mValue.UnitHasStringValue()) {
nsAutoString buffer;
item->mValue.GetStringValue(buffer);
if (buffer.EqualsLiteral("transform")) {
display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
}
if (buffer.EqualsLiteral("opacity")) {
display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
}
if (buffer.EqualsLiteral("scroll-position")) {
display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
}
display->mWillChange.AppendElement(buffer);
}
}
break;
}
case eCSSUnit_Inherit:
display->mWillChange = parentDisplay->mWillChange;
display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
canStoreInRuleTree = false;
break;
case eCSSUnit_Initial:
case eCSSUnit_Unset:
case eCSSUnit_Auto:
display->mWillChange.Clear();
display->mWillChangeBitField = 0;
break;
default:
MOZ_ASSERT(false, "unrecognized will-change unit");
}
/* Convert -moz-transform-origin. */
const nsCSSValue* transformOriginValue =
aRuleData->ValueForTransformOrigin();

View File

@ -211,6 +211,11 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_COLOR_CONTEXT_FILL -7
#define NS_COLOR_CONTEXT_STROKE -8
// See nsStyleDisplay
#define NS_STYLE_WILL_CHANGE_TRANSFORM (1<<0)
#define NS_STYLE_WILL_CHANGE_SCROLL (1<<1)
#define NS_STYLE_WILL_CHANGE_OPACITY (1<<2)
// See nsStyleDisplay
#define NS_STYLE_ANIMATION_DIRECTION_NORMAL 0
#define NS_STYLE_ANIMATION_DIRECTION_REVERSE 1

View File

@ -2308,6 +2308,7 @@ nsAnimation::SetInitialValues()
}
nsStyleDisplay::nsStyleDisplay()
: mWillChangeBitField(0)
{
MOZ_COUNT_CTOR(nsStyleDisplay);
mAppearance = NS_THEME_NONE;
@ -2382,6 +2383,8 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
, mClipFlags(aSource.mClipFlags)
, mOrient(aSource.mOrient)
, mMixBlendMode(aSource.mMixBlendMode)
, mWillChangeBitField(aSource.mWillChangeBitField)
, mWillChange(aSource.mWillChange)
, mTouchAction(aSource.mTouchAction)
, mBackfaceVisibility(aSource.mBackfaceVisibility)
, mTransformStyle(aSource.mTransformStyle)
@ -2509,6 +2512,10 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
}
if (mWillChangeBitField != aOther.mWillChangeBitField) {
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
}
// Note: Our current behavior for handling changes to the
// transition-duration, transition-delay, and transition-timing-function
// properties is to do nothing. In other words, the transition

View File

@ -1794,6 +1794,12 @@ struct nsStyleDisplay {
uint8_t mClipFlags; // [reset] see nsStyleConsts.h
uint8_t mOrient; // [reset] see nsStyleConsts.h
uint8_t mMixBlendMode; // [reset] see nsStyleConsts.h
uint8_t mWillChangeBitField; // [reset] see nsStyleConsts.h. Stores a bitfield
// representation of the property that
// are frequently queried. This should match
// mWillChange
nsAutoTArray<nsString, 1> mWillChange;
uint8_t mTouchAction; // [reset] see nsStyleConsts.h
// mSpecifiedTransform is the list of transform functions as

View File

@ -4884,6 +4884,17 @@ if (SpecialPowers.getBoolPref("layout.css.background-blend-mode.enabled")) {
};
}
if (SpecialPowers.getBoolPref("layout.css.will-change.enabled")) {
gCSSProperties["will-change"] = {
domProp: "willChange",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "auto" ],
other_values: [ "scroll-position", "contents", "transform", "opacity", "scroll-position, transform", "transform, opacity", "contents, transform", "property-that-doesnt-exist-yet" ],
invalid_values: [ "none", "all", "default", "auto, scroll-position", "scroll-position, auto", "transform scroll-position", ",", "trailing," ]
};
}
if (SpecialPowers.getBoolPref("layout.css.unset-value.enabled")) {
gCSSProperties["animation-direction"].invalid_values.push("normal, unset");
gCSSProperties["animation-name"].invalid_values.push("bounce, unset", "unset, bounce");

View File

@ -1763,6 +1763,9 @@ pref("layout.css.sticky.enabled", false);
pref("layout.css.sticky.enabled", true);
#endif
// Is support for CSS "will-change" enabled?
pref("layout.css.will-change.enabled", false);
// Is support for CSS "text-align: true X" enabled?
pref("layout.css.text-align-true-value.enabled", false);