Commit 193a6c3d authored by Boris Chiou's avatar Boris Chiou
Browse files

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
parent 8604a517
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -441,6 +441,10 @@ class Animation : public DOMEventTargetHelper,
    PostUpdate();
  }

  bool UsingScrollTimeline() const {
    return mTimeline && mTimeline->IsScrollTimeline();
  }

 protected:
  void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
  void CancelNoUpdate();
+11 −2
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;

+36 −0
Original line number Diff line number Diff line
@@ -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;
+43 −4
Original line number Diff line number Diff line
@@ -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;
};