Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[scroll-animations] Integrate @scroll-timeline with animations
Until now it was possible to parse @scroll-timeline rules, but they did not actually do anything. This CL performs the necessary integration into StyleEngine and CSSAnimations (partially) to make something happen. The applicable StyleRuleScrollTimeline objects are maintained on StyleEngine. When calculating the animation update, we now take the animation-timeline property into account, and look for a rule on StyleEngine corresponding to the specified timeline name. This rule (if found) then causes a new ScrollTimeline to be created. This is by no means a fully functional implementation, but it's a start. The most notable omission is updating timelines, which is currently not possible (crbug.com/1097053). Other omissions, flaws, or postponed work are either tracked as bugs (with TODOs that reference them) or as failing expectations. This ensures that we don't miss anything before shipping. Bug:1074052 Change-Id: I04e75be1dc970ed2f542e60457f8db25bbb0fe7a
- Loading branch information
1 parent
e2ebd58
commit efdf6d4
Showing
9 changed files
with
750 additions
and
0 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
scroll-animations/css/at-scroll-timeline-before-phase.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule"> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#phase-algorithm"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/web-animations/testcommon.js"></script> | ||
<style> | ||
#scroller { | ||
overflow: scroll; | ||
width: 100px; | ||
height: 100px; | ||
} | ||
#contents { | ||
height: 200px; | ||
} | ||
@keyframes expand { | ||
from { width: 100px; } | ||
to { width: 200px; } | ||
} | ||
#element { | ||
width: 0px; | ||
} | ||
/* Ensure stable expectations if feature is not supported */ | ||
@supports not (animation-timeline:foo) { | ||
#element { animation-play-state: paused; } | ||
} | ||
</style> | ||
<div id=scroller> | ||
<div id=contents></div> | ||
</div> | ||
<div id=container></div> | ||
<script> | ||
promise_test(async (t) => { | ||
try { | ||
// Make sure scroller has a layout box. | ||
await waitForNextFrame(); | ||
|
||
container.innerHTML = ` | ||
<div id=element></div> | ||
<style> | ||
@scroll-timeline timeline { | ||
source: selector(#scroller); | ||
time-range: 10s; | ||
start: 50px; | ||
end: 100px; | ||
} | ||
#element { | ||
animation: expand 10s linear; | ||
animation-timeline: timeline; | ||
} | ||
</style> | ||
`; | ||
// Animation should not apply in before phase. | ||
assert_equals(getComputedStyle(element).width, '0px'); | ||
await waitForNextFrame(); | ||
// Animation should still not apply. | ||
assert_equals(getComputedStyle(element).width, '0px'); | ||
} finally { | ||
container.innerHTML = ''; | ||
} | ||
}, 'Animation does not apply when timeline phase is before'); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/web-animations/testcommon.js"></script> | ||
<style> | ||
#scroller { | ||
overflow: scroll; | ||
width: 100px; | ||
height: 100px; | ||
} | ||
#contents { | ||
height: 200px; | ||
} | ||
@keyframes expand { | ||
from { width: 100px; } | ||
to { width: 200px; } | ||
} | ||
@scroll-timeline timeline { | ||
source: selector(#scroller); | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
@scroll-timeline timeline { | ||
source: selector(#scroller); | ||
time-range: 1s; | ||
start: 0px; | ||
end: 50px; | ||
} | ||
#element { | ||
animation: expand 10s linear; | ||
animation-timeline: timeline; | ||
} | ||
/* Ensure stable expectations if feature is not supported */ | ||
@supports not (animation-timeline:foo) { | ||
#element { animation-play-state: paused; } | ||
} | ||
</style> | ||
<div id=scroller> | ||
<div id=contents></div> | ||
</div> | ||
<div id=element></div> | ||
<script> | ||
promise_test(async (t) => { | ||
scroller.scrollTop = 25; | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element).width, '105px'); | ||
}, 'Latest @scroll-timeline rule wins'); | ||
</script> |
59 changes: 59 additions & 0 deletions
59
scroll-animations/css/at-scroll-timeline-inactive-phase.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule"> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#phase-algorithm"> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/web-animations/testcommon.js"></script> | ||
<style> | ||
#scroller { | ||
overflow: scroll; | ||
width: 100px; | ||
height: 100px; | ||
} | ||
#contents { | ||
height: 200px; | ||
} | ||
@keyframes expand { | ||
from { width: 100px; } | ||
to { width: 200px; } | ||
} | ||
#element { | ||
width: 0px; | ||
animation: expand 10s linear paused; | ||
animation-timeline: timeline; | ||
} | ||
</style> | ||
<div id="container"></div> | ||
<div id=element></div> | ||
<script> | ||
|
||
promise_test(async (t) => { | ||
try { | ||
container.innerHTML = ` | ||
<div id=scroller> | ||
<div id=contents></div> | ||
</div> | ||
<style> | ||
@scroll-timeline timeline { | ||
source: selector(#scroller); | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
</style> | ||
`; | ||
|
||
// The source has no layout box at the time the scroll timeline is created. | ||
assert_equals(getComputedStyle(element).width, '0px'); | ||
scroller.offsetTop; // Ensure a layout box for the scroller. | ||
// Wait for an update to the timeline state: | ||
await waitForNextFrame(); | ||
// The timeline should now be active, and the animation should apply: | ||
assert_equals(getComputedStyle(element).width, '100px'); | ||
} finally { | ||
container.innerHTML = ''; | ||
} | ||
}, 'Animation does not apply when timeline is initially inactive'); | ||
|
||
</script> |
129 changes: 129 additions & 0 deletions
129
scroll-animations/css/at-scroll-timeline-orientation.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule"> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#descdef-scroll-timeline-orientation"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/web-animations/testcommon.js"></script> | ||
<style> | ||
#scroller { | ||
overflow: scroll; | ||
width: 100px; | ||
height: 100px; | ||
} | ||
#contents { | ||
height: 300px; | ||
width: 300px; | ||
} | ||
@keyframes expand { | ||
from { width: 100px; } | ||
to { width: 200px; } | ||
} | ||
@scroll-timeline timeline_auto { | ||
source: selector(#scroller); | ||
orientation: auto; | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
@scroll-timeline timeline_vertical { | ||
source: selector(#scroller); | ||
orientation: vertical; | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
@scroll-timeline timeline_horizontal { | ||
source: selector(#scroller); | ||
orientation: horizontal; | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
@scroll-timeline timeline_block { | ||
source: selector(#scroller); | ||
orientation: block; | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
@scroll-timeline timeline_inline { | ||
source: selector(#scroller); | ||
orientation: inline; | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
#container > div { | ||
width: 0px; | ||
animation: expand 10s linear; | ||
} | ||
/* Ensure stable expectations if feature is not supported */ | ||
@supports not (animation-timeline:foo) { | ||
#container > div { animation-play-state: paused; } | ||
} | ||
.horizontal { writing-mode: horizontal-tb; } | ||
.vertical { writing-mode: vertical-lr; } | ||
#element_auto { animation-timeline: timeline_auto; } | ||
#element_vertical { animation-timeline: timeline_vertical; } | ||
#element_horizontal { animation-timeline: timeline_horizontal; } | ||
#element_block_in_horizontal { animation-timeline: timeline_block; } | ||
#element_inline_in_horizontal { animation-timeline: timeline_inline; } | ||
#element_block_in_vertical { animation-timeline: timeline_block; } | ||
#element_inline_in_vertical { animation-timeline: timeline_inline; } | ||
</style> | ||
<div id=scroller> | ||
<div id=contents></div> | ||
</div> | ||
<div id=container> | ||
<div id=element_auto></div> | ||
<div id=element_vertical></div> | ||
<div id=element_horizontal></div> | ||
<div id=element_block_in_horizontal class="horizontal"></div> | ||
<div id=element_inline_in_horizontal class="horizontal"></div> | ||
<div id=element_block_in_vertical class="vertical"></div> | ||
<div id=element_inline_in_vertical class="vertical"></div> | ||
</div> | ||
<script> | ||
// Animations linked to a vertical scroll-timelines are at 75% progress. | ||
scroller.scrollTop = 75; | ||
// Animations linked to a horizontal scroll-timelines are at 25% progress. | ||
scroller.scrollLeft = 25; | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_auto).width, '175px'); | ||
}, 'Orientation auto behaves as expected'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_vertical).width, '175px'); | ||
}, 'Orientation vertical behaves as expected'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_horizontal).width, '125px'); | ||
}, 'Orientation horizontal behaves as expected'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_block_in_horizontal).width, '175px'); | ||
}, 'Orientation block behaves as expected in horizontal writing-mode'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_inline_in_horizontal).width, '125px'); | ||
}, 'Orientation inline behaves as expected in horizontal writing-mode'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_block_in_vertical).writingMode, 'vertical-lr'); | ||
assert_equals(getComputedStyle(element_block_in_vertical).width, '125px'); | ||
}, 'Orientation block behaves as expected in vertical writing-mode'); | ||
|
||
promise_test(async (t) => { | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element_inline_in_vertical).writingMode, 'vertical-lr'); | ||
assert_equals(getComputedStyle(element_inline_in_vertical).width, '175px'); | ||
}, 'Orientation inline behaves as expected in vertical writing-mode'); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule"> | ||
<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#avoiding-cycles"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/web-animations/testcommon.js"></script> | ||
<style> | ||
#scroller { | ||
overflow: scroll; | ||
width: 100px; | ||
height: 100px; | ||
} | ||
#contents { | ||
height: 200px; | ||
} | ||
@keyframes expand { | ||
from { width: 100px; } | ||
to { width: 200px; } | ||
} | ||
@scroll-timeline timeline { | ||
source: selector(#scroller); | ||
time-range: 10s; | ||
start: 0px; | ||
end: 100px; | ||
} | ||
#element { | ||
width: 0px; | ||
animation: expand 10s linear; | ||
animation-timeline: timeline; | ||
} | ||
/* Ensure stable expectations if feature is not supported */ | ||
@supports not (animation-timeline:foo) { | ||
#element { animation-play-state: paused; } | ||
} | ||
</style> | ||
<div id=scroller> | ||
<div id=contents></div> | ||
</div> | ||
<div id=element></div> | ||
<script> | ||
promise_test(async (t) => { | ||
// The scroll timeline is initially inactive until the first frame. | ||
assert_equals(getComputedStyle(element).width, '0px'); | ||
await waitForNextFrame(); | ||
scroller.scrollTop = 50; | ||
// Scrolling position should not yet be reflected in the animation, | ||
// since the new scroll position has not yet been sampled. | ||
assert_equals(getComputedStyle(element).width, '100px'); | ||
await waitForNextFrame(); | ||
assert_equals(getComputedStyle(element).width, '150px'); | ||
}, 'Scroll position is sampled once per frame'); | ||
</script> |
Oops, something went wrong.