fune/testing/web-platform/tests/css/css-properties-values-api/get-computed-style-enumeration.html
Frederic Wang 138e00de8e Bug 1855629 - Handling of custom properties when enumerating getComputedStyle(). r=emilio
After bug 1840478, non-inherited custom properties using their initial
values are represented as absent from `ComputedCustomProperties` in
order to save memory. Wherever the values of such properties are
requested, it is necessary to fallback to any registered initial value.
However, this makes difficult to properly enumerate custom properties
for exposure via the `CSSStyleDeclaration.item()` API and indeed our
current implementation only exposes the properties actually present in
`ComputedCustomProperties`.

Additionally, such a representation conflicts with pre-existent
representation of guaranteed-invalid values as absent values, causing
some issues e.g. bad handling of invalid at computed-value time [1] [2].

This patch changes `ComputedCustomProperties` so that registered initial
values are always stored in the `non_inherited` map, immediately fixing
the issue with `CSSStyleDeclaration.item()` and preparing follow-up
work on guaranteed-invalid values.

To avoid excessive increase of memory usage, the `non_inherited` map
becomes ref-counted. The associated Stylist contains an up-to-date
ComputedCustomProperties with registered custom properties that have
initial values, and the `non_inherited` map can generally just be
shallow-cloned from it.

A new test `get-computed-style-enumeration.html` is added to make sure
custom properties are correctly exposed when enumerating
`CSSStyleDeclaration` as a list. A similar but more restricted version
already exists: `cssstyledeclaration-registered-custom-properties.html`.
Two test cases are also added to `determine-registration.html` in order
to cover some issue previously detected during the review of
`get_custom_property_initial_values`.

[1] https://drafts.csswg.org/css-variables-2/#invalid-at-computed-value-time
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=1855946

Differential Revision: https://phabricator.services.mozilla.com/D189999
2023-10-06 12:03:16 +00:00

96 lines
3.4 KiB
HTML

<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@property --inherited-length-1 {
syntax: "<length>";
inherits: true;
initial-value: 10px;
}
@property --inherited-length-2 {
syntax: "<length>";
inherits: true;
initial-value: 20px;
}
@property --non-inherited-length-1 {
syntax: "<length>";
inherits: false;
initial-value: 30px;
}
@property --non-inherited-length-2 {
syntax: "<length>";
inherits: false;
initial-value: 40px;
}
@property --inherited-no-initial-value-1 {
syntax: "*";
inherits: true;
}
@property --inherited-no-initial-value-2 {
syntax: "*";
inherits: true;
}
@property --inherited-no-initial-value-3 {
syntax: "*";
inherits: true;
}
@property --non-inherited-no-initial-value-1 {
syntax: "*";
inherits: false;
}
@property --non-inherited-no-initial-value-2 {
syntax: "*";
inherits: false;
}
@property --non-inherited-no-initial-value-3 {
syntax: "*";
inherits: false;
}
#parent {
--inherited-no-initial-value-2: parent-A;
--non-inherited-no-initial-value-2: parent-B;
--non-registered-property-2: parent-C;
}
#node {
--inherited-length-1: 50px;
--non-inherited-length-1: 60px;
--inherited-no-initial-value-1: child-A;
--non-inherited-no-initial-value-1: child-B;
--non-registered-property-1: child-C;
}
</style>
<div id="parent"><div id="node"></div></div>
<script>
let style = window.getComputedStyle(document.getElementById("node"));
let properties = new Map();
Array.from(style).filter(name => name.startsWith("--"))
.forEach(name => properties.set(name, style.getPropertyValue(name)));
test(() => {
assert_equals(properties.get("--inherited-length-1"), "50px");
assert_equals(properties.get("--non-inherited-length-1"), "60px");
assert_equals(properties.get("--inherited-no-initial-value-1"), "child-A");
assert_equals(properties.get("--non-inherited-no-initial-value-1"), "child-B");
assert_equals(properties.get("--non-registered-property-1"), "child-C");
}, "Custom properties specified on the node exposed when enumerating computed style.");
test(() => {
assert_equals(properties.get("--inherited-no-initial-value-2"), "parent-A");
assert_equals(properties.get("--non-registered-property-2"), "parent-C");
}, "Inherited custom properties specified on the parent exposed when enumerating computed style.");
test(() => {
assert_equals(properties.get("--inherited-length-2"), "20px");
assert_equals(properties.get("--non-inherited-length-2"), "40px");
}, "Unspecified properties with initial values exposed when enumerating computed style.");
test(() => {
assert_false(properties.has("--non-inherited-no-initial-value-2"));
}, "Non-inherited custom properties specified on the parent without initial values not exposed when enumerating computed style.");
test(() => {
assert_false(properties.has("--inherited-no-initial-value-3"), "inherited");
assert_false(properties.has("--non-inherited-no-initial-value-3"), "non-inherited");
}, "Unspecified properties without initial values not exposed when enumerating computed style.");
</script>