Bug 949132 - Add a flag to FrameMetrics indicating a non-APZ scroll (original patch by mstange). r=tn

This commit is contained in:
Kartikaya Gupta 2013-12-16 12:04:45 -05:00
parent b85de8fde7
commit 4ad1847fb9
10 changed files with 94 additions and 51 deletions

View File

@ -87,6 +87,7 @@ GK_ATOM(applet, "applet")
GK_ATOM(applyImports, "apply-imports")
GK_ATOM(applyTemplates, "apply-templates")
GK_ATOM(mozapptype, "mozapptype")
GK_ATOM(apz, "apz")
GK_ATOM(archive, "archive")
GK_ATOM(area, "area")
GK_ATOM(arrow, "arrow")

View File

@ -1636,23 +1636,6 @@ nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aSc
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ScrollToCSSPixelsApproximate(float aX, float aY, bool* aRetVal)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsIScrollableFrame* sf = static_cast<nsGlobalWindow*>(window.get())->GetScrollFrame();
if (sf) {
sf->ScrollToCSSPixelsApproximate(CSSPoint(aX, aY));
}
if (aRetVal) {
*aRetVal = (sf != nullptr);
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, float* aScrollY)
{

View File

@ -43,7 +43,7 @@ interface nsIDOMEventTarget;
interface nsIRunnable;
interface nsICompositionStringSynthesizer;
[scriptable, uuid(38740b7e-095e-4198-a012-cf5f9e102a6a)]
[scriptable, uuid(c6efd629-7282-4f0d-9db8-0fa59c191dd5)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -750,13 +750,6 @@ interface nsIDOMWindowUtils : nsISupports {
*/
void getScrollXYFloat(in boolean aFlushLayout, out float aScrollX, out float aScrollY);
/**
* Sets the scroll position of the root scroll frame of the window.
* Returns true on success, false on error (if the window didn't have a root
* scroll frame).
*/
boolean scrollToCSSPixelsApproximate(in float aX, in float aY);
/**
* Returns the scrollbar width of the window's scroll frame.
*

View File

@ -585,6 +585,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mPresShellId);
WriteParam(aMsg, aParam.mIsRoot);
WriteParam(aMsg, aParam.mHasScrollgrab);
WriteParam(aMsg, aParam.mUpdateScrollOffset);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
@ -603,7 +604,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab));
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset));
}
};

View File

@ -55,6 +55,7 @@ public:
, mPresShellId(-1)
, mIsRoot(false)
, mHasScrollgrab(false)
, mUpdateScrollOffset(false)
{}
// Default copy ctor and operator= are fine
@ -73,7 +74,8 @@ public:
mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
mPresShellId == aOther.mPresShellId &&
mIsRoot == aOther.mIsRoot;
mIsRoot == aOther.mIsRoot &&
mUpdateScrollOffset == aOther.mUpdateScrollOffset;
}
bool operator!=(const FrameMetrics& aOther) const
{
@ -284,6 +286,10 @@ public:
// Whether or not this frame is for an element marked 'scrollgrab'.
bool mHasScrollgrab;
// Whether mScrollOffset was updated by something other than the APZ code, and
// if the APZC receiving this metrics should update its local copy.
bool mUpdateScrollOffset;
};
/**

View File

@ -630,6 +630,13 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
metrics.mScrollOffset = CSSPoint::FromAppUnits(scrollPosition);
// If the frame was scrolled since the last layers update, and by
// something other than the APZ code, we want to tell the APZ to update
// its scroll offset.
nsIAtom* originOfLastScroll = scrollableFrame->OriginOfLastScroll();
metrics.mUpdateScrollOffset = (originOfLastScroll && originOfLastScroll != nsGkAtoms::apz);
scrollableFrame->ResetOriginOfLastScroll();
}
else {
nsRect contentBounds = aForFrame->GetRect();

View File

@ -1537,6 +1537,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
, mResizerBox(nullptr)
, mOuter(aOuter)
, mAsyncScroll(nullptr)
, mOriginOfLastScroll(nullptr)
, mDestination(0, 0)
, mScrollPosAtLastPaint(0, 0)
, mRestorePos(-1, -1)
@ -1652,12 +1653,13 @@ ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition)
}
void
ScrollFrameHelper::ScrollToCSSPixelsApproximate(const CSSPoint& aScrollPosition)
ScrollFrameHelper::ScrollToCSSPixelsApproximate(const CSSPoint& aScrollPosition,
nsIAtom *aOrigin)
{
nsPoint pt = CSSPoint::ToAppUnits(aScrollPosition);
nscoord halfRange = nsPresContext::CSSPixelsToAppUnits(1000);
nsRect range(pt.x - halfRange, pt.y - halfRange, 2*halfRange - 1, 2*halfRange - 1);
ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
ScrollToWithOrigin(pt, nsIScrollableFrame::INSTANT, aOrigin, &range);
// 'this' might be destroyed here
}
@ -1687,7 +1689,7 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
// async-scrolling process and do an instant scroll.
mAsyncScroll = nullptr;
nsWeakFrame weakFrame(mOuter);
ScrollToImpl(mDestination, range);
ScrollToImpl(mDestination, range, aOrigin);
if (!weakFrame.IsAlive()) {
return;
}
@ -1707,7 +1709,7 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
mAsyncScroll = nullptr;
// Observer setup failed. Scroll the normal way.
nsWeakFrame weakFrame(mOuter);
ScrollToImpl(mDestination, range);
ScrollToImpl(mDestination, range, aOrigin);
if (!weakFrame.IsAlive()) {
return;
}
@ -1982,8 +1984,15 @@ ScrollFrameHelper::ScheduleSyntheticMouseMove()
}
void
ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOrigin)
{
if (aOrigin == nullptr) {
// If no origin was specified, we still want to set it to something that's
// non-null, so that we can use nullness to distinguish if the frame was scrolled
// at all. Default it to some generic placeholder.
aOrigin = nsGkAtoms::other;
}
nsPresContext* presContext = mOuter->PresContext();
nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
// 'scale' is our estimate of the scale factor that will be applied
@ -2038,6 +2047,7 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
nsPoint oldScrollFramePos = mScrolledFrame->GetPosition();
// Update frame position for scrolling
mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
mOriginOfLastScroll = aOrigin;
// We pass in the amount to move visually
ScrollVisual(oldScrollFramePos);

View File

@ -191,13 +191,14 @@ public:
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition);
void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsIAtom* aOrigin = nullptr);
CSSIntPoint GetScrollPositionCSSPixels();
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
void ScrollToImpl(nsPoint aScrollPosition, const nsRect& aRange);
void ScrollToImpl(nsPoint aScrollPosition, const nsRect& aRange, nsIAtom* aOrigin = nullptr);
void ScrollVisual(nsPoint aOldScrolledFramePosition);
/**
* @note This method might destroy the frame, pres shell and other objects.
@ -305,6 +306,9 @@ public:
void HandleScrollbarStyleSwitching();
nsIAtom* OriginOfLastScroll() const { return mOriginOfLastScroll; }
void ResetOriginOfLastScroll() { mOriginOfLastScroll = nullptr; }
// owning references to the nsIAnonymousContentCreator-built content
nsCOMPtr<nsIContent> mHScrollbarContent;
nsCOMPtr<nsIContent> mVScrollbarContent;
@ -323,6 +327,7 @@ public:
nsRefPtr<AsyncScroll> mAsyncScroll;
nsRefPtr<ScrollbarActivity> mScrollbarActivity;
nsTArray<nsIScrollPositionListener*> mListeners;
nsIAtom* mOriginOfLastScroll;
nsRect mScrollPort;
// Where we're currently scrolling to, if we're scrolling asynchronously.
// If we're not in the middle of an asynchronous scroll then this is
@ -589,8 +594,9 @@ public:
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixels(aScrollPosition);
}
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition);
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsIAtom* aOrigin = nullptr) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition, aOrigin);
}
/**
* @note This method might destroy the frame, pres shell and other objects.
@ -642,6 +648,12 @@ public:
virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
return mHelper.IsRectNearlyVisible(aRect);
}
virtual nsIAtom* OriginOfLastScroll() MOZ_OVERRIDE {
return mHelper.OriginOfLastScroll();
}
virtual void ResetOriginOfLastScroll() MOZ_OVERRIDE {
mHelper.ResetOriginOfLastScroll();
}
// nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
@ -883,8 +895,9 @@ public:
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixels(aScrollPosition);
}
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition);
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsIAtom* aOrigin = nullptr) MOZ_OVERRIDE {
mHelper.ScrollToCSSPixelsApproximate(aScrollPosition, aOrigin);
}
virtual CSSIntPoint GetScrollPositionCSSPixels() MOZ_OVERRIDE {
return mHelper.GetScrollPositionCSSPixels();
@ -893,7 +906,7 @@ public:
* @note This method might destroy the frame, pres shell and other objects.
*/
virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr) MOZ_OVERRIDE {
nsIntPoint* aOverflow, nsIAtom* aOrigin = nullptr) MOZ_OVERRIDE {
mHelper.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
}
/**
@ -933,6 +946,12 @@ public:
virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
return mHelper.IsRectNearlyVisible(aRect);
}
virtual nsIAtom* OriginOfLastScroll() MOZ_OVERRIDE {
return mHelper.OriginOfLastScroll();
}
virtual void ResetOriginOfLastScroll() MOZ_OVERRIDE {
mHelper.ResetOriginOfLastScroll();
}
// nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {

View File

@ -25,6 +25,7 @@ class nsIFrame;
class nsPresContext;
class nsIContent;
class nsRenderingContext;
class nsIAtom;
/**
* Interface for frames that are scrollable. This interface exposes
@ -186,7 +187,8 @@ public:
* number of layer pixels (so the operation is fast and looks clean).
* The scroll mode is INSTANT.
*/
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition) = 0;
virtual void ScrollToCSSPixelsApproximate(const mozilla::CSSPoint& aScrollPosition,
nsIAtom *aOrigin = nullptr) = 0;
/**
* Returns the scroll position in integer CSS pixels, rounded to the nearest
@ -268,6 +270,15 @@ public:
* visibility heuristics for how close it is to the visible scrollport.
*/
virtual bool IsRectNearlyVisible(const nsRect& aRect) = 0;
/**
* Returns the origin passed in to the last ScrollToImpl call that took
* effect.
*/
virtual nsIAtom* OriginOfLastScroll() = 0;
/**
* Clears the "origin of last scroll" property stored in this frame.
*/
virtual void ResetOriginOfLastScroll() = 0;
};
#endif

View File

@ -84,6 +84,25 @@ MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics,
- aActualScrollOffset;
}
static CSSPoint
ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint)
{
if (!aFrame) {
return CSSPoint();
}
// If the scrollable frame got a scroll request from something other than us
// since the last layers update, then we don't want to push our scroll request
// because we'll clobber that one, which is bad.
if (!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz) {
aFrame->ScrollToCSSPixelsApproximate(aPoint, nsGkAtoms::apz);
}
// Return the final scroll position after setting it so that anything that relies
// on it can have an accurate value. Note that even if we set it above re-querying it
// is a good idea because it may have gotten clamped or rounded.
return CSSPoint::FromAppUnits(aFrame->GetScrollPosition());
}
void
APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
FrameMetrics& aMetrics)
@ -105,12 +124,8 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
// Scroll the window to the desired spot
aUtils->ScrollToCSSPixelsApproximate(aMetrics.mScrollOffset.x, aMetrics.mScrollOffset.y, nullptr);
// Re-query the scroll position after setting it so that anything that relies on it
// can have an accurate value.
CSSPoint actualScrollOffset;
aUtils->GetScrollXYFloat(false, &actualScrollOffset.x, &actualScrollOffset.y);
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset);
// Correct the display port due to the difference between mScrollOffset and the
// actual scroll offset, possibly align it to tile boundaries (if tiled layers are
@ -167,12 +182,8 @@ APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
// We currently do not support zooming arbitrary subframes. They can only
// be scrolled, so here we only have to set the scroll position and displayport.
CSSPoint actualScrollOffset;
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
if (sf) {
sf->ScrollToCSSPixelsApproximate(aMetrics.mScrollOffset);
actualScrollOffset = CSSPoint::FromAppUnits(sf->GetScrollPosition());
}
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
if (element) {