mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-26 20:26:53 +00:00
LibWeb: Parse the will-change
property
This property provides a hint to the rendering engine about properties that are likely to change in the near future, allowing for early optimizations to be applied.
This commit is contained in:
parent
0e4fb9ae73
commit
4f663ca6e7
Notes:
github-actions[bot]
2025-08-18 11:37:59 +00:00
Author: https://github.com/tcl3
Commit: 4f663ca6e7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5870
Reviewed-by: https://github.com/AtkinsSJ ✅
16 changed files with 335 additions and 2 deletions
|
@ -1911,4 +1911,46 @@ ScrollbarWidth ComputedProperties::scrollbar_width() const
|
|||
return keyword_to_scrollbar_width(value.to_keyword()).release_value();
|
||||
}
|
||||
|
||||
WillChange ComputedProperties::will_change() const
|
||||
{
|
||||
auto const& value = property(PropertyID::WillChange);
|
||||
if (value.to_keyword() == Keyword::Auto)
|
||||
return WillChange::make_auto();
|
||||
|
||||
auto to_will_change_entry = [](StyleValue const& value) -> Optional<WillChange::WillChangeEntry> {
|
||||
if (value.is_keyword()) {
|
||||
switch (value.as_keyword().keyword()) {
|
||||
case Keyword::Contents:
|
||||
return WillChange::Type::Contents;
|
||||
case Keyword::ScrollPosition:
|
||||
return WillChange::Type::ScrollPosition;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
VERIFY(value.is_custom_ident());
|
||||
auto custom_ident = value.as_custom_ident().custom_ident();
|
||||
auto property_id = property_id_from_string(custom_ident);
|
||||
if (!property_id.has_value())
|
||||
return {};
|
||||
|
||||
return property_id.release_value();
|
||||
};
|
||||
|
||||
if (value.is_value_list()) {
|
||||
auto const& value_list = value.as_value_list();
|
||||
Vector<WillChange::WillChangeEntry> will_change_entries;
|
||||
for (auto const& style_value : value_list.values()) {
|
||||
if (auto entry = to_will_change_entry(*style_value); entry.has_value())
|
||||
will_change_entries.append(*entry);
|
||||
}
|
||||
return WillChange(move(will_change_entries));
|
||||
}
|
||||
|
||||
auto will_change_entry = to_will_change_entry(value);
|
||||
if (will_change_entry.has_value())
|
||||
return WillChange({ *will_change_entry });
|
||||
return WillChange::make_auto();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -196,6 +196,8 @@ public:
|
|||
ClipRule clip_rule() const;
|
||||
float flood_opacity() const;
|
||||
|
||||
WillChange will_change() const;
|
||||
|
||||
Gfx::FontCascadeList const& computed_font_list() const
|
||||
{
|
||||
VERIFY(m_font_list);
|
||||
|
|
|
@ -87,6 +87,33 @@ struct ScrollbarColorData {
|
|||
Color track_color { Color::Transparent };
|
||||
};
|
||||
|
||||
struct WillChange {
|
||||
enum class Type : u8 {
|
||||
Contents,
|
||||
ScrollPosition,
|
||||
};
|
||||
using WillChangeEntry = Variant<Type, PropertyID>;
|
||||
|
||||
WillChange(Vector<WillChangeEntry> values)
|
||||
: m_value(move(values))
|
||||
{
|
||||
}
|
||||
|
||||
static WillChange make_auto() { return WillChange(); }
|
||||
|
||||
bool is_auto() const { return m_value.is_empty(); }
|
||||
bool has_contents() const { return m_value.contains_slow(Type::Contents); }
|
||||
bool has_scroll_position() const { return m_value.contains_slow(Type::ScrollPosition); }
|
||||
bool has_property(PropertyID property_id) const { return m_value.contains_slow(property_id); }
|
||||
|
||||
private:
|
||||
WillChange()
|
||||
{
|
||||
}
|
||||
|
||||
Vector<WillChangeEntry> m_value;
|
||||
};
|
||||
|
||||
using CursorData = Variant<NonnullRefPtr<CursorStyleValue const>, CursorPredefined>;
|
||||
|
||||
using ListStyleType = Variant<CounterStyleNameKeyword, String>;
|
||||
|
@ -231,6 +258,7 @@ public:
|
|||
};
|
||||
}
|
||||
static CSS::ScrollbarWidth scrollbar_width() { return CSS::ScrollbarWidth::Auto; }
|
||||
static WillChange will_change() { return WillChange::make_auto(); }
|
||||
};
|
||||
|
||||
enum class BackgroundSize {
|
||||
|
@ -609,6 +637,8 @@ public:
|
|||
ScrollbarColorData scrollbar_color() const { return m_inherited.scrollbar_color; }
|
||||
CSS::ScrollbarWidth scrollbar_width() const { return m_noninherited.scrollbar_width; }
|
||||
|
||||
WillChange will_change() const { return m_noninherited.will_change; }
|
||||
|
||||
NonnullOwnPtr<ComputedValues> clone_inherited_values() const
|
||||
{
|
||||
auto clone = make<ComputedValues>();
|
||||
|
@ -804,6 +834,8 @@ protected:
|
|||
Vector<CounterData, 0> counter_reset;
|
||||
Vector<CounterData, 0> counter_set;
|
||||
|
||||
WillChange will_change { InitialValues::will_change() };
|
||||
|
||||
Color flood_color { InitialValues::flood_color() };
|
||||
float flood_opacity { InitialValues::flood_opacity() };
|
||||
} m_noninherited;
|
||||
|
@ -1014,6 +1046,8 @@ public:
|
|||
void set_counter_increment(Vector<CounterData> value) { m_noninherited.counter_increment = move(value); }
|
||||
void set_counter_reset(Vector<CounterData> value) { m_noninherited.counter_reset = move(value); }
|
||||
void set_counter_set(Vector<CounterData> value) { m_noninherited.counter_set = move(value); }
|
||||
|
||||
void set_will_change(WillChange value) { m_noninherited.will_change = move(value); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -449,6 +449,7 @@
|
|||
"scale-down",
|
||||
"screen",
|
||||
"scroll",
|
||||
"scroll-position",
|
||||
"scrollbar",
|
||||
"se-resize",
|
||||
"searchfield",
|
||||
|
|
|
@ -490,6 +490,7 @@ private:
|
|||
RefPtr<StyleValue const> parse_touch_action_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_white_space_shorthand(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_white_space_trim_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_will_change_value(TokenStream<ComponentValue>&);
|
||||
|
||||
RefPtr<StyleValue const> parse_list_of_time_values(PropertyID, TokenStream<ComponentValue>&);
|
||||
|
||||
|
|
|
@ -797,6 +797,11 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
|
|||
if (auto parsed_value = parse_white_space_trim_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::WillChange:
|
||||
if (auto parsed_value = parse_will_change_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -5692,4 +5697,28 @@ RefPtr<StyleValue const> Parser::parse_white_space_shorthand(TokenStream<Compone
|
|||
return make_whitespace_shorthand(white_space_collapse, text_wrap_mode, white_space_trim);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-will-change/#will-change
|
||||
RefPtr<StyleValue const> Parser::parse_will_change_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// auto | <animateable-feature>#
|
||||
// <animateable-feature> = scroll-position | contents | <custom-ident>
|
||||
if (parse_all_as_single_keyword_value(tokens, Keyword::Auto))
|
||||
return KeywordStyleValue::create(Keyword::Auto);
|
||||
|
||||
auto parse_animateable_feature = [this](TokenStream<ComponentValue>& tokens) -> RefPtr<StyleValue const> {
|
||||
auto style_value = parse_css_value_for_property(PropertyID::WillChange, tokens);
|
||||
if (!style_value)
|
||||
return nullptr;
|
||||
|
||||
if (style_value->to_keyword() == Keyword::Auto)
|
||||
return nullptr;
|
||||
|
||||
return style_value;
|
||||
};
|
||||
|
||||
return parse_comma_separated_value_list(tokens, [&parse_animateable_feature](auto& tokens) {
|
||||
return parse_animateable_feature(tokens);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3565,6 +3565,21 @@
|
|||
"unitless-length"
|
||||
]
|
||||
},
|
||||
"will-change": {
|
||||
"affects-layout": false,
|
||||
"affects-stacking-context": true,
|
||||
"animation-type": "none",
|
||||
"inherited": false,
|
||||
"initial": "auto",
|
||||
"valid-types": [
|
||||
"custom-ident ![all,auto,contents,none,scroll-position,will-change]"
|
||||
],
|
||||
"valid-identifiers": [
|
||||
"auto",
|
||||
"scroll-position",
|
||||
"contents"
|
||||
]
|
||||
},
|
||||
"word-break": {
|
||||
"animation-type": "discrete",
|
||||
"initial": "normal",
|
||||
|
|
|
@ -1015,6 +1015,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
|
|||
computed_values.set_mix_blend_mode(computed_style.mix_blend_mode());
|
||||
computed_values.set_view_transition_name(computed_style.view_transition_name());
|
||||
computed_values.set_contain(computed_style.contain());
|
||||
computed_values.set_will_change(computed_style.will_change());
|
||||
|
||||
computed_values.set_caret_color(computed_style.caret_color(*this));
|
||||
computed_values.set_color_interpolation(computed_style.color_interpolation());
|
||||
|
|
|
@ -258,6 +258,7 @@ All properties associated with getComputedStyle(document.body):
|
|||
"view-transition-name",
|
||||
"white-space-trim",
|
||||
"width",
|
||||
"will-change",
|
||||
"x",
|
||||
"y",
|
||||
"z-index"
|
||||
|
|
|
@ -725,6 +725,8 @@ All supported properties and their default values exposed from CSSStylePropertie
|
|||
'whiteSpaceTrim': 'none'
|
||||
'white-space-trim': 'none'
|
||||
'width': '284px'
|
||||
'willChange': 'auto'
|
||||
'will-change': 'auto'
|
||||
'wordBreak': 'normal'
|
||||
'word-break': 'normal'
|
||||
'wordSpacing': 'normal'
|
||||
|
|
|
@ -256,6 +256,7 @@ vertical-align: baseline
|
|||
view-transition-name: none
|
||||
white-space-trim: none
|
||||
width: 784px
|
||||
will-change: auto
|
||||
x: 0px
|
||||
y: 0px
|
||||
z-index: auto
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 255 tests
|
||||
Found 256 tests
|
||||
|
||||
248 Pass
|
||||
249 Pass
|
||||
7 Fail
|
||||
Pass accent-color
|
||||
Pass border-collapse
|
||||
|
@ -256,6 +256,7 @@ Pass vertical-align
|
|||
Pass view-transition-name
|
||||
Pass white-space-trim
|
||||
Fail width
|
||||
Pass will-change
|
||||
Pass x
|
||||
Pass y
|
||||
Pass z-index
|
|
@ -0,0 +1,111 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 106 tests
|
||||
|
||||
106 Pass
|
||||
Pass e.style['will-change'] = "auto transform" should not set the property value
|
||||
Pass e.style['will-change'] = "auto, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "contents auto" should not set the property value
|
||||
Pass e.style['will-change'] = "contents, auto" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, default" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, none" should not set the property value
|
||||
Pass e.style['will-change'] = "initial, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, default" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, none" should not set the property value
|
||||
Pass e.style['will-change'] = "inherit, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, default" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, none" should not set the property value
|
||||
Pass e.style['will-change'] = "unset, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, default" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, none" should not set the property value
|
||||
Pass e.style['will-change'] = "revert, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, default" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, none" should not set the property value
|
||||
Pass e.style['will-change'] = "revert-layer, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, default" should not set the property value
|
||||
Pass e.style['will-change'] = "default, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "default, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "default, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "default, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "default, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "default, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "default, default" should not set the property value
|
||||
Pass e.style['will-change'] = "default, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "default, none" should not set the property value
|
||||
Pass e.style['will-change'] = "default, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, default" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, none" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, none" should not set the property value
|
||||
Pass e.style['will-change'] = "none, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "none, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "none, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "none, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "none, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "none, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "none, default" should not set the property value
|
||||
Pass e.style['will-change'] = "none, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "none, none" should not set the property value
|
||||
Pass e.style['will-change'] = "none, all" should not set the property value
|
||||
Pass e.style['will-change'] = "transform, all" should not set the property value
|
||||
Pass e.style['will-change'] = "all, transform" should not set the property value
|
||||
Pass e.style['will-change'] = "all, initial" should not set the property value
|
||||
Pass e.style['will-change'] = "all, inherit" should not set the property value
|
||||
Pass e.style['will-change'] = "all, unset" should not set the property value
|
||||
Pass e.style['will-change'] = "all, revert" should not set the property value
|
||||
Pass e.style['will-change'] = "all, revert-layer" should not set the property value
|
||||
Pass e.style['will-change'] = "all, default" should not set the property value
|
||||
Pass e.style['will-change'] = "all, will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "all, none" should not set the property value
|
||||
Pass e.style['will-change'] = "all, all" should not set the property value
|
||||
Pass e.style['will-change'] = "will-change" should not set the property value
|
||||
Pass e.style['will-change'] = "none" should not set the property value
|
||||
Pass e.style['will-change'] = "all" should not set the property value
|
|
@ -0,0 +1,14 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 9 tests
|
||||
|
||||
9 Pass
|
||||
Pass e.style['will-change'] = "auto" should set the property value
|
||||
Pass e.style['will-change'] = "scroll-position" should set the property value
|
||||
Pass e.style['will-change'] = "contents" should set the property value
|
||||
Pass e.style['will-change'] = "transform" should set the property value
|
||||
Pass e.style['will-change'] = "background-color" should set the property value
|
||||
Pass e.style['will-change'] = "scroll-position, contents" should set the property value
|
||||
Pass e.style['will-change'] = "scroll-position, transform" should set the property value
|
||||
Pass e.style['will-change'] = "contents, transform" should set the property value
|
||||
Pass e.style['will-change'] = "transform, background-color" should set the property value
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Will Change Test: parsing will-change with invalid values</title>
|
||||
<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-will-change/#propdef-will-change">
|
||||
<meta name="assert" content="will-change only supports the grammar 'auto | <animateable-feature>#'.">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<script src="../../../css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("will-change", "auto transform");
|
||||
test_invalid_value("will-change", "auto, transform");
|
||||
test_invalid_value("will-change", "contents auto");
|
||||
test_invalid_value("will-change", "contents, auto");
|
||||
|
||||
let excludedKeywords = [
|
||||
// CSS-wide keywords are excluded from <custom-ident>
|
||||
// https://drafts.csswg.org/css-values-4/#identifier-value
|
||||
"initial",
|
||||
"inherit",
|
||||
"unset",
|
||||
"revert",
|
||||
"revert-layer",
|
||||
"default",
|
||||
|
||||
// will-change additionally excludes the following from <custom-ident>
|
||||
"will-change",
|
||||
"none",
|
||||
"all",
|
||||
];
|
||||
|
||||
for (let keyword of excludedKeywords) {
|
||||
test_invalid_value("will-change", `transform, ${keyword}`);
|
||||
test_invalid_value("will-change", `${keyword}, transform`);
|
||||
for (let k of excludedKeywords) {
|
||||
test_invalid_value("will-change", `${keyword}, ${k}`);
|
||||
}
|
||||
}
|
||||
|
||||
test_invalid_value("will-change", "will-change");
|
||||
test_invalid_value("will-change", "none");
|
||||
test_invalid_value("will-change", "all");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Will Change Test: parsing will-change with valid values</title>
|
||||
<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-will-change/#propdef-will-change">
|
||||
<meta name="assert" content="will-change supports the full grammar 'auto | <animateable-feature>#'.">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<script src="../../../css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("will-change", "auto");
|
||||
|
||||
// <animateable-feature> = scroll-position | contents | <custom-ident>
|
||||
test_valid_value("will-change", "scroll-position");
|
||||
test_valid_value("will-change", "contents");
|
||||
test_valid_value("will-change", "transform");
|
||||
test_valid_value("will-change", "background-color");
|
||||
|
||||
test_valid_value("will-change", "scroll-position, contents");
|
||||
test_valid_value("will-change", "scroll-position, transform");
|
||||
test_valid_value("will-change", "contents, transform");
|
||||
test_valid_value("will-change", "transform, background-color");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue