mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1808410 - Part 3: Create timeline for view(). r=emilio
Also, I add some similar tests but they don't use Named Timeline Range, which is not supported by Gecko now (Bug 1824875). Differential Revision: https://phabricator.services.mozilla.com/D173905
This commit is contained in:
parent
97804f78e4
commit
77a0fd63cf
@ -28,10 +28,22 @@ already_AddRefed<ViewTimeline> ViewTimeline::MakeNamed(
|
|||||||
auto scroller = Scroller::Nearest(const_cast<Element*>(element), pseudo);
|
auto scroller = Scroller::Nearest(const_cast<Element*>(element), pseudo);
|
||||||
|
|
||||||
// 2. Create timeline.
|
// 2. Create timeline.
|
||||||
return RefPtr<ViewTimeline>(
|
return MakeAndAddRef<ViewTimeline>(aDocument, scroller,
|
||||||
new ViewTimeline(aDocument, scroller, aStyleTimeline.GetAxis(),
|
aStyleTimeline.GetAxis(), aSubject,
|
||||||
aSubject, aPseudoType, aStyleTimeline.GetInset()))
|
aPseudoType, aStyleTimeline.GetInset());
|
||||||
.forget();
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
already_AddRefed<ViewTimeline> ViewTimeline::MakeAnonymous(
|
||||||
|
Document* aDocument, const NonOwningAnimationTarget& aTarget,
|
||||||
|
StyleScrollAxis aAxis, const StyleViewTimelineInset& aInset) {
|
||||||
|
// view() finds the nearest scroll container from the animation target.
|
||||||
|
auto [element, pseudo] =
|
||||||
|
FindNearestScroller(aTarget.mElement, aTarget.mPseudoType);
|
||||||
|
Scroller scroller = Scroller::Nearest(const_cast<Element*>(element), pseudo);
|
||||||
|
return MakeAndAddRef<ViewTimeline>(aDocument, scroller, aAxis,
|
||||||
|
aTarget.mElement, aTarget.mPseudoType,
|
||||||
|
aInset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewTimeline::ReplacePropertiesWith(Element* aSubjectElement,
|
void ViewTimeline::ReplacePropertiesWith(Element* aSubjectElement,
|
||||||
|
@ -18,6 +18,9 @@ namespace mozilla::dom {
|
|||||||
* is a special case of ScrollTimeline.
|
* is a special case of ScrollTimeline.
|
||||||
*/
|
*/
|
||||||
class ViewTimeline final : public ScrollTimeline {
|
class ViewTimeline final : public ScrollTimeline {
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
friend already_AddRefed<T> mozilla::MakeAndAddRef(Args&&... aArgs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ViewTimeline, ScrollTimeline)
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ViewTimeline, ScrollTimeline)
|
||||||
@ -30,6 +33,10 @@ class ViewTimeline final : public ScrollTimeline {
|
|||||||
Document* aDocument, Element* aSubject, PseudoStyleType aPseudoType,
|
Document* aDocument, Element* aSubject, PseudoStyleType aPseudoType,
|
||||||
const StyleViewTimeline& aStyleTimeline);
|
const StyleViewTimeline& aStyleTimeline);
|
||||||
|
|
||||||
|
static already_AddRefed<ViewTimeline> MakeAnonymous(
|
||||||
|
Document* aDocument, const NonOwningAnimationTarget& aTarget,
|
||||||
|
StyleScrollAxis aAxis, const StyleViewTimelineInset& aInset);
|
||||||
|
|
||||||
JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override {
|
JS::Handle<JSObject*> aGivenProto) override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -270,8 +270,11 @@ static already_AddRefed<dom::AnimationTimeline> GetTimeline(
|
|||||||
return ScrollTimeline::MakeAnonymous(aPresContext->Document(), aTarget,
|
return ScrollTimeline::MakeAnonymous(aPresContext->Document(), aTarget,
|
||||||
scroll.axis, scroll.scroller);
|
scroll.axis, scroll.scroller);
|
||||||
}
|
}
|
||||||
case StyleAnimationTimeline::Tag::View:
|
case StyleAnimationTimeline::Tag::View: {
|
||||||
// TODO: Support this in this patch series. Treat it as auto for now.
|
const auto& view = aStyleTimeline.AsView();
|
||||||
|
return ViewTimeline::MakeAnonymous(aPresContext->Document(), aTarget,
|
||||||
|
view.axis, view.inset);
|
||||||
|
}
|
||||||
case StyleAnimationTimeline::Tag::Auto:
|
case StyleAnimationTimeline::Tag::Auto:
|
||||||
return do_AddRef(aTarget.mElement->OwnerDoc()->Timeline());
|
return do_AddRef(aTarget.mElement->OwnerDoc()->Timeline());
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,36 @@
|
|||||||
[animation-timeline-view-functional-notation.tentative.html]
|
[animation-timeline-view-functional-notation.tentative.html]
|
||||||
[animation-timeline: view()]
|
[animation-timeline: view()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(50px)]
|
[animation-timeline: view(50px)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(auto 50px)]
|
[animation-timeline: view(auto 50px)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(inline)]
|
[animation-timeline: view(inline)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(horizontal)]
|
[animation-timeline: view(horizontal)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(vertical)]
|
[animation-timeline: view(vertical)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(horizontal 50px)]
|
[animation-timeline: view(horizontal 50px)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(), view(inline)]
|
[animation-timeline: view(), view(inline)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
|
||||||
[animation-timeline: view(inline) changes to view(inline 50px)]
|
[animation-timeline: view(inline) changes to view(inline 50px)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1824875
|
||||||
|
@ -8,6 +8,20 @@
|
|||||||
<script src="/web-animations/testcommon.js"></script>
|
<script src="/web-animations/testcommon.js"></script>
|
||||||
<script src="support/testcommon.js"></script>
|
<script src="support/testcommon.js"></script>
|
||||||
<style>
|
<style>
|
||||||
|
@keyframes fade-in-out-without-timeline-range {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
40% { opacity: 1; }
|
||||||
|
60% { opacity: 1; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
@keyframes fade-out-without-timeline-range {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
@keyframes change-font-size-without-timeline-range {
|
||||||
|
0% { font-size: 10px; }
|
||||||
|
100% { font-size: 30px; }
|
||||||
|
}
|
||||||
@keyframes fade-in-out {
|
@keyframes fade-in-out {
|
||||||
entry 0% { opacity: 0; }
|
entry 0% { opacity: 0; }
|
||||||
entry 100% { opacity: 1; }
|
entry 100% { opacity: 1; }
|
||||||
@ -96,6 +110,203 @@ async function scrollTop(element, value) {
|
|||||||
await waitForNextFrame();
|
await waitForNextFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------
|
||||||
|
// Tests without timeline range name
|
||||||
|
// ---------------------------------
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['content', 'target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-in-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view()";
|
||||||
|
// So the range is [200px, 500px].
|
||||||
|
|
||||||
|
await scrollTop(container, 200);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 0%');
|
||||||
|
await scrollTop(container, 260);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 20%');
|
||||||
|
await scrollTop(container, 320);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 40%');
|
||||||
|
|
||||||
|
await scrollTop(container, 380);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 60%');
|
||||||
|
await scrollTop(container, 440);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 80%');
|
||||||
|
await scrollTop(container, 500);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view() without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['content', 'target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-in-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(50px)";
|
||||||
|
// So the range is [250px, 450px].
|
||||||
|
|
||||||
|
await scrollTop(container, 250);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 0%');
|
||||||
|
await scrollTop(container, 290);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 20%');
|
||||||
|
await scrollTop(container, 330);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 40%');
|
||||||
|
|
||||||
|
await scrollTop(container, 370);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 60%');
|
||||||
|
await scrollTop(container, 410);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 80%');
|
||||||
|
await scrollTop(container, 450);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(50px) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['content', 'target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-in-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(auto 50px)";
|
||||||
|
// So the range is [250px, 500px].
|
||||||
|
|
||||||
|
await scrollTop(container, 250);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 0%');
|
||||||
|
await scrollTop(container, 300);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 20%');
|
||||||
|
await scrollTop(container, 350);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 40%');
|
||||||
|
|
||||||
|
await scrollTop(container, 400);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '1', 'At 60%');
|
||||||
|
await scrollTop(container, 450);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.5', 'At 80%');
|
||||||
|
await scrollTop(container, 500);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(auto 50px) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(inline)";
|
||||||
|
// So the range is [-200px, 100px], but it is impossible to scroll to the
|
||||||
|
// negative part.
|
||||||
|
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_approx_equals(parseFloat(getComputedStyle(div).opacity), 0.33333,
|
||||||
|
0.00001, 'At 66.7%');
|
||||||
|
// Note: 20% for each 60px.
|
||||||
|
await scrollLeft(container, 40);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80%');
|
||||||
|
await scrollLeft(container, 100);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(inline) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(horizontal)";
|
||||||
|
// So the range is [-200px, 100px], but it is impossible to scroll to the
|
||||||
|
// negative part.
|
||||||
|
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_approx_equals(parseFloat(getComputedStyle(div).opacity), 0.33333,
|
||||||
|
0.00001, 'At 66.7%');
|
||||||
|
// Note: 20% for each 60px.
|
||||||
|
await scrollLeft(container, 40);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80%');
|
||||||
|
await scrollLeft(container, 100);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(horizontal) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(vertical)";
|
||||||
|
// So the range is [-200px, 100px], but it is impossible to scroll to the
|
||||||
|
// negative part.
|
||||||
|
|
||||||
|
await scrollTop(container, 0);
|
||||||
|
assert_approx_equals(parseFloat(getComputedStyle(div).opacity), 0.33333,
|
||||||
|
0.00001, 'At 66.7%');
|
||||||
|
// Note: 20% for each 60px.
|
||||||
|
await scrollTop(container, 40);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80%');
|
||||||
|
await scrollTop(container, 100);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(vertical) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(horizontal 50px)";
|
||||||
|
// So the range is [-150px, 50px], but it is impossible to scroll to the
|
||||||
|
// negative part.
|
||||||
|
|
||||||
|
// Note: 25% for each 50px.
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.25', 'At 75%');
|
||||||
|
await scrollLeft(container, 10);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80%');
|
||||||
|
await scrollLeft(container, 50);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(horizontal 50px) without timeline range name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear, " +
|
||||||
|
"change-font-size-without-timeline-range 1s linear";
|
||||||
|
div.style.animationTimeline = "view(50px), view(inline 50px)";
|
||||||
|
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_equals(getComputedStyle(div).fontSize, '25px', 'At 75% inline');
|
||||||
|
await scrollLeft(container, 10);
|
||||||
|
assert_equals(getComputedStyle(div).fontSize, '26px', 'At 80% inline');
|
||||||
|
await scrollLeft(container, 50);
|
||||||
|
assert_equals(getComputedStyle(div).fontSize, '30px', 'At 100% inline');
|
||||||
|
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
|
||||||
|
await scrollTop(container, 0);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.25', 'At 75% block');
|
||||||
|
await scrollTop(container, 10);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80% block');
|
||||||
|
await scrollTop(container, 50);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100% block');
|
||||||
|
|
||||||
|
await scrollLeft(container, 10);
|
||||||
|
await scrollTop(container, 10);
|
||||||
|
assert_equals(getComputedStyle(div).fontSize, '26px', 'At 80% inline');
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80% block');
|
||||||
|
}, 'animation-timeline: view(50px), view(inline 50px) without timeline range ' +
|
||||||
|
'name');
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
let [container, div] = createTargetWithStuff(t, ['target', 'content']);
|
||||||
|
container.style.overflow = 'hidden';
|
||||||
|
div.style.animation = "fade-out-without-timeline-range 1s linear";
|
||||||
|
|
||||||
|
div.style.animationTimeline = "view(inline)";
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_approx_equals(parseFloat(getComputedStyle(div).opacity), 0.33333,
|
||||||
|
0.00001, 'At 66.7%');
|
||||||
|
await scrollLeft(container, 40);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.2', 'At 80%');
|
||||||
|
await scrollLeft(container, 100);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
|
||||||
|
div.style.animationTimeline = "view(inline 50px)";
|
||||||
|
await scrollLeft(container, 0);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0.25', 'At 75%');
|
||||||
|
await scrollLeft(container, 50);
|
||||||
|
assert_equals(getComputedStyle(div).opacity, '0', 'At 100%');
|
||||||
|
}, 'animation-timeline: view(inline) changes to view(inline 50px), without' +
|
||||||
|
'timeline range name');
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------
|
||||||
|
// Tests with timeline range name
|
||||||
|
// ---------------------------------
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
let [container, div] = createTargetWithStuff(t, ['content', 'target', 'content']);
|
let [container, div] = createTargetWithStuff(t, ['content', 'target', 'content']);
|
||||||
div.style.animation = "fade-in-out 1s linear";
|
div.style.animation = "fade-in-out 1s linear";
|
||||||
|
Loading…
Reference in New Issue
Block a user