Bug 1662013 - Introduce a ScrollPositionUpdate and plumb it in. r=tnikkel,botond

This adds a ScrollPositionUpdate class. Code in nsGfxScrollFrame creates
instances of these classes every time the scroll generation is incremented,
and saves them to an array. The array is sent in the scroll metadata to the
compositor as part of a paint transaction.

Currently this data is not used at all on the APZ side, and exists alongside
(independently of) the existing scroll fields, so this patch should not have
any functional effects.

Differential Revision: https://phabricator.services.mozilla.com/D88741
This commit is contained in:
Kartikaya Gupta 2020-09-12 13:05:53 +00:00
Родитель 1ef2a5628a
Коммит 378887e276
11 изменённых файлов: 309 добавлений и 7 удалений

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

@ -18,6 +18,7 @@
#include "mozilla/gfx/Logging.h" // for Log
#include "mozilla/layers/LayersTypes.h" // for ScrollDirection
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid
#include "mozilla/ScrollPositionUpdate.h" // for ScrollPositionUpdate
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "nsDataHashtable.h" // for nsDataHashtable
@ -933,7 +934,8 @@ struct ScrollMetadata {
mResolutionUpdated == aOther.mResolutionUpdated &&
mIsRDMTouchSimulationActive == aOther.mIsRDMTouchSimulationActive &&
mDisregardedDirection == aOther.mDisregardedDirection &&
mOverscrollBehavior == aOther.mOverscrollBehavior;
mOverscrollBehavior == aOther.mOverscrollBehavior &&
mScrollUpdates == aOther.mScrollUpdates;
}
bool operator!=(const ScrollMetadata& aOther) const {
@ -1035,6 +1037,10 @@ struct ScrollMetadata {
return mOverscrollBehavior;
}
void SetScrollUpdates(const nsTArray<ScrollPositionUpdate>& aUpdates) {
mScrollUpdates = aUpdates;
}
private:
FrameMetrics mMetrics;
@ -1110,6 +1116,10 @@ struct ScrollMetadata {
// The overscroll behavior for this scroll frame.
OverscrollBehaviorInfo mOverscrollBehavior;
// The ordered list of scroll position updates for this scroll frame since
// the last transaction.
CopyableTArray<ScrollPositionUpdate> mScrollUpdates;
// WARNING!!!!
//
// When adding new fields to ScrollMetadata, the following places should be

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

@ -498,6 +498,14 @@ void AppendToString(std::stringstream& aStream, ImageFormat format,
aStream << sfx;
}
void AppendToString(std::stringstream& aStream,
const mozilla::ScrollPositionUpdate& aUpdate,
const char* pfx, const char* sfx) {
aStream << pfx;
aUpdate.AppendToString(aStream);
aStream << sfx;
}
} // namespace layers
} // namespace mozilla

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

@ -276,6 +276,10 @@ void AppendToString(std::stringstream& aStream, gfx::SurfaceType format,
void AppendToString(std::stringstream& aStream, ImageFormat format,
const char* pfx = "", const char* sfx = "");
void AppendToString(std::stringstream& aStream,
const mozilla::ScrollPositionUpdate& aUpdate,
const char* pfx = "", const char* sfx = "");
// Sometimes, you just want a string from a single value.
template <typename T>
std::string Stringify(const T& obj) {

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

@ -400,6 +400,10 @@ struct ParamTraits<mozilla::layers::LayerClip> {
}
};
template <>
struct ParamTraits<mozilla::ScrollPositionUpdate>
: PlainOldDataSerializer<mozilla::ScrollPositionUpdate> {};
template <>
struct ParamTraits<mozilla::layers::ScrollMetadata>
: BitfieldHelper<mozilla::layers::ScrollMetadata> {
@ -422,6 +426,7 @@ struct ParamTraits<mozilla::layers::ScrollMetadata>
WriteParam(aMsg, aParam.mIsRDMTouchSimulationActive);
WriteParam(aMsg, aParam.mDisregardedDirection);
WriteParam(aMsg, aParam.mOverscrollBehavior);
WriteParam(aMsg, aParam.mScrollUpdates);
}
static bool ReadContentDescription(const Message* aMsg, PickleIterator* aIter,
@ -457,7 +462,8 @@ struct ParamTraits<mozilla::layers::ScrollMetadata>
ReadBoolForBitfield(aMsg, aIter, aResult,
&paramType::SetIsRDMTouchSimulationActive)) &&
ReadParam(aMsg, aIter, &aResult->mDisregardedDirection) &&
ReadParam(aMsg, aIter, &aResult->mOverscrollBehavior);
ReadParam(aMsg, aIter, &aResult->mOverscrollBehavior) &&
ReadParam(aMsg, aIter, &aResult->mScrollUpdates);
}
};

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

@ -9397,6 +9397,7 @@ ScrollMetadata nsLayoutUtils::ComputeScrollMetadata(
metadata.SetSnapInfo(scrollableFrame->GetScrollSnapInfo());
metadata.SetOverscrollBehavior(
scrollableFrame->GetOverscrollBehaviorInfo());
metadata.SetScrollUpdates(scrollableFrame->GetScrollUpdates());
}
// If we have the scrollparent being the same as the scroll id, the

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

@ -0,0 +1,127 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ScrollPositionUpdate.h"
#include "mozilla/Assertions.h"
namespace mozilla {
ScrollPositionUpdate::ScrollPositionUpdate()
: mScrollGeneration(0),
mType(ScrollUpdateType::Absolute),
mScrollMode(ScrollMode::Normal),
mScrollOrigin(ScrollOrigin::None) {}
/*static*/
ScrollPositionUpdate ScrollPositionUpdate::NewScrollframe(
uint32_t aGeneration) {
ScrollPositionUpdate ret;
ret.mScrollGeneration = aGeneration;
ret.mScrollMode = ScrollMode::Instant;
return ret;
}
/*static*/
ScrollPositionUpdate ScrollPositionUpdate::NewScroll(uint32_t aGeneration,
ScrollOrigin aOrigin,
nsPoint aDestination) {
MOZ_ASSERT(aOrigin != ScrollOrigin::NotSpecified);
MOZ_ASSERT(aOrigin != ScrollOrigin::None);
ScrollPositionUpdate ret;
ret.mScrollGeneration = aGeneration;
ret.mType = ScrollUpdateType::Absolute;
ret.mScrollMode = ScrollMode::Instant;
ret.mScrollOrigin = aOrigin;
ret.mDestination = CSSPoint::FromAppUnits(aDestination);
return ret;
}
/*static*/
ScrollPositionUpdate ScrollPositionUpdate::NewRelativeScroll(
uint32_t aGeneration, nsPoint aSource, nsPoint aDestination) {
ScrollPositionUpdate ret;
ret.mScrollGeneration = aGeneration;
ret.mType = ScrollUpdateType::Relative;
ret.mScrollMode = ScrollMode::Instant;
ret.mScrollOrigin = ScrollOrigin::Relative;
ret.mDestination = CSSPoint::FromAppUnits(aDestination);
ret.mSource = CSSPoint::FromAppUnits(aSource);
return ret;
}
/*static*/
ScrollPositionUpdate ScrollPositionUpdate::NewSmoothScroll(
uint32_t aGeneration, ScrollOrigin aOrigin, nsPoint aDestination) {
MOZ_ASSERT(aOrigin != ScrollOrigin::NotSpecified);
MOZ_ASSERT(aOrigin != ScrollOrigin::None);
ScrollPositionUpdate ret;
ret.mScrollGeneration = aGeneration;
ret.mType = ScrollUpdateType::Absolute;
ret.mScrollMode = ScrollMode::SmoothMsd;
ret.mScrollOrigin = aOrigin;
ret.mDestination = CSSPoint::FromAppUnits(aDestination);
return ret;
}
/*static*/
ScrollPositionUpdate ScrollPositionUpdate::NewPureRelativeScroll(
uint32_t aGeneration, ScrollOrigin aOrigin, ScrollMode aMode,
const nsPoint& aDelta) {
MOZ_ASSERT(aOrigin != ScrollOrigin::NotSpecified);
MOZ_ASSERT(aOrigin != ScrollOrigin::None);
ScrollPositionUpdate ret;
ret.mScrollGeneration = aGeneration;
ret.mType = ScrollUpdateType::PureRelative;
ret.mScrollMode = aMode;
ret.mScrollOrigin = aOrigin;
ret.mDelta = CSSPoint::FromAppUnits(aDelta);
return ret;
}
bool ScrollPositionUpdate::operator==(
const ScrollPositionUpdate& aOther) const {
// instances are immutable, and all the fields are set when the generation
// is set. So if the generation matches, these instances are identical.
return mScrollGeneration == aOther.mScrollGeneration;
}
uint32_t ScrollPositionUpdate::GetGeneration() const {
return mScrollGeneration;
}
ScrollUpdateType ScrollPositionUpdate::GetType() const { return mType; }
ScrollMode ScrollPositionUpdate::GetMode() const { return mScrollMode; }
ScrollOrigin ScrollPositionUpdate::GetOrigin() const { return mScrollOrigin; }
CSSPoint ScrollPositionUpdate::GetDestination() const {
MOZ_ASSERT(mType == ScrollUpdateType::Absolute ||
mType == ScrollUpdateType::Relative);
return mDestination;
}
CSSPoint ScrollPositionUpdate::GetSource() const {
MOZ_ASSERT(mType == ScrollUpdateType::Relative);
return mSource;
}
CSSPoint ScrollPositionUpdate::GetDelta() const {
MOZ_ASSERT(mType == ScrollUpdateType::PureRelative);
return mDelta;
}
void ScrollPositionUpdate::AppendToString(std::stringstream& aStream) const {
aStream << "ScrollPositionUpdate(gen=" << mScrollGeneration
<< ", type=" << (int)mType << ", mode=" << (int)mScrollMode
<< ", origin=" << (int)mScrollOrigin << ", dst=" << mDestination.x
<< "," << mDestination.y << ", src=" << mSource.x << "," << mSource.y
<< ", delta=" << mDelta.x << "," << mDelta.y << ")";
}
} // namespace mozilla

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

@ -0,0 +1,104 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ScrollPositionUpdate_h_
#define mozilla_ScrollPositionUpdate_h_
#include <cstdint>
#include "nsPoint.h"
#include "mozilla/ScrollOrigin.h"
#include "mozilla/ScrollTypes.h"
#include "Units.h"
namespace mozilla {
enum class ScrollUpdateType {
// A scroll update to a specific destination, regardless of the current
// scroll position.
Absolute,
// A scroll update by a specific amount, based off a given starting scroll
// position. XXX Fold this into PureRelative, it should be relatively
// straightforward after bug 1655733.
Relative,
// A scroll update by a specific amount, where only the delta is provided.
// The delta should be applied to whatever the current scroll position is
// on the receiver side.
PureRelative,
};
/**
* This class represents an update to the scroll position that is initiated by
* something on the main thread. A list of these classes is accumulated by
* scrollframes on the main thread, and the list is sent over as part of a
* paint transaction to the compositor. The compositor can then iterate through
* the scroll updates and apply/merge them with scrolling that has already
* occurred independently on the compositor side.
*/
class ScrollPositionUpdate {
public:
// Constructor for IPC use only.
explicit ScrollPositionUpdate();
// Create a ScrollPositionUpdate for a newly created (or reconstructed)
// scrollframe.
static ScrollPositionUpdate NewScrollframe(uint32_t aGeneration);
// Create a ScrollPositionUpdate for a new absolute/instant scroll, to
// the given destination.
static ScrollPositionUpdate NewScroll(uint32_t aGeneration,
ScrollOrigin aOrigin,
nsPoint aDestination);
// Create a ScrollPositionUpdate for a new relative/instant scroll, with
// the given source/destination.
static ScrollPositionUpdate NewRelativeScroll(uint32_t aGeneration,
nsPoint aSource,
nsPoint aDestination);
// Create a ScrollPositionUpdate for a new absolute/smooth scroll, which
// animates smoothly to the given destination from whatever the current
// scroll position is in the receiver.
static ScrollPositionUpdate NewSmoothScroll(uint32_t aGeneration,
ScrollOrigin aOrigin,
nsPoint aDestination);
// Create a ScrollPositionUpdate for a new pure-relative scroll. The
// aMode parameter controls whether or not this is a smooth animation or
// instantaneous scroll.
static ScrollPositionUpdate NewPureRelativeScroll(uint32_t aGeneration,
ScrollOrigin aOrigin,
ScrollMode aMode,
const nsPoint& aDelta);
bool operator==(const ScrollPositionUpdate& aOther) const;
uint32_t GetGeneration() const;
ScrollUpdateType GetType() const;
ScrollMode GetMode() const;
ScrollOrigin GetOrigin() const;
// GetDestination is only valid for Absolute and Relative types; it asserts
// otherwise.
CSSPoint GetDestination() const;
// GetSource is only valid for the Relative type; it asserts otherwise.
CSSPoint GetSource() const;
// GetDelta is only valid for the PureRelative type; it asserts otherwise.
CSSPoint GetDelta() const;
void AppendToString(std::stringstream& aStream) const;
private:
uint32_t mScrollGeneration;
// Refer to the ScrollUpdateType documentation for what the types mean.
// All fields are populated for all types, except as noted below.
ScrollUpdateType mType;
ScrollMode mScrollMode;
ScrollOrigin mScrollOrigin;
// mDestination is not populated when mType == PureRelative.
CSSPoint mDestination;
// mSource is not populated when mType == Absolute || mType == PureRelative.
CSSPoint mSource;
// mDelta is not populated when mType == Absolute || mType == Relative.
CSSPoint mDelta;
};
} // namespace mozilla
#endif // mozilla_ScrollPositionUpdate_h_

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

@ -152,6 +152,7 @@ EXPORTS.mozilla += [
'ReflowOutput.h',
'ScrollbarPreferences.h',
'ScrollOrigin.h',
'ScrollPositionUpdate.h',
'ViewportFrame.h',
'WritingModes.h',
]
@ -222,6 +223,7 @@ UNIFIED_SOURCES += [
'ScrollAnimationBezierPhysics.cpp',
'ScrollAnimationMSDPhysics.cpp',
'ScrollbarActivity.cpp',
'ScrollPositionUpdate.cpp',
'ScrollSnap.cpp',
'ScrollVelocityQueue.cpp',
'StickyScrollContainer.cpp',

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

@ -2279,6 +2279,9 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot)
mProcessingScrollEvent(false),
mApzAnimationInProgress(false),
mVelocityQueue(aOuter->PresContext()) {
mScrollUpdates.AppendElement(
ScrollPositionUpdate::NewScrollframe(mScrollGeneration));
if (LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0) {
mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
}
@ -3028,6 +3031,17 @@ void ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange,
mRelativeOffset.reset();
}
mScrollGeneration = ++sScrollGenerationCounter;
if (aOrigin == ScrollOrigin::Relative) {
MOZ_ASSERT(!isScrollOriginDowngrade);
MOZ_ASSERT(mLastScrollOrigin == ScrollOrigin::Relative);
mScrollUpdates.AppendElement(ScrollPositionUpdate::NewRelativeScroll(
mScrollGeneration, mApzScrollPos, pt));
} else if (aOrigin != ScrollOrigin::Apz) {
mScrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
mScrollGeneration, mLastScrollOrigin, pt));
}
if (mLastScrollOrigin == ScrollOrigin::Apz) {
mApzScrollPos = GetScrollPosition();
}
@ -4571,15 +4585,17 @@ void ScrollFrameHelper::ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit,
if (mRelativeOffset.isNothing()) {
mRelativeOffset = Some(nsPoint(0, 0));
}
mRelativeOffset->x = NSCoordSaturatingAdd(
mRelativeOffset->x,
NSCoordSaturatingNonnegativeMultiply(aDelta.x, deltaMultiplier.width));
mRelativeOffset->y = NSCoordSaturatingAdd(
mRelativeOffset->y,
nsPoint delta(
NSCoordSaturatingNonnegativeMultiply(aDelta.x, deltaMultiplier.width),
NSCoordSaturatingNonnegativeMultiply(aDelta.y, deltaMultiplier.height));
mRelativeOffset->x = NSCoordSaturatingAdd(mRelativeOffset->x, delta.x);
mRelativeOffset->y = NSCoordSaturatingAdd(mRelativeOffset->y, delta.y);
mScrollGeneration = ++sScrollGenerationCounter;
mScrollUpdates.AppendElement(ScrollPositionUpdate::NewPureRelativeScroll(
mScrollGeneration, aOrigin, aMode, delta));
if (!nsLayoutUtils::HasDisplayPort(mOuter->GetContent())) {
if (MOZ_LOG_TEST(sDisplayportLog, LogLevel::Debug)) {
mozilla::layers::ScrollableLayerGuid::ViewID viewID =
@ -7594,6 +7610,9 @@ void ScrollFrameHelper::ApzSmoothScrollTo(const nsPoint& aDestination,
mApzSmoothScrollDestination = Some(aDestination);
mScrollGeneration = ++sScrollGenerationCounter;
mScrollUpdates.AppendElement(ScrollPositionUpdate::NewSmoothScroll(
mScrollGeneration, aOrigin, aDestination));
if (!nsLayoutUtils::HasDisplayPort(mOuter->GetContent())) {
// If this frame doesn't have a displayport then there won't be an
// APZC instance for it and so there won't be anything to process
@ -7663,3 +7682,7 @@ bool ScrollFrameHelper::IsSmoothScroll(dom::ScrollBehavior aBehavior) const {
styleFrame->StyleDisplay()->mScrollBehavior ==
StyleScrollBehavior::Smooth);
}
nsTArray<ScrollPositionUpdate> ScrollFrameHelper::GetScrollUpdates() const {
return mScrollUpdates.Clone();
}

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

@ -443,6 +443,7 @@ class ScrollFrameHelper : public nsIReflowCallback {
mAllowScrollOriginDowngrade = true;
mApzScrollPos = GetScrollPosition();
mRelativeOffset.reset();
mScrollUpdates.Clear();
}
void NotifyApproximateFrameVisibilityUpdate(bool aIgnoreDisplayPort);
bool GetDisplayPortAtLastApproximateFrameVisibilityUpdate(
@ -464,6 +465,7 @@ class ScrollFrameHelper : public nsIReflowCallback {
bool IsApzAnimationInProgress() const { return mApzAnimationInProgress; }
uint32_t CurrentScrollGeneration() const { return mScrollGeneration; }
nsPoint LastScrollDestination() const { return mDestination; }
nsTArray<ScrollPositionUpdate> GetScrollUpdates() const;
using IncludeApzAnimation = nsIScrollableFrame::IncludeApzAnimation;
bool IsScrollAnimating(IncludeApzAnimation = IncludeApzAnimation::Yes) const;
@ -569,6 +571,9 @@ class ScrollFrameHelper : public nsIReflowCallback {
ScrollOrigin mLastSmoothScrollOrigin;
Maybe<nsPoint> mApzSmoothScrollDestination;
uint32_t mScrollGeneration;
nsTArray<ScrollPositionUpdate> mScrollUpdates;
// NOTE: On mobile this value might be factoring into overflow:hidden region
// in the case of the top level document.
nsRect mScrollPort;
@ -1066,6 +1071,9 @@ class nsHTMLScrollFrame : public nsContainerFrame,
nsPoint LastScrollDestination() final {
return mHelper.LastScrollDestination();
}
nsTArray<mozilla::ScrollPositionUpdate> GetScrollUpdates() const final {
return mHelper.GetScrollUpdates();
}
void ResetScrollInfoIfNeeded(uint32_t aGeneration,
bool aApzAnimationInProgress) final {
mHelper.ResetScrollInfoIfNeeded(aGeneration, aApzAnimationInProgress);
@ -1544,6 +1552,9 @@ class nsXULScrollFrame final : public nsBoxFrame,
nsPoint LastScrollDestination() final {
return mHelper.LastScrollDestination();
}
nsTArray<mozilla::ScrollPositionUpdate> GetScrollUpdates() const final {
return mHelper.GetScrollUpdates();
}
void ResetScrollInfoIfNeeded(uint32_t aGeneration,
bool aApzAnimationInProgress) final {
mHelper.ResetScrollInfoIfNeeded(aGeneration, aApzAnimationInProgress);

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

@ -15,6 +15,7 @@
#include "mozilla/dom/WindowBinding.h" // for mozilla::dom::ScrollBehavior
#include "mozilla/Maybe.h"
#include "mozilla/ScrollOrigin.h"
#include "mozilla/ScrollPositionUpdate.h"
#include "mozilla/ScrollStyles.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/gfx/Point.h"
@ -460,6 +461,11 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
* requested smooth scroll animation.
*/
virtual nsPoint LastScrollDestination() = 0;
/**
* Returns the list of scroll position updates since the last call to
* NotifyApzTransaction().
*/
virtual nsTArray<mozilla::ScrollPositionUpdate> GetScrollUpdates() const = 0;
/**
* Clears the "origin of last scroll" property stored in this frame, if
* the generation counter passed in matches the current scroll generation