--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -883,36 +883,47 @@ Element::ScrollTo(const ScrollToOptions&
Scroll(aOptions);
}
void
Element::ScrollBy(double aXScrollDif, double aYScrollDif)
{
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
- CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
- scrollPos += CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
- mozilla::ToZeroIfNonfinite(aYScrollDif));
- Scroll(scrollPos, ScrollOptions());
+ ScrollToOptions options;
+ options.mLeft.Construct(aXScrollDif);
+ options.mTop.Construct(aYScrollDif);
+ ScrollBy(options);
}
}
void
Element::ScrollBy(const ScrollToOptions& aOptions)
{
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
- CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
+ CSSIntPoint scrollDelta;
if (aOptions.mLeft.WasPassed()) {
- scrollPos.x += mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
+ scrollDelta.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
}
if (aOptions.mTop.WasPassed()) {
- scrollPos.y += mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
+ scrollDelta.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
}
- Scroll(scrollPos, aOptions);
+
+ nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
+ if (aOptions.mBehavior == ScrollBehavior::Smooth) {
+ scrollMode = nsIScrollableFrame::SMOOTH_MSD;
+ } else if (aOptions.mBehavior == ScrollBehavior::Auto) {
+ ScrollStyles styles = sf->GetScrollStyles();
+ if (styles.mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
+ scrollMode = nsIScrollableFrame::SMOOTH_MSD;
+ }
+ }
+
+ sf->ScrollByCSSPixels(scrollDelta, scrollMode, nsGkAtoms::relative);
}
}
int32_t
Element::ScrollTop()
{
nsIScrollableFrame* sf = GetScrollFrame();
return sf ? sf->GetScrollPositionCSSPixels().y : 0;
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -3937,42 +3937,52 @@ nsGlobalWindowInner::ScrollTo(const CSSI
void
nsGlobalWindowInner::ScrollBy(double aXScrollDif, double aYScrollDif)
{
FlushPendingNotifications(FlushType::Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
- // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
- auto scrollDif = CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),
- mozilla::ToZeroIfNonfinite(aYScrollDif));
// It seems like it would make more sense for ScrollBy to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
- ScrollTo(sf->GetScrollPositionCSSPixels() + scrollDif, ScrollOptions());
+ ScrollToOptions options;
+ options.mLeft.Construct(aXScrollDif);
+ options.mTop.Construct(aYScrollDif);
+ ScrollBy(options);
}
}
void
nsGlobalWindowInner::ScrollBy(const ScrollToOptions& aOptions)
{
FlushPendingNotifications(FlushType::Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
- CSSIntPoint scrollPos = sf->GetScrollPositionCSSPixels();
+ CSSIntPoint scrollDelta;
if (aOptions.mLeft.WasPassed()) {
- scrollPos.x += mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
+ scrollDelta.x = mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());
}
if (aOptions.mTop.WasPassed()) {
- scrollPos.y += mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
- }
-
- ScrollTo(scrollPos, aOptions);
+ scrollDelta.y = mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());
+ }
+
+ nsIScrollableFrame::ScrollMode scrollMode = nsIScrollableFrame::INSTANT;
+ if (aOptions.mBehavior == ScrollBehavior::Smooth) {
+ scrollMode = nsIScrollableFrame::SMOOTH_MSD;
+ } else if (aOptions.mBehavior == ScrollBehavior::Auto) {
+ ScrollStyles styles = sf->GetScrollStyles();
+ if (styles.mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_SMOOTH) {
+ scrollMode = nsIScrollableFrame::SMOOTH_MSD;
+ }
+ }
+
+ sf->ScrollByCSSPixels(scrollDelta, scrollMode, nsGkAtoms::relative);
}
}
void
nsGlobalWindowInner::ScrollByLines(int32_t numLines,
const ScrollOptions& aOptions)
{
FlushPendingNotifications(FlushType::Layout);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1520,17 +1520,17 @@ ScrollFrameHelper::ThumbMoved(nsScrollba
// Don't try to scroll if we're already at an acceptable place.
// Don't call Contains here since Contains returns false when the point is
// on the bottom or right edge of the rectangle.
if (allowedRange.ClampPoint(current) == current) {
return;
}
- ScrollTo(dest, nsIScrollableFrame::INSTANT, &allowedRange);
+ ScrollTo(dest, nsIScrollableFrame::INSTANT, nsGkAtoms::other, &allowedRange);
}
void
ScrollFrameHelper::ScrollbarReleased(nsScrollbarFrame* aScrollbar)
{
// Scrollbar scrolling does not result in fling gestures, clear any
// accumulated velocity
mVelocityQueue.Reset();
@@ -2289,18 +2289,34 @@ ScrollFrameHelper::HasPluginFrames()
bool
ScrollFrameHelper::HasBgAttachmentLocal() const
{
const nsStyleBackground* bg = mOuter->StyleBackground();
return bg->HasLocalBackground();
}
void
+ScrollFrameHelper::ScrollTo(nsPoint aScrollPosition,
+ nsIScrollableFrame::ScrollMode aMode,
+ nsAtom* aOrigin,
+ const nsRect* aRange,
+ nsIScrollbarMediator::ScrollSnapMode aSnap)
+{
+ if (aOrigin == nullptr) {
+ aOrigin = nsGkAtoms::other;
+ }
+ ScrollToWithOrigin(aScrollPosition, aMode,
+ aOrigin, aRange,
+ aSnap);
+}
+
+void
ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
- nsIScrollableFrame::ScrollMode aMode)
+ nsIScrollableFrame::ScrollMode aMode,
+ nsAtom* aOrigin)
{
nsPoint current = GetScrollPosition();
CSSIntPoint currentCSSPixels = GetScrollPositionCSSPixels();
nsPoint pt = CSSPoint::ToAppUnits(aScrollPosition);
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2*halfPixel - 1, 2*halfPixel - 1);
// XXX I don't think the following blocks are needed anymore, now that
// ScrollToImpl simply tries to scroll an integer number of layer
@@ -2310,17 +2326,20 @@ ScrollFrameHelper::ScrollToCSSPixels(con
range.x = pt.x;
range.width = 0;
}
if (currentCSSPixels.y == aScrollPosition.y) {
pt.y = current.y;
range.y = pt.y;
range.height = 0;
}
- ScrollTo(pt, aMode, &range);
+ if (aOrigin == nullptr) {
+ aOrigin = nsGkAtoms::other;
+ }
+ ScrollTo(pt, aMode, aOrigin, &range);
// 'this' might be destroyed here
}
void
ScrollFrameHelper::ScrollToCSSPixelsApproximate(const CSSPoint& aScrollPosition,
nsAtom *aOrigin)
{
nsPoint pt = CSSPoint::ToAppUnits(aScrollPosition);
@@ -4224,17 +4243,17 @@ ScrollFrameHelper::ScrollBy(nsIntPoint a
}
case nsIScrollableFrame::WHOLE: {
nsPoint pos = GetScrollPosition();
AdjustForWholeDelta(aDelta.x, &pos.x);
AdjustForWholeDelta(aDelta.y, &pos.y);
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
GetSnapPointForDestination(aUnit, mDestination, pos);
}
- ScrollTo(pos, aMode);
+ ScrollTo(pos, aMode, nsGkAtoms::other);
// 'this' might be destroyed here
if (aOverflow) {
*aOverflow = nsIntPoint(0, 0);
}
return;
}
default:
NS_ERROR("Invalid scroll mode");
@@ -4290,16 +4309,46 @@ ScrollFrameHelper::ScrollBy(nsIntPoint a
!nsLayoutUtils::AsyncPanZoomEnabled(mOuter)) {
// When APZ is disabled, we must track the velocity
// on the main thread; otherwise, the APZC will manage this.
mVelocityQueue.Sample(GetScrollPosition());
}
}
void
+ScrollFrameHelper::ScrollByCSSPixels(const CSSIntPoint& aDelta,
+ nsIScrollableFrame::ScrollMode aMode,
+ nsAtom* aOrigin)
+{
+ nsPoint current = GetScrollPosition();
+ nsPoint pt = current + CSSPoint::ToAppUnits(aDelta);
+ nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
+ nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2*halfPixel - 1, 2*halfPixel - 1);
+ // XXX I don't think the following blocks are needed anymore, now that
+ // ScrollToImpl simply tries to scroll an integer number of layer
+ // pixels from the current position
+ if (aDelta.x == 0.0f) {
+ pt.x = current.x;
+ range.x = pt.x;
+ range.width = 0;
+ }
+ if (aDelta.y == 0.0f) {
+ pt.y = current.y;
+ range.y = pt.y;
+ range.height = 0;
+ }
+ if (aOrigin == nullptr) {
+ aOrigin = nsGkAtoms::other;
+ }
+ ScrollToWithOrigin(pt, aMode, aOrigin, &range,
+ nsIScrollbarMediator::DISABLE_SNAP);
+ // 'this' might be destroyed here
+}
+
+void
ScrollFrameHelper::ScrollSnap(nsIScrollableFrame::ScrollMode aMode)
{
float flingSensitivity = gfxPrefs::ScrollSnapPredictionSensitivity();
int maxVelocity = gfxPrefs::ScrollSnapPredictionMaxVelocity();
maxVelocity = nsPresContext::CSSPixelsToAppUnits(maxVelocity);
int maxOffset = maxVelocity * flingSensitivity;
nsPoint velocity = mVelocityQueue.GetVelocity();
// Multiply each component individually to avoid integer multiply
@@ -4316,17 +4365,17 @@ ScrollFrameHelper::ScrollSnap(const nsPo
nsIScrollableFrame::ScrollMode aMode)
{
nsRect scrollRange = GetScrollRangeForClamping();
nsPoint pos = GetScrollPosition();
nsPoint snapDestination = scrollRange.ClampPoint(aDestination);
if (GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS,
pos,
snapDestination)) {
- ScrollTo(snapDestination, aMode);
+ ScrollTo(snapDestination, aMode, nsGkAtoms::other);
}
}
nsSize
ScrollFrameHelper::GetLineScrollAmount() const
{
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetInflatedFontMetricsForFrame(mOuter);
@@ -6615,17 +6664,17 @@ ScrollFrameHelper::DragScroll(WidgetEven
offset.y = margin;
if (scrollPoint.y < rangeRect.height) {
willScroll = true;
}
}
}
if (offset.x || offset.y) {
- ScrollTo(GetScrollPosition() + offset, nsIScrollableFrame::NORMAL);
+ ScrollTo(GetScrollPosition() + offset, nsIScrollableFrame::NORMAL, nsGkAtoms::other);
}
return willScroll;
}
static void
AsyncScrollbarDragRejected(nsIFrame* aScrollbar)
{
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -232,28 +232,27 @@ public:
mozilla::TimeDuration aDeltaTime);
/**
* @note This method might destroy the frame, pres shell and other objects.
* aRange is the range of allowable scroll positions around the desired
* aScrollPosition. Null means only aScrollPosition is allowed.
* This is a closed-ended range --- aRange.XMost()/aRange.YMost() are allowed.
*/
void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode,
+ nsAtom* aOrigin = nullptr,
const nsRect* aRange = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap
- = nsIScrollbarMediator::DISABLE_SNAP) {
- ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange,
- aSnap);
- }
+ = nsIScrollbarMediator::DISABLE_SNAP);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
nsIScrollableFrame::ScrollMode aMode
- = nsIScrollableFrame::INSTANT);
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsAtom* aOrigin = nullptr);
CSSIntPoint GetScrollPositionCSSPixels();
/**
@@ -265,16 +264,20 @@ public:
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow,
nsAtom* aOrigin = nullptr,
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
nsIScrollbarMediator::ScrollSnapMode aSnap
= nsIScrollbarMediator::DISABLE_SNAP);
+ void ScrollByCSSPixels(const CSSIntPoint& aDelta,
+ nsIScrollableFrame::ScrollMode aMode
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToRestoredPosition();
enum class LoadingState {
Loading,
Stopped,
@@ -872,25 +875,26 @@ public:
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
const nsRect* aRange = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap
= nsIScrollbarMediator::DISABLE_SNAP)
override {
- mHelper.ScrollTo(aScrollPosition, aMode, aRange, aSnap);
+ mHelper.ScrollTo(aScrollPosition, aMode, nsGkAtoms::other, aRange, aSnap);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
nsIScrollableFrame::ScrollMode aMode
- = nsIScrollableFrame::INSTANT) override {
- mHelper.ScrollToCSSPixels(aScrollPosition, aMode);
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) override {
+ mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aOrigin);
}
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition, aOrigin);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
@@ -903,16 +907,22 @@ public:
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow, nsAtom* aOrigin = nullptr,
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
nsIScrollbarMediator::ScrollSnapMode aSnap
= nsIScrollbarMediator::DISABLE_SNAP)
override {
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
}
+ virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
+ nsIScrollableFrame::ScrollMode aMode
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) override {
+ mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin);
+ }
virtual void ScrollSnap() override {
mHelper.ScrollSnap();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToRestoredPosition() override {
mHelper.ScrollToRestoredPosition();
@@ -1326,25 +1336,26 @@ public:
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
const nsRect* aRange = nullptr,
ScrollSnapMode aSnap = nsIScrollbarMediator::DISABLE_SNAP)
override {
- mHelper.ScrollTo(aScrollPosition, aMode, aRange, aSnap);
+ mHelper.ScrollTo(aScrollPosition, aMode, nsGkAtoms::other, aRange, aSnap);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
nsIScrollableFrame::ScrollMode aMode
- = nsIScrollableFrame::INSTANT) override {
- mHelper.ScrollToCSSPixels(aScrollPosition, aMode);
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) override {
+ mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aOrigin);
}
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition, aOrigin);
}
virtual CSSIntPoint GetScrollPositionCSSPixels() override {
return mHelper.GetScrollPositionCSSPixels();
}
@@ -1354,16 +1365,22 @@ public:
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow, nsAtom* aOrigin = nullptr,
nsIScrollableFrame::ScrollMomentum aMomentum = nsIScrollableFrame::NOT_MOMENTUM,
nsIScrollbarMediator::ScrollSnapMode aSnap
= nsIScrollbarMediator::DISABLE_SNAP)
override {
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin, aMomentum, aSnap);
}
+ virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
+ nsIScrollableFrame::ScrollMode aMode
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) override {
+ mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin);
+ }
virtual void ScrollSnap() override {
mHelper.ScrollSnap();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollToRestoredPosition() override {
mHelper.ScrollToRestoredPosition();
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -236,17 +236,18 @@ public:
*
* When aMode is SMOOTH_MSD, intermediate animation frames may be outside the
* range and / or moving in any direction; GetScrollPositionCSSPixels will be
* exactly aScrollPosition at the end of the scroll animation unless the
* SMOOTH_MSD animation is interrupted.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
nsIScrollableFrame::ScrollMode aMode
- = nsIScrollableFrame::INSTANT) = 0;
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) = 0;
/**
* @note This method might destroy the frame, pres shell and other objects.
* Scrolls to a particular position in float CSS pixels.
* This does not guarantee that GetScrollPositionCSSPixels equals
* aScrollPosition afterward. It tries to scroll as close to
* aScrollPosition as possible while scrolling by an integer
* number of layer pixels (so the operation is fast and looks clean).
*/
@@ -274,16 +275,21 @@ public:
*/
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow = nullptr,
nsAtom* aOrigin = nullptr,
ScrollMomentum aMomentum = NOT_MOMENTUM,
nsIScrollbarMediator::ScrollSnapMode aSnap
= nsIScrollbarMediator::DISABLE_SNAP) = 0;
+ virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
+ nsIScrollableFrame::ScrollMode aMode
+ = nsIScrollableFrame::INSTANT,
+ nsAtom* aOrigin = nullptr) = 0;
+
/**
* Perform scroll snapping, possibly resulting in a smooth scroll to
* maintain the scroll snap position constraints. Velocity sampled from
* main thread scrolling is used to determine best matching snap point
* when called after a fling gesture on a trackpad or mouse wheel.
*/
virtual void ScrollSnap() = 0;