Bug 1676791 - Part 3: Implement the computation of timing. r=hiro

This patch focus on the timing computation of animation effects. We have
to compute the correct progress based on the scroll offsets. Now we
simplify the implementation only from 0% to 100%. The test cases will be
added in the last patch once we hook the scroll timeline to the CSS
animation.

Differential Revision: https://phabricator.services.mozilla.com/D129101
This commit is contained in:
Boris Chiou 2021-12-08 01:16:29 +00:00
Родитель 8604a51732
Коммит 193a6c3d7a
5 изменённых файлов: 96 добавлений и 6 удалений

Просмотреть файл

@ -441,6 +441,10 @@ class Animation : public DOMEventTargetHelper,
PostUpdate();
}
bool UsingScrollTimeline() const {
return mTimeline && mTimeline->IsScrollTimeline();
}
protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void CancelNoUpdate();

Просмотреть файл

@ -8,7 +8,9 @@
#define mozilla_dom_AnimationEffect_h
#include "mozilla/ComputedTiming.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/ScrollTimeline.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TimingParams.h"
#include "nsCycleCollectionParticipant.h"
@ -19,7 +21,6 @@ class ErrorResult;
namespace dom {
class Animation;
class KeyframeEffect;
struct ComputedEffectTiming;
struct EffectTiming;
@ -49,7 +50,15 @@ class AnimationEffect : public nsISupports, public nsWrapperCache {
virtual void UpdateTiming(const OptionalEffectTiming& aTiming,
ErrorResult& aRv);
const TimingParams& SpecifiedTiming() const { return mTiming; }
const TimingParams& SpecifiedTiming() const {
return mAnimation && mAnimation->UsingScrollTimeline()
// This returns the TimingParams which is used for getting
// ComputedTiming. For now, we assume all the callers of
// SpecifiedTiming() want to use this for scroll-timelines
// (and let the animation events be an undefined part).
? ScrollTimeline::GetTiming()
: mTiming;
}
void SetSpecifiedTiming(TimingParams&& aTiming);
// This function takes as input the timing parameters of an animation and

Просмотреть файл

@ -101,6 +101,8 @@ class AnimationTimeline : public nsISupports, public nsWrapperCache {
virtual Document* GetDocument() const = 0;
virtual bool IsScrollTimeline() const { return false; }
protected:
nsCOMPtr<nsIGlobalObject> mWindow;

Просмотреть файл

@ -8,6 +8,9 @@
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Document.h"
#include "nsIFrame.h"
#include "nsIScrollableFrame.h"
#include "nsLayoutUtils.h"
namespace mozilla::dom {
@ -54,6 +57,39 @@ ScrollTimeline::ScrollTimeline(Document* aDocument, Element* aScroller)
RegisterWithScrollSource();
}
Nullable<TimeDuration> ScrollTimeline::GetCurrentTimeAsDuration() const {
const nsIFrame* frame = nsLayoutUtils::GetScrollFrameFromContent(mSource);
const nsIScrollableFrame* scrollFrame =
frame ? frame->GetScrollTargetFrame() : nullptr;
if (!scrollFrame) {
return nullptr;
}
const auto orientation = GetPhysicalOrientation(frame->GetWritingMode());
// If this orientation is not ready for scrolling (i.e. the scroll range is
// not larger than or equal to one device pixel), we make it 100%.
if (!scrollFrame->GetAvailableScrollingDirections().contains(orientation)) {
return TimeDuration::FromMilliseconds(SCROLL_TIMELINE_DURATION_MILLISEC);
}
const nsPoint& scrollOffset = scrollFrame->GetScrollPosition();
const nsRect& scrollRange = scrollFrame->GetScrollRange();
const bool isHorizontal = orientation == layers::ScrollDirection::eHorizontal;
// Note: For RTL, scrollOffset.x or scrollOffset.y may be negative, e.g. the
// range of its value is [0, -range], so we have to use the absolute value.
double position = std::abs(isHorizontal ? scrollOffset.x : scrollOffset.y);
double range = isHorizontal ? scrollRange.width : scrollRange.height;
MOZ_ASSERT(range > 0.0);
// Use the definition of interval progress to compute the progress.
// Note: We simplify the scroll offsets to [0%, 100%], so offset weight and
// offset index are ignored here.
// https://drafts.csswg.org/scroll-animations-1/#progress-calculation-algorithm
double progress = position / range;
return TimeDuration::FromMilliseconds(progress *
SCROLL_TIMELINE_DURATION_MILLISEC);
}
void ScrollTimeline::RegisterWithScrollSource() {
if (!mSource) {
return;

Просмотреть файл

@ -10,6 +10,10 @@
#include "mozilla/dom/AnimationTimeline.h"
#include "mozilla/HashTable.h"
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/TimingParams.h"
#include "mozilla/WritingModes.h"
#define SCROLL_TIMELINE_DURATION_MILLISEC 100000
namespace mozilla {
namespace dom {
@ -71,10 +75,7 @@ class ScrollTimeline final : public AnimationTimeline {
}
// AnimationTimeline methods.
Nullable<TimeDuration> GetCurrentTimeAsDuration() const override {
// FIXME: We will update this function in the patch series.
return nullptr;
}
Nullable<TimeDuration> GetCurrentTimeAsDuration() const override;
bool TracksWallclockTime() const override { return false; }
Nullable<TimeDuration> ToTimelineTime(
const TimeStamp& aTimeStamp) const override {
@ -88,6 +89,7 @@ class ScrollTimeline final : public AnimationTimeline {
return {};
}
Document* GetDocument() const override { return mDocument; }
bool IsScrollTimeline() const override { return true; }
void ScheduleAnimations() {
// FIXME: Bug 1737927: Need to check the animation mutation observers for
@ -97,6 +99,19 @@ class ScrollTimeline final : public AnimationTimeline {
Tick();
}
static const TimingParams& GetTiming() {
// Use default values except for mDuration and mFill.
// Use a fixed duration defined in SCROLL_TIMELINE_DURATIONMILLISEC, and use
// FillMode::Both to make sure the animation is in effect at 100%.
// Note: it's unfortunate TimingParams cannot be a const variable because
// we have to use StickyTimingDuration::FromMilliseconds() in its
// constructor.
static TimingParams sTiming =
TimingParams(SCROLL_TIMELINE_DURATION_MILLISEC, 0.0, 1.0,
PlaybackDirection::Normal, FillMode::Both);
return sTiming;
}
protected:
virtual ~ScrollTimeline() { Teardown(); }
@ -110,7 +125,31 @@ class ScrollTimeline final : public AnimationTimeline {
void RegisterWithScrollSource();
void UnregisterFromScrollSource();
// A helper to get the physical orientation of this scroll-timeline.
//
// The spec defines auto, but there is a spec issue:
// "ISSUE 5 Define these values." in this section. The DOM interface removed
// auto and use block as default value, so we treat auto as block now.
// https://drafts.csswg.org/scroll-animations-1/#descdef-scroll-timeline-orientation
layers::ScrollDirection GetPhysicalOrientation(WritingMode aWM) const {
return mDirection == StyleScrollDirection::Horizontal ||
(!aWM.IsVertical() &&
mDirection == StyleScrollDirection::Inline) ||
(aWM.IsVertical() &&
(mDirection == StyleScrollDirection::Block ||
mDirection == StyleScrollDirection::Auto))
? layers::ScrollDirection::eHorizontal
: layers::ScrollDirection::eVertical;
}
RefPtr<Document> mDocument;
// FIXME: Bug 1733260: new spec proposal uses a new way to define scroller,
// and move the element-based offset into view-timeline, so here we only
// implement the default behavior of scroll timeline:
// 1. "source" is auto (use main viewport scroller), and
// 2. "scroll-offsets" is none (i.e. always 0% ~ 100%).
// So now we will only use the scroll direction from @scroll-timeline rule.
RefPtr<Element> mSource;
StyleScrollDirection mDirection;
};