Skip to content

Commit

Permalink
[anchor-position] Properly implement CSSOM API classes
Browse files Browse the repository at this point in the history
This patch adds proper implementation of the CSSPositionFallbackRule
and CSSTryRule API as specified [1]:

1. It reimplements `CSSPositionFallbackRule` as a subclass of
   `CSSGroupingRule`, and `StyleRulePositionFallback` as a subclass
   of `StyleRuleGroup`.

2. It adds some code to `CSSGroupingRule.insertRule()` to make sure
   the function only adds `@try` rules into `CSSPositionFallbackRule`.

3. Since `CSSStyleRule.style.setProperty()` can add disallowed
   properties into a `@try` block [2], this patch also adds filtering
   into the style cascade to make sure when applying the style from
   a `@try` rule, only allowed properties' values are applied.

This patch also manually adds the IDL of the APIs into wpt so that we
can add idlharness test without waiting for the IDL auto roller.

[1] https://drafts.csswg.org/css-anchor-position-1/#interfaces
[2] w3c/csswg-drafts#9042

Bug: 1309178
Change-Id: Ib7700605a9968a3547fbe99197c882e8aa6caaea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4668131
Reviewed-by: Daniil Sakhapov <sakhapov@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1168271}
  • Loading branch information
xiaochengh authored and chromium-wpt-export-bot committed Jul 10, 2023
1 parent b9f2c32 commit 1379ecf
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 0 deletions.
81 changes: 81 additions & 0 deletions css/css-anchor-position/at-position-fallback-cssom.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<title>Tests the CSSOM interfaces of @position-fallback and @try rules</title>
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#interfaces">
<link rel="author" href="mailto:xiaochengh@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<div id="anchor"></div>
<div id="not-anchor"></div>
<div id="target"></div>

<script>
function createStyle(t, text) {
const style = document.createElement('style');
style.textContent = text;
t.add_cleanup(() => style.remove());
document.head.appendChild(style);
return style;
}

test(t => {
const style = createStyle(
t, '@position-fallback --pf { @try { left: anchor(right); } }');
const positionFallbackRule = style.sheet.cssRules[0];
assert_true(positionFallbackRule instanceof CSSPositionFallbackRule);
assert_equals(positionFallbackRule.name, '--pf');
assert_equals(positionFallbackRule.cssRules.length, 1);

const tryRule = positionFallbackRule.cssRules[0];
assert_true(tryRule instanceof CSSTryRule);
assert_true(tryRule.style instanceof CSSStyleDeclaration);
assert_equals(tryRule.style.length, 1);
assert_equals(tryRule.style.left, 'anchor(right)');
}, 'CSSPositionFallbackRule and CSSTryRule attribute values');

test(t => {
const style = createStyle(t, '@position-fallback --pf {}');
const positionFallbackRule = style.sheet.cssRules[0];

assert_equals(positionFallbackRule.insertRule('@try {}', 0), 0,
'@try rules can be inserted');
assert_throws_dom('HierarchyRequestError',
() => positionFallbackRule.insertRule('#target { color: red; }', 1),
'style rules cannot be inserted');
assert_throws_dom('HierarchyRequestError',
() => positionFallbackRule.insertRule('@keyframes foo {}', 1),
'other at-rules cannot be inserted');
}, 'CSSPositionFallbackRule.insertRule can insert @try rules only');


test(t => {
const style = createStyle(t, `
@position-fallback --pf { @try { top: anchor(top); } }
#anchor, #not-anchor, #target {
position: absolute; width: 100px; height: 100px; left: 0;
}
#anchor { top: 100px; anchor-name: --a; }
#not-anchor { top: 200px; anchor-name: --b; }
#target { position-fallback: --pf; anchor-default: --a; }
`);
const positionFallbackRule = style.sheet.cssRules[0];
const tryRule = positionFallbackRule.cssRules[0];

// Check the initial position fallback result
assert_equals(target.getBoundingClientRect().left, 0);
assert_equals(target.getBoundingClientRect().top, 100);

// `left` is an allowed property in `@try` and should affect position fallback.
tryRule.style.setProperty('left', 'anchor(right)');
assert_equals(target.getBoundingClientRect().left, 100);
assert_equals(target.getBoundingClientRect().top, 100);

// These properties are disallowed in `@try` rule, and hence should not affect
// position fallback.
tryRule.style.setProperty('anchor-default', '--b');
tryRule.style.setProperty('position', 'static');
assert_equals(target.getBoundingClientRect().left, 100);
assert_equals(target.getBoundingClientRect().top, 100);
}, 'CSSTryRule.style.setProperty setting allowed and disallowed properties');

</script>
37 changes: 37 additions & 0 deletions css/css-anchor-position/idlharness.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!doctype html>
<title>CSS Anchor Positioning IDL tests</title>
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#interfaces">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>
<script src="/resources/idlharness.js"></script>

<style>
@position-fallback --fallback {
@try {}
@try {}
}
</style>

<script>
'use strict';
idl_test(
['css-anchor-position'],
['cssom'],
idl_array => {
try {
self.positionFallback = document.styleSheets[0].cssRules.item(0);
self.try1 = self.positionFallback.cssRules.item(0);
self.try2 = self.positionFallback.cssRules.item(1);
} catch (e) {
// Will be surfaced when any rule is undefined below.
}

idl_array.add_objects({
CSSPositionFallbackRule: ['positionFallback'],
CSSTryRule: ['try1', 'try2'],
CSSStyleDeclaration: ['try1.style', 'try2.style'],
});
}
);
</script>
11 changes: 11 additions & 0 deletions interfaces/css-anchor-position.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Source: CSS Anchor Positioning (https://drafts.csswg.org/css-anchor-position-1/)

[Exposed=Window]
interface CSSPositionFallbackRule : CSSGroupingRule {
readonly attribute CSSOMString name;
};

[Exposed=Window]
interface CSSTryRule : CSSRule {
[SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
};

0 comments on commit 1379ecf

Please sign in to comment.