Bug 1676791 - Part 8: Hook scroll-timeline rule into Cascade data and use it for CSS animations. r=emilio,hiro

We hook the rule into cascade data, and so we can look it up by timeline
name. Now we only use StyleScrollDirection from @scroll-timeline rule.
`source` and `scroll-offsets` are skipped now and use the default values
instead because I'm pretty sure the syntax will be changed in Bug 1733260,
and `scroll-offsets` may be obsolete because the spec proposal intents to
make it be always 0% ~ 100%.

Also, add some reftests for the default `source` and `scroll-offsets`,
and different `orientation`s.

Besides, we disable at-scroll-timeline-start-end.html in Gecko because
we don't support start/end descriptors, and there are too many
intermittents in it.

Differential Revision: https://phabricator.services.mozilla.com/D126452
This commit is contained in:
Boris Chiou 2021-12-08 01:16:31 +00:00
parent b47eaf7ccc
commit 74f0bd8a0c
35 changed files with 1034 additions and 496 deletions

View File

@ -22,6 +22,7 @@ namespace dom {
class Animation;
class Document;
class ScrollTimeline;
class AnimationTimeline : public nsISupports, public nsWrapperCache {
public:
@ -104,6 +105,7 @@ class AnimationTimeline : public nsISupports, public nsWrapperCache {
virtual bool IsMonotonicallyIncreasing() const = 0;
virtual bool IsScrollTimeline() const { return false; }
virtual const ScrollTimeline* AsScrollTimeline() const { return nullptr; }
protected:
nsCOMPtr<nsIGlobalObject> mWindow;

View File

@ -8,6 +8,7 @@
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Document.h"
#include "mozilla/AnimationTarget.h"
#include "nsIFrame.h"
#include "nsIScrollableFrame.h"
#include "nsLayoutUtils.h"
@ -48,12 +49,6 @@ ScrollTimeline::ScrollTimeline(Document* aDocument, Element* aScroller)
// FIXME: Bug 1737918: We may have to udpate the constructor arguments
// because this can be nearest, root, or a specific container. For now,
// the input is a source element directly and it is the root element.
//
// FIXME: it seems we cannot use Document->GetScrollingElement() in the
// caller (i.e. nsAnimationManager::BuildAnimation()) because it flushes
// the layout, Perhaps we have to define a variant version, like
// GetScrollingElementNoLayout(), which doesn't do layout. So this causes
// a bug on quirks mode.
mSource(aScroller),
mDirection(StyleScrollDirection::Auto) {
MOZ_ASSERT(aDocument);
@ -67,6 +62,22 @@ ScrollTimeline::ScrollTimeline(Document* aDocument, Element* aScroller)
RegisterWithScrollSource();
}
already_AddRefed<ScrollTimeline> ScrollTimeline::FromRule(
const RawServoScrollTimelineRule& aRule, Document* aDocument,
const NonOwningAnimationTarget& aTarget) {
// FIXME: Use ScrollingElement in the next patch.
RefPtr<ScrollTimeline> timeline = new ScrollTimeline(
aDocument, aTarget.mElement->OwnerDoc()->GetDocumentElement());
// FIXME: Bug 1737918: applying new spec update.
// Note: If the rules changes after we build the scroll-timeline rule, we
// rebuild the animtions, so does the timeline object (because now we create
// the scroll-timeline for each animation).
// FIXME: Bug 1738135: If the scroll timeline is hold by Element, we have to
// update it once the rule is changed.
timeline->mDirection = Servo_ScrollTimelineRule_GetOrientation(&aRule);
return timeline.forget();
}
Nullable<TimeDuration> ScrollTimeline::GetCurrentTimeAsDuration() const {
const nsIFrame* frame = nsLayoutUtils::GetScrollFrameFromContent(mSource);
const nsIScrollableFrame* scrollFrame =

View File

@ -14,6 +14,9 @@
#include "mozilla/WritingModes.h"
namespace mozilla {
struct NonOwningAnimationTarget;
namespace dom {
class Document;
@ -62,6 +65,16 @@ class ScrollTimeline final : public AnimationTimeline {
ScrollTimeline() = delete;
ScrollTimeline(Document* aDocument, Element* aScroller);
// FIXME: Bug 1737918: Rewrite this because @scroll-timeline will be obsolete.
static already_AddRefed<ScrollTimeline> FromRule(
const RawServoScrollTimelineRule& aRule, Document* aDocument,
const NonOwningAnimationTarget& aTarget);
bool operator==(const ScrollTimeline& aOther) const {
return mDocument == aOther.mDocument && mSource == aOther.mSource &&
mDirection == aOther.mDirection;
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ScrollTimeline,
AnimationTimeline)
@ -89,6 +102,7 @@ class ScrollTimeline final : public AnimationTimeline {
Document* GetDocument() const override { return mDocument; }
bool IsMonotonicallyIncreasing() const override { return false; }
bool IsScrollTimeline() const override { return true; }
const ScrollTimeline* AsScrollTimeline() const override { return this; }
void ScheduleAnimations() {
// FIXME: Bug 1737927: Need to check the animation mutation observers for

View File

@ -8,6 +8,7 @@ prefs =
gfx.omta.background-color=true
layout.css.motion-path.enabled=true
layout.css.individual-transform.enabled=true
layout.css.scroll-linked-animations.enabled=true
gfx.font_loader.delay=0
gfx.font_loader.interval=0
# Support files for chrome tests that we want to load over HTTP need
@ -45,6 +46,7 @@ skip-if = (os == 'win' && bits == 64) # Bug 1363957
[mozilla/test_distance_of_path_function.html]
[mozilla/test_distance_of_transform.html]
[mozilla/test_document_timeline_origin_time_range.html]
[mozilla/test_get_animations_on_scroll_animations.html]
[mozilla/test_hide_and_show.html]
[mozilla/test_mainthread_synchronization_pref.html]
[mozilla/test_moz_prefixed_properties.html]

View File

@ -0,0 +1,74 @@
<!doctype html>
<head>
<meta charset=utf-8>
<title>Test getAnimations() which doesn't return scroll animations</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<style>
@scroll-timeline test-timeline {
source: auto;
}
@keyframes animWidth {
from { width: 100px; }
to { width: 200px }
}
@keyframes animTop {
to { top: 100px }
}
.fill-vh {
width: 100px;
height: 100vh;
}
</style>
</head>
<body>
<div id="log"></div>
<script>
"use strict";
// FIXME: getAnimations() doesn't return scroll-animations. We should fix this
// in Bug 1676795.
test(function(t) {
const div = addDiv(t,
{ style: "width: 10px; height: 100px; " +
"animation: animWidth 100s test-timeline, animTop 200s;" });
// Sanity check to make sure the scroll animation is there.
addDiv(t, { class: "fill-vh" });
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = maxScroll;
assert_equals(getComputedStyle(div).width, "200px",
"The scroll animation is there");
const animations = div.getAnimations();
assert_equals(animations.length, 1,
'getAnimations() should not include scroll animations');
assert_equals(animations[0].animationName, "animTop",
'getAmimations() should not return scroll animations');
}, 'Element.getAnimation() should not include scroll animations');
test(function(t) {
const div = addDiv(t,
{ style: "width: 10px; height: 100px; " +
"animation: animWidth 100s test-timeline, animTop 100s;" });
// Sanity check to make sure the scroll animation is there.
addDiv(t, { class: "fill-vh" });
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = maxScroll;
assert_equals(getComputedStyle(div).width, "200px",
"The scroll animation is there");
const animations = document.getAnimations();
assert_equals(animations.length, 1,
'getAnimations() should not include scroll animations');
assert_equals(animations[0].animationName, "animTop",
'getAmimations() should not return scroll animations');
}, 'Document.getAnimation() should not include scroll animations');
</script>
</body>

View File

@ -34,7 +34,7 @@ void CSSScrollTimelineRule::GetSource(nsString& aSource) const {
}
void CSSScrollTimelineRule::GetOrientation(nsString& aOrientation) const {
Servo_ScrollTimelineRule_GetOrientation(mRawRule, &aOrientation);
Servo_ScrollTimelineRule_GetOrientationAsString(mRawRule, &aOrientation);
}
void CSSScrollTimelineRule::GetScrollOffsets(nsString& aScrollOffsets) const {

View File

@ -1052,6 +1052,10 @@ inline AspectRatio StyleAspectRatio::ToLayoutRatio() const {
: AspectRatio();
}
inline nsAtom* StyleTimelineOrKeyframesName::AsAtom() const {
return IsIdent() ? AsIdent().AsAtom() : AsQuotedString().AsAtom();
}
} // namespace mozilla
#endif

View File

@ -1190,6 +1190,12 @@ const RawServoCounterStyleRule* ServoStyleSet::CounterStyleRuleForName(
return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
}
const RawServoScrollTimelineRule* ServoStyleSet::ScrollTimelineRuleForName(
nsAtom* aName) {
MOZ_ASSERT(!StylistNeedsUpdate());
return Servo_StyleSet_GetScrollTimelineRule(mRawSet.get(), aName);
}
already_AddRefed<gfxFontFeatureValueSet>
ServoStyleSet::BuildFontFeatureValueSet() {
MOZ_ASSERT(!StylistNeedsUpdate());

View File

@ -356,6 +356,8 @@ class ServoStyleSet {
const RawServoCounterStyleRule* CounterStyleRuleForName(nsAtom* aName);
const RawServoScrollTimelineRule* ScrollTimelineRuleForName(nsAtom* aName);
// Get all the currently-active font feature values set.
already_AddRefed<gfxFontFeatureValueSet> BuildFontFeatureValueSet();

View File

@ -16,6 +16,7 @@
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/ScrollTimeline.h"
#include "nsPresContext.h"
#include "nsPresContextInlines.h"
@ -48,6 +49,7 @@ using mozilla::dom::Element;
using mozilla::dom::KeyframeEffect;
using mozilla::dom::MutationObservers;
using mozilla::dom::OptionalEffectTiming;
using mozilla::dom::ScrollTimeline;
////////////////////////// nsAnimationManager ////////////////////////////
@ -140,7 +142,7 @@ static void UpdateOldAnimationPropertiesWithNew(
CSSAnimation& aOld, TimingParams&& aNewTiming,
nsTArray<Keyframe>&& aNewKeyframes, bool aNewIsStylePaused,
CSSAnimationProperties aOverriddenProperties,
ServoCSSAnimationBuilder& aBuilder) {
ServoCSSAnimationBuilder& aBuilder, dom::AnimationTimeline* aTimeline) {
bool animationChanged = false;
// Update the old from the new so we can keep the original object
@ -176,6 +178,22 @@ static void UpdateOldAnimationPropertiesWithNew(
}
}
// Replace the timeline if
// 1. The old timeline is null and the new one is non-null.
// 2. The old timeline is non-null and the new one is null.
// 3. Both timelines are scroll-timeline but they have different members
// (i.e. different owner documents, sources, or directions).
// FIXME: I believe we can do better if both are scroll-timelines, e.g. just
// replace the different members, instead of the entire timeline.
// We will do that in Bug 1738135.
dom::AnimationTimeline* oldTimeline = aOld.GetTimeline();
if (!oldTimeline != !aTimeline ||
(oldTimeline && aTimeline &&
oldTimeline->AsScrollTimeline() != aTimeline->AsScrollTimeline())) {
aOld.SetTimelineNoUpdate(aTimeline);
animationChanged = true;
}
// Handle changes in play state. If the animation is idle, however,
// changes to animation-play-state should *not* restart it.
if (aOld.PlayState() != AnimationPlayState::Idle &&
@ -198,6 +216,40 @@ static void UpdateOldAnimationPropertiesWithNew(
}
}
// FIXME: Bug 1737918: Update the syntax of animation-timeline, and null
// timeline may be obsolete.
static already_AddRefed<dom::AnimationTimeline> GetTimeline(
const StyleAnimationTimeline& aStyleTimeline, nsPresContext* aPresContext,
const NonOwningAnimationTarget& aTarget) {
RefPtr<dom::AnimationTimeline> timeline;
switch (aStyleTimeline.tag) {
case StyleAnimationTimeline::Tag::Timeline: {
nsAtom* name = aStyleTimeline.AsTimeline().AsAtom();
const auto* rule =
aPresContext->StyleSet()->ScrollTimelineRuleForName(name);
if (rule) {
// We do intentionally use the pres context's document for the owner of
// ScrollTimeline since it's consistent with what we do for
// KeyframeEffect instance.
RefPtr<ScrollTimeline> scrollTimeline =
ScrollTimeline::FromRule(*rule, aPresContext->Document(), aTarget);
timeline = scrollTimeline;
} else {
// Unknown timeline, so treat is as no timeline.
// Keep nullptr.
}
break;
}
case StyleAnimationTimeline::Tag::None:
// Keep nullptr.
break;
case StyleAnimationTimeline::Tag::Auto:
timeline = aTarget.mElement->OwnerDoc()->Timeline();
break;
}
return timeline.forget();
}
// Returns a new animation set up with given StyleAnimation.
// Or returns an existing animation matching StyleAnimation's name updated
// with the new StyleAnimation.
@ -226,6 +278,9 @@ static already_AddRefed<CSSAnimation> BuildAnimation(
bool isStylePaused = aStyleDisplay.GetAnimationPlayState(animIdx) ==
StyleAnimationPlayState::Paused;
RefPtr<dom::AnimationTimeline> timeline =
GetTimeline(aStyleDisplay.GetTimeline(animIdx), aPresContext, aTarget);
// Find the matching animation with animation name in the old list
// of animations and remove the matched animation from the list.
RefPtr<CSSAnimation> oldAnim =
@ -242,7 +297,7 @@ static already_AddRefed<CSSAnimation> BuildAnimation(
// In order to honor what the spec said, we'd copy more data over.
UpdateOldAnimationPropertiesWithNew(
*oldAnim, std::move(timing), std::move(keyframes), isStylePaused,
oldAnim->GetOverriddenProperties(), aBuilder);
oldAnim->GetOverriddenProperties(), aBuilder, timeline);
return oldAnim.forget();
}
@ -259,7 +314,7 @@ static already_AddRefed<CSSAnimation> BuildAnimation(
animation->SetOwningElement(
OwningElementRef(*aTarget.mElement, aTarget.mPseudoType));
animation->SetTimelineNoUpdate(aTarget.mElement->OwnerDoc()->Timeline());
animation->SetTimelineNoUpdate(timeline);
animation->SetEffectNoUpdate(effect);
if (isStylePaused) {

View File

@ -1151,6 +1151,7 @@ struct StyleAnimation {
dom::FillMode GetFillMode() const { return mFillMode; }
StyleAnimationPlayState GetPlayState() const { return mPlayState; }
float GetIterationCount() const { return mIterationCount; }
const StyleAnimationTimeline& GetTimeline() const { return mTimeline; }
void SetName(already_AddRefed<nsAtom> aName) { mName = aName; }
void SetName(nsAtom* aName) { mName = aName; }
@ -1315,6 +1316,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
return mAnimations[aIndex % mAnimationTimingFunctionCount]
.GetTimingFunction();
}
const mozilla::StyleAnimationTimeline& GetTimeline(uint32_t aIndex) const {
return mAnimations[aIndex % mAnimationTimelineCount].GetTimeline();
}
// The threshold used for extracting a shape from shape-outside: <image>.
float mShapeImageThreshold = 0.0f;

View File

@ -435,6 +435,7 @@ const RunningOn = {
Compositor: 1,
Either: 2,
TodoMainThread: 3,
TodoCompositor: 4,
};
const ExpectComparisonTo = {
@ -620,10 +621,9 @@ const ExpectComparisonTo = {
// Compare animated value with expected
var actualValue = normalize(actualStr);
if (actualValue === null) {
ok(false, desc + ": should return a valid result - got " + actualStr);
return;
}
// Note: the actualStr should be empty string when using todoCompositor, so
// actualValue is null in this case. However, compare() should handle null
// well.
okOrTodo(
compare(expectedValue, actualValue, tolerance),
desc +
@ -692,6 +692,11 @@ const ExpectComparisonTo = {
};
window.matricesRoughlyEqual = function(a, b, tolerance) {
// Error handle if a or b is invalid.
if (!a || !b) {
return false;
}
tolerance = tolerance || 0.00011;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {

View File

@ -5,6 +5,7 @@ prefs =
dom.animations-api.getAnimations.enabled=true
dom.animations-api.implicit-keyframes.enabled=true
dom.animations-api.timelines.enabled=true
dom.animations.mainthread-synchronization-with-geometric-animations=true
gfx.omta.background-color=true
gfx.font_loader.delay=0
layout.css.accent-color.enabled=true
@ -18,7 +19,7 @@ prefs =
layout.css.backdrop-filter.enabled=true
layout.css.fit-content-function.enabled=true
layout.css.d-property.enabled=true
layout.css.scroll-linked-animations=true
layout.css.scroll-linked-animations.enabled=true
layout.css.scrollbar-gutter.enabled=true
support-files =
animation_utils.js

View File

@ -13419,7 +13419,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-linked-animations.enabled")) {
gCSSProperties["animation"].subproperties.push("animation-timeline");
gCSSProperties["animation"].initial_values.push(
"none none 0s 0s ease normal running 1.0 auto",
"auto"
"none none auto"
);
gCSSProperties["animation"].other_values.push(
"none none 0s 0s cubic-bezier(0.25, 0.1, 0.25, 1.0) normal running 1.0 auto",
@ -13431,6 +13431,9 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-linked-animations.enabled")) {
"1s bounce none, 2s none auto"
);
gCSSProperties["-moz-animation"].subproperties.push("animation-timeline");
gCSSProperties["-webkit-animation"].subproperties.push("animation-timeline");
gCSSProperties["animation-timeline"] = {
domProp: "animationTimeline",
inherited: false,
@ -13445,7 +13448,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-linked-animations.enabled")) {
"color",
"bounce, bubble, opacity",
"foobar",
"auto",
"\\32bounce",
"-bounce",
"-\\32bounce",

View File

@ -171,6 +171,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=964646
0%, 100% { transform: translateX(50px) }
25%, 75% { transform: none }
}
.fill-vh {
width: 100px;
height: 100vh;
}
@scroll-timeline test-timeline {
orientation: block;
}
@keyframes geometry {
from { width: 50px; }
to { width: 100px; }
}
</style>
</head>
<body>
@ -2427,12 +2441,12 @@ addAsyncAnimTest(async function() {
gDiv.style.backgroundColor = "rgb(0, 255, 0)";
await waitForPaintsFlushed();
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor,
"background-color transition starting with current-color runs on " +
"compositor thread");
advance_clock(5000);
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor,
"background-color on compositor at 5s");
done_div();
@ -2452,20 +2466,20 @@ addAsyncAnimTest(async function() {
await waitForPaintsFlushed();
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor,
"background-color animation starting with current-color runs on " +
"compositor thread");
advance_clock(500);
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor,
"background-color on compositor at 5s");
// Change the parent's color in the middle of the animation.
parent.style.color = "rgb(0, 0, 255)";
await waitForPaintsFlushed();
omta_todo_is("background-color", "rgb(0, 128, 128)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(0, 128, 128)", RunningOn.TodoCompositor,
"background-color on compositor is reflected by the parent's " +
"color change");
@ -2493,13 +2507,13 @@ addAsyncAnimTest(async function() {
gDiv.animate({ backgroundColor: [ "currentColor", "rgb(0, 255, 0)" ] }, 1000);
await waitForPaintsFlushed();
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor,
"background-color animation starting with current-color runs on " +
"compositor thread");
advance_clock(500);
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.ToDoCompositor,
omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor,
"background-color on compositor at 5s");
const topLocation =
@ -2846,5 +2860,36 @@ addAsyncAnimTest(async function() {
done_div();
});
// transform property with scroll-linked animations.
addAsyncAnimTest(async function() {
new_div("animation: always_fifty 10s scroll_timeline;");
await waitForPaintsFlushed();
omta_todo_is("transform", { tx: 50 }, RunningOn.TodoCompositor,
"scroll transform animations should runs on compositor thread");
done_div();
});
// The non-omta property with scroll-timeline together with an omta property
// with document-timeline.
addAsyncAnimTest(async function() {
// Put an empty filling element to make the scroll range be non-zero, so the
// progress of scroll-timeline is 0% (running), instead of 100% (finished).
let filling = document.createElement("div");
filling.classList.add("fill-vh");
document.body.appendChild(filling);
new_div("animation: geometry 10s test-timeline, always_fifty 1s infinite;");
await waitForPaintsFlushed();
// Note: width is not a OMTA property, so it must be running on the main
// thread.
omta_is("transform", { tx: 50 }, RunningOn.Compositor,
"transform animations should runs on compositor thread");
done_div();
filling.remove();
});
</script>
</html>

View File

@ -211,25 +211,27 @@ is(e.style.transition, "", "should not have transition shorthand (lists differen
e.setAttribute("style", "transition: color, width; transition-delay: 0s");
is(e.style.transition, "", "should not have transition shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
isnot(e.style.animation, "", "should have animation shorthand (lists same length)");
e.setAttribute("style", "animation-name: bounce, roll, left; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll, left; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms, 300ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms, 300ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear, ease-out; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear, ease-out; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s, 0s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s, 0s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards, both; animation-iteration-count: infinite, 2; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards, both; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2, 1; animation-play-state: paused, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2, 1; animation-play-state: paused, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running, running;");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running, running; animation-timeline: auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running; animation-timeline: auto, auto, auto;");
is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
// Check that the 'border' shorthand resets 'border-image' and

View File

@ -619,11 +619,12 @@ impl StylesheetInvalidationSet {
// existing elements.
}
},
ScrollTimeline(..) => {
// TODO: Bug 1676784: check if animation-timeline name is referenced.
// Now we do nothing.
},
CounterStyle(..) | Page(..) | Viewport(..) | FontFeatureValues(..) => {
// TODO: Check if timeline name is referenced, though this might go away in bug 1737918.
ScrollTimeline(..) |
CounterStyle(..) |
Page(..) |
Viewport(..) |
FontFeatureValues(..) => {
debug!(
" > Found unsupported rule, marking the whole subtree \
invalid."

View File

@ -277,7 +277,7 @@ trait PrivateMatchMethods: TElement {
let old_box_style = old_style.get_box();
let keyframes_could_have_changed = context
let keyframes_or_timeline_could_have_changed = context
.shared
.traversal_flags
.contains(TraversalFlags::ForCSSRuleChanges);
@ -287,9 +287,9 @@ trait PrivateMatchMethods: TElement {
// element has or will have CSS animation style regardless of whether
// the animation is running or not.
//
// TODO: We should check which @keyframes were added/changed/deleted and
// update only animations corresponding to those @keyframes.
if keyframes_could_have_changed {
// TODO: We should check which @keyframes/@scroll-timeline were added/changed/deleted and
// update only animations corresponding to those @keyframes/@scroll-timeline.
if keyframes_or_timeline_could_have_changed {
return true;
}

View File

@ -31,7 +31,9 @@ use crate::stylesheets::keyframes_rule::KeyframesAnimation;
use crate::stylesheets::layer_rule::{LayerId, LayerName, LayerOrder};
use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
#[cfg(feature = "gecko")]
use crate::stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule};
use crate::stylesheets::{
CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule, ScrollTimelineRule,
};
use crate::stylesheets::{
CssRule, EffectiveRulesIterator, Origin, OriginSet, PerOrigin, PerOriginIter,
};
@ -1567,6 +1569,10 @@ pub struct ExtraStyleData {
/// A map of effective page rules.
#[cfg(feature = "gecko")]
pub pages: Vec<Arc<Locked<PageRule>>>,
/// A map of effective scroll-timeline rules.
#[cfg(feature = "gecko")]
pub scroll_timelines: PrecomputedHashMap<Atom, Arc<Locked<ScrollTimelineRule>>>,
}
#[cfg(feature = "gecko")]
@ -1595,6 +1601,18 @@ impl ExtraStyleData {
fn add_page(&mut self, rule: &Arc<Locked<PageRule>>) {
self.pages.push(rule.clone());
}
/// Add the given @scroll-timeline rule.
fn add_scroll_timeline(
&mut self,
guard: &SharedRwLockReadGuard,
rule: &Arc<Locked<ScrollTimelineRule>>,
)-> Result<(), FailedAllocationError> {
let name = rule.read_with(guard).name.as_atom().clone();
self.scroll_timelines
.try_insert(name, rule.clone())
.map(|_| {})
}
}
impl ExtraStyleData {
@ -1605,6 +1623,7 @@ impl ExtraStyleData {
self.font_feature_values.clear();
self.counter_styles.clear();
self.pages.clear();
self.scroll_timelines.clear();
}
}
}
@ -1629,6 +1648,7 @@ impl MallocSizeOf for ExtraStyleData {
n += self.font_feature_values.shallow_size_of(ops);
n += self.counter_styles.shallow_size_of(ops);
n += self.pages.shallow_size_of(ops);
n += self.scroll_timelines.shallow_size_of(ops);
n
}
}
@ -2373,12 +2393,10 @@ impl CascadeData {
}
},
#[cfg(feature = "gecko")]
CssRule::ScrollTimeline(..) => {
// TODO: Bug 1676791: set the timeline into animation.
// https://phabricator.services.mozilla.com/D126452
//
CssRule::ScrollTimeline(ref rule) => {
// Note: Bug 1733260: we may drop @scroll-timeline rule once this spec issue
// https://github.com/w3c/csswg-drafts/issues/6674 gets landed.
self.extra_data.add_scroll_timeline(guard, rule)?;
},
#[cfg(feature = "gecko")]
CssRule::FontFace(ref rule) => {

View File

@ -884,3 +884,8 @@ renaming_overrides_prefixing = true
public:
StyleAnimationTimeline(): tag(Tag::Auto) {}
"""
"TimelineOrKeyframesName" = """
public:
inline nsAtom* AsAtom() const;
"""

View File

@ -118,6 +118,7 @@ use style::string_cache::{Atom, WeakAtom};
use style::style_adjuster::StyleAdjuster;
use style::stylesheets::import_rule::ImportSheet;
use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
use style::stylesheets::scroll_timeline_rule::ScrollDirection;
use style::stylesheets::supports_rule::parse_condition_or_declaration;
use style::stylesheets::{
AllowImportRules, CounterStyleRule, CssRule, CssRuleType, CssRules, CssRulesHelpers,
@ -2794,20 +2795,28 @@ pub extern "C" fn Servo_ScrollTimelineRule_GetSource(
}
#[no_mangle]
pub extern "C" fn Servo_ScrollTimelineRule_GetOrientation(
pub extern "C" fn Servo_ScrollTimelineRule_GetOrientationAsString(
rule: &RawServoScrollTimelineRule,
result: &mut nsString,
) {
read_locked_arc(rule, |rule: &ScrollTimelineRule| {
rule.descriptors
.orientation
.as_ref()
.unwrap_or(&Default::default())
.unwrap_or_default()
.to_css(&mut CssWriter::new(result))
.unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_ScrollTimelineRule_GetOrientation(
rule: &RawServoScrollTimelineRule,
) -> ScrollDirection {
read_locked_arc(rule, |rule: &ScrollTimelineRule| {
rule.descriptors.orientation.unwrap_or_default()
})
}
#[no_mangle]
pub extern "C" fn Servo_ScrollTimelineRule_GetScrollOffsets(
rule: &RawServoScrollTimelineRule,
@ -6336,6 +6345,21 @@ pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetScrollTimelineRule(
raw_data: &RawServoStyleSet,
name: *mut nsAtom,
) -> *const RawServoScrollTimelineRule {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
Atom::with(name, |name| {
data.stylist
.iter_extra_data_origins()
.filter_map(|(d, _)| d.scroll_timelines.get(name))
.next()
.map_or(ptr::null(), |rule| rule.as_borrowed())
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
raw_data: &RawServoStyleSet,

View File

@ -1,7 +0,0 @@
[animation-timeline-none.html]
[Animation with unknown timeline name holds current time at zero]
expected: FAIL
[Animation with animation-timeline:none holds current time at zero]
expected: FAIL

View File

@ -1,58 +1,13 @@
[at-scroll-timeline-element-offsets.html]
[Scroll at offset 200 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 150 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 99 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 150 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 398 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 199 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 199 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 362 updates animation correctly [element_end_start_05\]]
expected: FAIL
@ -62,63 +17,15 @@
[Scroll at offset 206 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 175 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 398 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 375 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_start_400px\]]
expected: FAIL
@ -128,36 +35,12 @@
[Scroll at offset 393 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 248 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 247 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_start_start\]]
expected: FAIL
@ -179,3 +62,222 @@
[Scroll at offset 50 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 199 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_start_start\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 99 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 375 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 199 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_end_start\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 99 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_end_1_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 375 updates animation correctly [element_end_start_05\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 199 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_start_400px\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 49 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 250 updates animation correctly [element_50px_end\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_outside\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_display_none\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 300 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 400 updates animation correctly [element_null_target\]]
expected: FAIL
[Scroll at offset 450 updates animation correctly [element_null_target\]]
expected: FAIL

View File

@ -1,310 +1,2 @@
[at-scroll-timeline-start-end.html]
[Scroll at offset 49 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 51 updates animation correctly [element_50px_100px\]]
expected: [FAIL, PASS]
[Scroll at offset 49 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_auto_100px\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 50 updates animation correctly [element_auto_100px\]]
expected: FAIL
[Scroll at offset 99 updates animation correctly [element_0px_100px\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 50 updates animation correctly [element_0px_100px\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_0px_100px\]]
expected: FAIL
[Scroll at offset 99 updates animation correctly [element_auto_100px\]]
expected: FAIL
[Scroll at offset 1 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 101 updates animation correctly [element_0px_100px\]]
expected: FAIL
[Scroll at offset 101 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 1 updates animation correctly [element_0px_100px\]]
expected:
if (os == "linux") and not fission: [FAIL, PASS]
FAIL
[Scroll at offset 99 updates animation correctly [element_50px_100px\]]
expected: FAIL
[Scroll at offset 1 updates animation correctly [element_auto_100px\]]
expected: FAIL
[Scroll at offset 106 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 190 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 195 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 190 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 212 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 212 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 43 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 42 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 212 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 212 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 75 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 116 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 131 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 169 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 63 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 74 updates animation correctly [element_25p_75p\]]
expected: [FAIL, PASS]
[Scroll at offset 21 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 21 updates animation correctly [element_auto_auto\]]
expected:
if (os == "linux") and not debug and (processor == "x86_64") and not fission: [PASS, FAIL]
[FAIL, PASS]
[Scroll at offset 21 updates animation correctly [element_auto_auto_implicit\]]
expected:
if (os == "linux") and not fission and not swgl and (processor == "x86_64") and debug: [PASS, FAIL]
if (os == "linux") and not fission and not swgl and (processor == "x86_64") and not debug: [PASS, FAIL]
if (os == "win") and debug and not fission and (processor == "x86"): [PASS, FAIL]
if (os == "win") and not debug and (processor == "x86"): [PASS, FAIL]
if (os == "win") and debug and fission: [PASS, FAIL]
[FAIL, PASS]
[Scroll at offset 179 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 106 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 116 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 215 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 107 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 117 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 193 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 215 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 107 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 193 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 172 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 182 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 215 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 198 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 118 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 215 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 132 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 64 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 183 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 217 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 173 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 217 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 119 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 195 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 217 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 118 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 108 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 108 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 195 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 217 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 133 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 60 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 40 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 160 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 20 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 70 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 20 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 20 updates animation correctly [element_auto_auto_implicit\]]
expected:
if debug and not swgl: [PASS, FAIL]
[FAIL, PASS]
[Scroll at offset 180 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 180 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_auto_auto\]]
expected: FAIL
[Scroll at offset 170 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 110 updates animation correctly [element_calc_calc\]]
expected: FAIL
[Scroll at offset 100 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 110 updates animation correctly [element_25p_75p\]]
expected: FAIL
[Scroll at offset 125 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 185 updates animation correctly [element_50px_auto\]]
expected: FAIL
[Scroll at offset 200 updates animation correctly [element_auto_auto_implicit\]]
expected: FAIL
[Scroll at offset 0 updates animation correctly [element_0px_100px\]]
expected:
if (os == "win") and not debug and not fission and (processor == "x86_64"): [PASS, FAIL]
if (os == "mac") and not debug: [PASS, FAIL]
[FAIL, PASS]
[Scroll at offset 50 updates animation correctly [element_50px_100px\]]
expected: [PASS, FAIL]
[Scroll at offset 0 updates animation correctly [element_auto_auto\]]
expected: [PASS, FAIL]
[Scroll at offset 50 updates animation correctly [element_50px_auto\]]
expected: [PASS, FAIL]
[Scroll at offset 0 updates animation correctly [element_auto_100px\]]
expected: [PASS, FAIL]
[Scroll at offset 0 updates animation correctly [element_auto_auto_implicit\]]
expected:
if (os == "linux") and not fission and not debug and (processor == "x86_64"): [FAIL, PASS]
[PASS, FAIL]
[Scroll at offset 0 updates animation correctly [element_auto_auto\]]
expected:
if (os == "win") and fission and not debug: PASS
if (os == "android") and debug: PASS
if (os == "win") and not fission: PASS
if os == "mac": PASS
[PASS, FAIL]
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1733521

View File

@ -55,15 +55,3 @@
expected:
if not nightly_build: FAIL
[After transitioning from a null timeline on an animation with a sufficiently ancient start time it is finished]
expected: FAIL
[After clearing timeline on running animation it is still running]
expected: FAIL
[After transitioning from a null timeline on an animation with a start time it is still running]
expected: FAIL
[After clearing timeline on finished animation it is running]
expected: FAIL

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<title>Reference for default @scroll-timeline</title>
<iframe width="400" height="400" srcdoc='
<html>
<style>
html {
min-height: 100%;
padding-bottom: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
transform: translateY(100px);
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<script>
window.addEventListener("load", function() {
// Move the scroller to halfway.
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
});
</script>
<div id="box"></div>
</html>
'></iframe>

View File

@ -0,0 +1,69 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<title>The default scroll-timeline at rule in the iframe</title>
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
<meta name="assert" content="CSS animation correctly updates values when using the default scroll-timeline at rule">
<link rel="match" href="at-scroll-timeline-default-descriptors-iframe-ref.html">
<iframe id="target" width="400" height="400" srcdoc='
<html>
<style>
@keyframes update {
from { transform: translateY(0px); }
to { transform: translateY(200px); }
}
@scroll-timeline test-timeline {
source: auto;
orientation: auto;
scroll-offsets: none;
}
html {
min-height: 100%;
padding-bottom: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
animation: update 1s linear;
animation-timeline: test-timeline;
}
#covered {
width: 100px;
height: 100px;
background-color: red;
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<script>
window.addEventListener("load", function() {
const scroller = document.scrollingElement;
// Move the scroller to the halfway point.
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
window.requestAnimationFrame(() => {
window.parent.postMessage("success", "*");
});
});
</script>
<body>
<div id="box"></div>
<div id="covered"></div>
</body>
</html>
'></iframe>
<script>
window.addEventListener("message", event => {
if (event.data == "success") {
document.documentElement.classList.remove("reftest-wait");
}
}, false);
</script>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<title>Reference for default @scroll-timeline</title>
<style>
html {
min-height: 100%;
padding-bottom: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
transform: translateY(100px);
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<div id="box"></div>
<script>
window.addEventListener('load', function() {
// Move the scroller to halfway.
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
});
</script>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>Reference for default @scroll-timeline with vertical-rl</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<style>
html {
min-block-size: 100%;
padding-block-end: 100px;
writing-mode: vertical-rl
}
#box {
width: 100px;
height: 100px;
background-color: green;
transform: translateX(-100px);
}
* {
margin-block: 0px;
}
</style>
<div id="box"></div>
<script>
window.addEventListener('load', function() {
// Move the scroller to halfway.
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollWidth - scroller.clientWidth;
scroller.scrollLeft = -0.5 * maxScroll;
});
</script>

View File

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<title>The default scroll-timeline at rule with writing-mode:vertical-rl</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
<meta name="assert" content="CSS animation correctly updates values when using
the default scroll-timeline at rule with writing-mode:vertical-rl">
<link rel="match" href="at-scroll-timeline-default-descriptors-writing-mode-rl-ref.html">
<style>
@keyframes update {
from { transform: translateX(0px); }
to { transform: translateX(-200px); }
}
@scroll-timeline test-timeline {
source: auto;
orientation: auto;
scroll-offsets: none;
}
html {
min-block-size: 100%;
padding-block-end: 100px;
writing-mode: vertical-rl;
}
#box {
width: 100px;
height: 100px;
background-color: green;
animation: update 1s linear;
animation-timeline: test-timeline;
}
#covered {
width: 100px;
height: 100px;
background-color: red;
}
* {
margin-block: 0px;
}
</style>
<div id="box"></div>
<div id="covered"></div>
<script>
window.addEventListener('load', function() {
const scroller = document.scrollingElement;
// Move the scroller to the halfway point.
const maxScroll = scroller.scrollWidth - scroller.clientWidth;
scroller.scrollLeft = -0.5 * maxScroll;
window.requestAnimationFrame(() => {
document.documentElement.classList.remove("reftest-wait");
});
});
</script>

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<title>The default scroll-timeline at rule</title>
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
<meta name="assert" content="CSS animation correctly updates values when using the default scroll-timeline at rule">
<link rel="match" href="at-scroll-timeline-default-descriptors-ref.html">
<style>
@keyframes update {
from { transform: translateY(0px); }
to { transform: translateY(200px); }
}
@scroll-timeline test-timeline {
source: auto;
orientation: auto;
scroll-offsets: none;
}
html {
min-height: 100%;
padding-bottom: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
animation: update 1s linear;
animation-timeline: test-timeline;
}
#covered {
width: 100px;
height: 100px;
background-color: red;
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<div id="box"></div>
<div id="covered"></div>
<script>
window.addEventListener('load', function() {
const scroller = document.scrollingElement;
// Move the scroller to the halfway point.
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
window.requestAnimationFrame(() => {
document.documentElement.classList.remove("reftest-wait");
});
});
</script>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<title>Reference for default @scroll-timeline</title>
<style>
html {
min-height: 100%;
padding-bottom: 50px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
transform: translateY(100px);
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<div id="box"></div>
<script>
window.addEventListener('load', function() {
// Move the scroller to halfway.
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.5 * maxScroll;
});
</script>

View File

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html class="reftest-wait">
<title>The default scroll-timeline at rule when the frame size changed</title>
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
<meta name="assert" content="CSS animation correctly updates values when using
the default scroll-timeline at rule and update the
frame size">
<link rel="match" href="at-scroll-timeline-frame-size-changed-ref.html">
<style>
@keyframes update {
from { transform: translateY(0px); }
to { transform: translateY(200px); }
}
@scroll-timeline test-timeline {
source: auto;
orientation: auto;
scroll-offsets: none;
}
html {
min-height: 100%;
padding-bottom: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
animation: update 1s linear;
animation-timeline: test-timeline;
}
#covered {
width: 100px;
height: 100px;
background-color: red;
}
* {
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<div id="box"></div>
<div id="covered"></div>
<script>
window.addEventListener('load', function() {
const scroller = document.scrollingElement;
// Move the scroller to the 25% point.
const maxScroll = scroller.scrollHeight - scroller.clientHeight;
scroller.scrollTop = 0.25 * maxScroll;
window.requestAnimationFrame(() => {
// Update scroll range to make the current position become 50% point.
scroller.style.paddingBottom = "50px";
window.requestAnimationFrame(() => {
document.documentElement.classList.remove("reftest-wait");
});
});
});
</script>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>Reference for @scroll-timeline with inline orientation</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<style>
html {
min-width: 100%;
padding-right: 100px;
}
#box {
width: 100px;
height: 100px;
background-color: green;
transform: translateX(100px);
}
* {
margin-left: 0px;
margin-right: 0px;
}
</style>
<div id="box"></div>
<script>
window.addEventListener('load', function() {
// Move the scroller to halfway.
const scroller = document.scrollingElement;
const maxScroll = scroller.scrollWidth - scroller.clientWidth;
scroller.scrollLeft = 0.5 * maxScroll;
});
</script>

View File

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<title>The scroll-timeline at rule with inline orientation and default source</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule">
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#descdef-scroll-timeline-orientation">
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-timeline">
<meta name="assert" content="CSS animation correctly updates values when using the inline orientation">
<link rel="match" href="at-scroll-timeline-inline-orientation-ref.html">
<style>
@keyframes update {
from { transform: translateX(0px); }
to { transform: translateX(200px); }
}
@scroll-timeline test-timeline {
source: auto;
orientation: inline;
scroll-offsets: none;
}
html {
min-width: 100%;
padding-right: 100px;
font-size: 0;
}
#box {
width: 100px;
height: 100px;
background-color: green;
animation: update 1s linear;
animation-timeline: test-timeline;
display: inline-block;
}
#covered {
width: 100px;
height: 100px;
background-color: red;
display: inline-block;
}
* {
margin-left: 0px;
margin-right: 0px;
}
</style>
<div id="box"></div>
<div id="covered"></div>
<script>
window.addEventListener('load', function() {
const scroller = document.scrollingElement;
// Move the scroller to the halfway point.
const maxScroll = scroller.scrollWidth - scroller.clientWidth;
scroller.scrollLeft = 0.5 * maxScroll;
window.requestAnimationFrame(() => {
document.documentElement.classList.remove("reftest-wait");
});
});
</script>