--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
@@ -25,17 +25,17 @@
namespace {
// Internal flags and constants
static const float ANIMATION_DURATION = 0.15f; // How many seconds the complete animation should span
static const int32_t MOVE_TOOLBAR_DOWN = 1; // Multiplier to move the toolbar down
static const int32_t MOVE_TOOLBAR_UP = -1; // Multiplier to move the toolbar up
static const float SHRINK_FACTOR = 0.95f; // Amount to shrink the either the full content for small pages or the amount left
- // See: IsEnoughPageToHideToolbar()
+ // See: PageTooSmallEnsureToolbarVisible()
} // namespace
namespace mozilla {
namespace layers {
AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator()
: mRootLayerTreeId(0)
// Read/Write Compositor Thread, Read only Controller thread
@@ -49,26 +49,29 @@ AndroidDynamicToolbarAnimator::AndroidDy
, mControllerResetOnNextMove(false)
, mControllerStartTouch(0)
, mControllerPreviousTouch(0)
, mControllerTotalDistance(0)
, mControllerMaxToolbarHeight(0)
, mControllerToolbarHeight(0)
, mControllerSurfaceHeight(0)
, mControllerCompositionHeight(0)
+ , mControllerRootScrollY(0.0f)
, mControllerLastDragDirection(0)
, mControllerTouchCount(0)
, mControllerLastEventTimeStamp(0)
, mControllerState(eNothingPending)
// Compositor thread only
, mCompositorShutdown(false)
, mCompositorAnimationDeferred(false)
, mCompositorLayersUpdateEnabled(false)
, mCompositorAnimationStarted(false)
, mCompositorReceivedFirstPaint(false)
+ , mCompositorWaitForPageResize(false)
+ , mCompositorToolbarShowRequested(false)
, mCompositorAnimationStyle(eAnimate)
, mCompositorMaxToolbarHeight(0)
, mCompositorToolbarHeight(0)
, mCompositorSurfaceHeight(0)
, mCompositorAnimationDirection(0)
, mCompositorAnimationStartHeight(0)
{}
@@ -96,27 +99,33 @@ GetTouchY(MultiTouchInput& multiTouch, S
*value = multiTouch.mTouches[0].mScreenPoint.y;
return true;
}
return false;
}
nsEventStatus
-AndroidDynamicToolbarAnimator::ReceiveInputEvent(InputData& aEvent)
+AndroidDynamicToolbarAnimator::ReceiveInputEvent(InputData& aEvent, const ScreenPoint& aScrollOffset)
{
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
+ mControllerRootScrollY = aScrollOffset.y;
+
// Only process and adjust touch events. Wheel events (aka scroll events) are adjusted in the NativePanZoomController
if (aEvent.mInputType != MULTITOUCH_INPUT) {
return nsEventStatus_eIgnore;
}
MultiTouchInput& multiTouch = aEvent.AsMultiTouchInput();
- ScreenIntCoord currentTouch = 0;
+
+ if (PageTooSmallEnsureToolbarVisible()) {
+ TranslateTouchEvent(multiTouch);
+ return nsEventStatus_eIgnore;
+ }
switch (multiTouch.mType) {
case MultiTouchInput::MULTITOUCH_START:
mControllerTouchCount = multiTouch.mTouches.Length();
break;
case MultiTouchInput::MULTITOUCH_END:
case MultiTouchInput::MULTITOUCH_CANCEL:
mControllerTouchCount -= multiTouch.mTouches.Length();
@@ -124,59 +133,66 @@ AndroidDynamicToolbarAnimator::ReceiveIn
default:
break;
}
if (mControllerTouchCount > 1) {
mControllerResetOnNextMove = true;
}
+ ScreenIntCoord currentTouch = 0;
+
if (mPinnedFlags || !GetTouchY(multiTouch, ¤tTouch)) {
TranslateTouchEvent(multiTouch);
return nsEventStatus_eIgnore;
}
// Only the return value from ProcessTouchDelta should
// change status to nsEventStatus_eConsumeNoDefault
nsEventStatus status = nsEventStatus_eIgnore;
const StaticToolbarState currentToolbarState = mToolbarState;
switch (multiTouch.mType) {
case MultiTouchInput::MULTITOUCH_START:
mControllerCancelTouchTracking = false;
mControllerStartTouch = mControllerPreviousTouch = currentTouch;
- if (currentToolbarState == eToolbarAnimating) {
+ // We don't want to stop the animation if we are near the bottom of the page.
+ if (!ScrollOffsetNearBottom() && (currentToolbarState == eToolbarAnimating)) {
StopCompositorAnimation();
}
break;
case MultiTouchInput::MULTITOUCH_MOVE: {
CheckForResetOnNextMove(currentTouch);
-
if ((mControllerState != eAnimationStartPending) &&
(mControllerState != eAnimationStopPending) &&
(currentToolbarState != eToolbarAnimating) &&
!mControllerCancelTouchTracking) {
+ // Don't move the toolbar if we are near the page bottom
+ // and the toolbar is not in transition
+ if (ScrollOffsetNearBottom() && !ToolbarInTransition()) {
+ ShowToolbarIfNotVisible(currentToolbarState);
+ break;
+ }
+
ScreenIntCoord delta = currentTouch - mControllerPreviousTouch;
mControllerPreviousTouch = currentTouch;
mControllerTotalDistance += delta;
if (delta != 0) {
ScreenIntCoord direction = (delta > 0 ? MOVE_TOOLBAR_DOWN : MOVE_TOOLBAR_UP);
if (mControllerLastDragDirection && (direction != mControllerLastDragDirection)) {
mControllerDragChangedDirection = true;
}
mControllerLastDragDirection = direction;
}
- if (IsEnoughPageToHideToolbar(delta)) {
- // NOTE: gfxPrefs::ToolbarScrollThreshold() returns a percentage as an intt32_t. So multiply it by 0.01f to convert.
- const uint32_t dragThreshold = Abs(std::lround(0.01f * gfxPrefs::ToolbarScrollThreshold() * mControllerCompositionHeight));
- if ((Abs(mControllerTotalDistance.value) > dragThreshold) && (delta != 0)) {
- mControllerDragThresholdReached = true;
- status = ProcessTouchDelta(currentToolbarState, delta, multiTouch.mTime);
- }
+ // NOTE: gfxPrefs::ToolbarScrollThreshold() returns a percentage as an int32_t. So multiply it by 0.01f to convert.
+ const uint32_t dragThreshold = Abs(std::lround(0.01f * gfxPrefs::ToolbarScrollThreshold() * mControllerCompositionHeight));
+ if ((Abs(mControllerTotalDistance.value) > dragThreshold) && (delta != 0)) {
+ mControllerDragThresholdReached = true;
+ status = ProcessTouchDelta(currentToolbarState, delta, multiTouch.mTime);
}
mControllerLastEventTimeStamp = multiTouch.mTime;
}
break;
}
case MultiTouchInput::MULTITOUCH_END:
case MultiTouchInput::MULTITOUCH_CANCEL:
// last finger was lifted
@@ -289,25 +305,28 @@ AndroidDynamicToolbarAnimator::ToolbarAn
break;
case STATIC_TOOLBAR_READY:
break;
case TOOLBAR_HIDDEN:
// If the toolbar is animating, then it is already unlocked.
if (mToolbarState != eToolbarAnimating) {
mToolbarState = eToolbarUnlocked;
if (mCompositorAnimationDeferred) {
- StartCompositorAnimation(mCompositorAnimationDirection, mCompositorAnimationStyle, mCompositorToolbarHeight);
+ StartCompositorAnimation(mCompositorAnimationDirection, mCompositorAnimationStyle, mCompositorToolbarHeight, mCompositorWaitForPageResize);
}
} else {
// The compositor is already animating the toolbar so no need to defer.
mCompositorAnimationDeferred = false;
}
break;
case TOOLBAR_VISIBLE:
- mToolbarState = eToolbarVisible;
+ // If we are currently animating, let the animation finish.
+ if (mToolbarState != eToolbarAnimating) {
+ mToolbarState = eToolbarVisible;
+ }
break;
case TOOLBAR_SHOW:
break;
case FIRST_PAINT:
break;
case REQUEST_SHOW_TOOLBAR_IMMEDIATELY:
NotifyControllerPendingAnimation(MOVE_TOOLBAR_DOWN, eImmediate);
break;
@@ -344,22 +363,27 @@ AndroidDynamicToolbarAnimator::UpdateAni
AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
if (!manager) {
return false;
}
if (mCompositorSurfaceHeight != mCompositorCompositionSize.height) {
// Waiting for the composition to resize
- return true;
+ if (mCompositorWaitForPageResize && mCompositorAnimationStarted) {
+ mCompositorWaitForPageResize = false;
+ } else {
+ return true;
+ }
} else if (!mCompositorAnimationStarted) {
parent->GetAPZCTreeManager()->AdjustScrollForSurfaceShift(ScreenPoint(0.0f, (float)(-mCompositorToolbarHeight)));
manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
mCompositorAnimationStarted = true;
mCompositorReceivedFirstPaint = false;
+ mCompositorToolbarShowRequested = false;
// Reset the start time so the toolbar does not jump on the first animation frame
mCompositorAnimationStartTimeStamp = aCurrentFrame;
// Since the delta time for this frame will be zero. Just return, the animation will start on the next frame.
return true;
}
bool continueAnimating = true;
@@ -375,19 +399,29 @@ AndroidDynamicToolbarAnimator::UpdateAni
// This animation was started in the future!
if (deltaTime < 0.0f) {
deltaTime = 0.0f;
}
mCompositorToolbarHeight = mCompositorAnimationStartHeight + ((int32_t)(rate * deltaTime) * mCompositorAnimationDirection);
}
if ((mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) && (mCompositorToolbarHeight >= mCompositorMaxToolbarHeight)) {
- continueAnimating = false;
- mToolbarState = eToolbarVisible;
- PostMessage(TOOLBAR_SHOW);
+ // if the toolbar is being animated and the page is at the end, the animation needs to wait for
+ // the page to resize before ending the animation so that the page may be scrolled
+ if (!mCompositorReceivedFirstPaint && mCompositorWaitForPageResize) {
+ continueAnimating = true;
+ } else {
+ continueAnimating = false;
+ mToolbarState = eToolbarVisible;
+ }
+ // Make sure we only send one show request per animation
+ if (!mCompositorToolbarShowRequested) {
+ PostMessage(TOOLBAR_SHOW);
+ mCompositorToolbarShowRequested = true;
+ }
mCompositorToolbarHeight = mCompositorMaxToolbarHeight;
} else if ((mCompositorAnimationDirection == MOVE_TOOLBAR_UP) && (mCompositorToolbarHeight <= 0)) {
continueAnimating = false;
mToolbarState = eToolbarUnlocked;
mCompositorToolbarHeight = 0;
}
if (continueAnimating) {
@@ -555,18 +589,18 @@ AndroidDynamicToolbarAnimator::ProcessTo
ScreenIntCoord deltaRemainder = 0;
mControllerToolbarHeight += aDelta;
if (tryingToHideToolbar && (mControllerToolbarHeight <= 0 )) {
deltaRemainder = mControllerToolbarHeight;
mControllerToolbarHeight = 0;
} else if (!tryingToHideToolbar && (mControllerToolbarHeight >= mControllerMaxToolbarHeight)) {
deltaRemainder = mControllerToolbarHeight - mControllerMaxToolbarHeight;
mControllerToolbarHeight = mControllerMaxToolbarHeight;
+ mControllerState = eShowPending;
PostMessage(TOOLBAR_SHOW);
- mControllerState = eShowPending;
}
UpdateCompositorToolbarHeight(mControllerToolbarHeight);
RequestComposite();
// If there was no delta left over, the event was completely consumed.
if (deltaRemainder == 0) {
status = nsEventStatus_eConsumeNoDefault;
}
@@ -594,19 +628,17 @@ AndroidDynamicToolbarAnimator::HandleTou
int32_t direction = mControllerLastDragDirection;
mControllerLastDragDirection = 0;
bool isRoot = mControllerScrollingRootContent;
mControllerScrollingRootContent = false;
bool dragChangedDirection = mControllerDragChangedDirection;
mControllerDragChangedDirection = false;
// If the drag direction changed and the toolbar is partially visible, hide in the direction with the least distance to travel.
- if (dragChangedDirection &&
- (mControllerToolbarHeight != mControllerMaxToolbarHeight) &&
- (mControllerToolbarHeight != 0)) {
+ if (dragChangedDirection && ToolbarInTransition()) {
direction = ((float)mControllerToolbarHeight / (float)mControllerMaxToolbarHeight) < 0.5f ? MOVE_TOOLBAR_UP : MOVE_TOOLBAR_DOWN;
}
// If the last touch didn't have a drag direction, use start of touch to find direction
if (!direction) {
if (mControllerToolbarHeight == mControllerMaxToolbarHeight) {
direction = MOVE_TOOLBAR_DOWN;
} else if (mControllerToolbarHeight == 0) {
@@ -635,17 +667,17 @@ AndroidDynamicToolbarAnimator::HandleTou
// Received a UI thread request to show or hide the snapshot during a touch.
// This overrides the touch event so just return.
if (cancelTouchTracking) {
return;
}
// The drag threshold has not been reach and the toolbar is either completely visible or completely hidden.
- if (!dragThresholdReached && ((mControllerToolbarHeight == mControllerMaxToolbarHeight) || (mControllerToolbarHeight == 0))) {
+ if (!dragThresholdReached && !ToolbarInTransition()) {
ShowToolbarIfNotVisible(aCurrentToolbarState);
return;
}
// The toolbar is already where it needs to be so just return.
if (((direction == MOVE_TOOLBAR_DOWN) && (mControllerToolbarHeight == mControllerMaxToolbarHeight)) ||
((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight == 0))) {
ShowToolbarIfNotVisible(aCurrentToolbarState);
@@ -656,29 +688,28 @@ AndroidDynamicToolbarAnimator::HandleTou
// snapshot toolbar is completely visible before showing, we don't want to enter this if block
// if the snapshot toolbar isn't completely visible to avoid early return.
if (!isRoot &&
((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight == mControllerMaxToolbarHeight))) {
ShowToolbarIfNotVisible(aCurrentToolbarState);
return;
}
- // The page is either too small or too close to the end to animate
- if (!IsEnoughPageToHideToolbar(direction)) {
- if (mControllerToolbarHeight == mControllerMaxToolbarHeight) {
+ if (ScrollOffsetNearBottom()) {
+ if (ToolbarInTransition()) {
+ // Toolbar is partially visible so make it visible since we are near the end of the page
+ direction = MOVE_TOOLBAR_DOWN;
+ } else {
+ // Don't start an animation if near the bottom of page and toolbar is completely visible or hidden
ShowToolbarIfNotVisible(aCurrentToolbarState);
return;
- } else if (mControllerToolbarHeight != 0) {
- // The snapshot is partially visible but there is not enough page
- // to hide the snapshot so make it visible by moving it down
- direction = MOVE_TOOLBAR_DOWN;
}
}
- StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight);
+ StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight, ScrollOffsetNearBottom());
}
void
AndroidDynamicToolbarAnimator::PostMessage(int32_t aMessage) {
// if the root layer tree id is zero then Initialize() has not been called yet
// so queue the message until Initialize() is called.
if (mRootLayerTreeId == 0) {
QueueMessage(aMessage);
@@ -785,54 +816,59 @@ AndroidDynamicToolbarAnimator::NotifyCon
// We received a show request but the real toolbar is hidden, so tell it to show now.
if ((aDirection == MOVE_TOOLBAR_DOWN) && (mToolbarState == eToolbarUnlocked)) {
PostMessage(TOOLBAR_SHOW);
}
return;
}
// NOTE: StartCompositorAnimation will set mControllerState to eAnimationStartPending
- StartCompositorAnimation(aDirection, aAnimationStyle, mControllerToolbarHeight);
+ StartCompositorAnimation(aDirection, aAnimationStyle, mControllerToolbarHeight, ScrollOffsetNearBottom());
MOZ_ASSERT(mControllerState == eAnimationStartPending);
}
void
-AndroidDynamicToolbarAnimator::StartCompositorAnimation(int32_t aDirection, AnimationStyle aAnimationStyle, ScreenIntCoord aHeight)
+AndroidDynamicToolbarAnimator::StartCompositorAnimation(int32_t aDirection, AnimationStyle aAnimationStyle, ScreenIntCoord aHeight, bool aWaitForPageResize)
{
if (!CompositorThreadHolder::IsInCompositorThread()) {
mControllerState = eAnimationStartPending;
- CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<int32_t, AnimationStyle, ScreenIntCoord>(
- this, &AndroidDynamicToolbarAnimator::StartCompositorAnimation, aDirection, aAnimationStyle, aHeight));
+ CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<int32_t, AnimationStyle, ScreenIntCoord, bool>(
+ this, &AndroidDynamicToolbarAnimator::StartCompositorAnimation, aDirection, aAnimationStyle, aHeight, aWaitForPageResize));
return;
}
MOZ_ASSERT(aDirection == MOVE_TOOLBAR_UP || aDirection == MOVE_TOOLBAR_DOWN);
- const StaticToolbarState currentToolbarState = mToolbarState;
+ const StaticToolbarState initialToolbarState = mToolbarState;
mCompositorAnimationDirection = aDirection;
mCompositorAnimationStartHeight = mCompositorToolbarHeight = aHeight;
mCompositorAnimationStyle = aAnimationStyle;
+ mCompositorWaitForPageResize = aWaitForPageResize;
// If the snapshot is not unlocked, request the UI thread update the snapshot
// and defer animation until it has been unlocked
- if (currentToolbarState != eToolbarUnlocked) {
+ if ((initialToolbarState != eToolbarUnlocked) && (initialToolbarState != eToolbarAnimating)) {
mCompositorAnimationDeferred = true;
PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
} else {
- // Toolbar is unlocked so animation may begin immediately
+ // Toolbar is either unlocked or already animating so animation may begin immediately
mCompositorAnimationDeferred = false;
mToolbarState = eToolbarAnimating;
- mCompositorAnimationStarted = false;
+ if (initialToolbarState != eToolbarAnimating) {
+ mCompositorAnimationStarted = false;
+ }
// Let the controller know we starting an animation so it may clear the AnimationStartPending flag.
NotifyControllerAnimationStarted();
CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
if (parent) {
mCompositorAnimationStartTimeStamp = parent->GetAPZCTreeManager()->GetFrameTime();
}
- // Kick the compositor to start the animation
- RequestComposite();
+ if (initialToolbarState != eToolbarAnimating) {
+ // Kick the compositor to start the animation if we aren't already animating.
+ RequestComposite();
+ }
}
}
void
AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted()
{
if (!APZThreadUtils::IsControllerThread()) {
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(this, &AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted));
@@ -938,50 +974,59 @@ AndroidDynamicToolbarAnimator::UpdateFra
CSSToScreenScale aScale,
CSSRect aCssPageRect)
{
if (!APZThreadUtils::IsControllerThread()) {
APZThreadUtils::RunOnControllerThread(NewRunnableMethod<ScreenPoint, CSSToScreenScale, CSSRect>(this, &AndroidDynamicToolbarAnimator::UpdateFrameMetrics, aScrollOffset, aScale, aCssPageRect));
return;
}
+ mControllerRootScrollY = aScrollOffset.y;
+
if (mControllerFrameMetrics.Update(aScrollOffset, aScale, aCssPageRect)) {
+ if (FuzzyEqualsMultiplicative(mControllerFrameMetrics.mPageRect.YMost(), mControllerCompositionHeight + mControllerFrameMetrics.mScrollOffset.y) &&
+ (mControllerFrameMetrics.mPageRect.YMost() > (mControllerSurfaceHeight * 2)) &&
+ (mControllerToolbarHeight != mControllerMaxToolbarHeight) &&
+ !mPinnedFlags) {
+ // The end of the page has been reached, the page is twice the height of the visible height,
+ // and the toolbar is not completely visible so animate it into view.
+ StartCompositorAnimation(MOVE_TOOLBAR_DOWN, eAnimate, mControllerToolbarHeight, /* wait for page resize */ true);
+ }
RefPtr<UiCompositorControllerParent> uiController = UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
MOZ_ASSERT(uiController);
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<ScreenPoint, CSSToScreenScale, CSSRect>(
uiController, &UiCompositorControllerParent::SendRootFrameMetrics,
aScrollOffset, aScale, aCssPageRect));
}
}
bool
-AndroidDynamicToolbarAnimator::IsEnoughPageToHideToolbar(ScreenIntCoord delta)
+AndroidDynamicToolbarAnimator::PageTooSmallEnsureToolbarVisible()
{
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- // The toolbar will only hide if dragging up so ignore positive deltas from dragging down.
- if (delta >= 0) {
+ // if the page is too small then the toolbar can not be hidden
+ if ((float)mControllerSurfaceHeight >= (mControllerFrameMetrics.mPageRect.YMost() * SHRINK_FACTOR)) {
+ // If the toolbar is partial hidden, show it.
+ if ((mControllerToolbarHeight != mControllerMaxToolbarHeight) && !mPinnedFlags) {
+ StartCompositorAnimation(MOVE_TOOLBAR_DOWN, eImmediate, mControllerToolbarHeight, /* wait for page resize */ true);
+ }
return true;
}
- // if the page is 1) too small or 2) too close to the bottom, then the toolbar can not be hidden
- if (((float)mControllerSurfaceHeight >= (mControllerFrameMetrics.mPageRect.YMost() * SHRINK_FACTOR)) ||
- ((float)mControllerSurfaceHeight >= ((mControllerFrameMetrics.mPageRect.YMost() - mControllerFrameMetrics.mScrollOffset.y) * SHRINK_FACTOR))) {
- return false;
- }
-
- return true;
+ return false;
}
void
AndroidDynamicToolbarAnimator::ShowToolbarIfNotVisible(StaticToolbarState aCurrentToolbarState)
{
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
if ((mControllerToolbarHeight == mControllerMaxToolbarHeight) &&
(aCurrentToolbarState != eToolbarVisible) &&
(mControllerState != eShowPending)) {
+ mControllerState = eShowPending;
PostMessage(TOOLBAR_SHOW);
}
}
bool
AndroidDynamicToolbarAnimator::FrameMetricsState::Update(const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aScale,
const CSSRect& aCssPageRect)
@@ -1039,16 +1084,38 @@ AndroidDynamicToolbarAnimator::CheckForR
mControllerTotalDistance = 0;
mControllerLastDragDirection = 0;
mControllerStartTouch = mControllerPreviousTouch = aCurrentTouch;
mControllerDragThresholdReached = false;
mControllerResetOnNextMove = false;
}
}
+bool
+AndroidDynamicToolbarAnimator::ScrollOffsetNearBottom() const
+{
+ MOZ_ASSERT(APZThreadUtils::IsControllerThread());
+ // Twice the toolbar's height is considered near the bottom of the page.
+ if ((mControllerToolbarHeight * 2) >= (mControllerFrameMetrics.mPageRect.YMost() - (mControllerRootScrollY + ScreenCoord(mControllerCompositionHeight)))) {
+ return true;
+ }
+ return false;
+}
+
+bool
+AndroidDynamicToolbarAnimator::ToolbarInTransition()
+{
+ if (APZThreadUtils::IsControllerThread()) {
+ return (mControllerToolbarHeight != mControllerMaxToolbarHeight) && (mControllerToolbarHeight != 0);
+ }
+
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ return (mCompositorToolbarHeight != mCompositorMaxToolbarHeight) && (mCompositorToolbarHeight != 0);
+}
+
void
AndroidDynamicToolbarAnimator::QueueMessage(int32_t aMessage)
{
if (!CompositorThreadHolder::IsInCompositorThread()) {
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<int32_t>(this, &AndroidDynamicToolbarAnimator::QueueMessage, aMessage));
return;
}
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
@@ -53,17 +53,17 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidDynamicToolbarAnimator);
AndroidDynamicToolbarAnimator();
void Initialize(uint64_t aRootLayerTreeId);
// Used to intercept events to determine if the event affects the toolbar.
// May apply translation to touch events if the toolbar is visible.
// Returns nsEventStatus_eIgnore when the event is not consumed and
// nsEventStatus_eConsumeNoDefault when the event was used to translate the
// toolbar.
- nsEventStatus ReceiveInputEvent(InputData& aEvent);
+ nsEventStatus ReceiveInputEvent(InputData& aEvent, const ScreenPoint& aScrollOffset);
void SetMaxToolbarHeight(ScreenIntCoord aHeight);
// When a pinned reason is set to true, the animator will prevent
// touch events from altering the height of the toolbar. All pinned
// reasons must be cleared before touch events will affect the toolbar.
// Animation requests from the UI thread are still honored even if any
// pin reason is set. This allows the UI thread to pin the toolbar for
// full screen and then request the animator hide the toolbar.
void SetPinned(bool aPinned, int32_t aReason);
@@ -134,31 +134,37 @@ protected:
// Sends a message to the UI thread. May be called from any thread
void PostMessage(int32_t aMessage);
void UpdateCompositorToolbarHeight(ScreenIntCoord aHeight);
void UpdateControllerToolbarHeight(ScreenIntCoord aHeight, ScreenIntCoord aMaxHeight = -1);
void UpdateControllerSurfaceHeight(ScreenIntCoord aHeight);
void UpdateControllerCompositionHeight(ScreenIntCoord aHeight);
void UpdateFixedLayerMargins();
void NotifyControllerPendingAnimation(int32_t aDirection, AnimationStyle aStyle);
- void StartCompositorAnimation(int32_t aDirection, AnimationStyle aStyle, ScreenIntCoord aHeight);
+ void StartCompositorAnimation(int32_t aDirection, AnimationStyle aStyle, ScreenIntCoord aHeight, bool aWaitForPageResize);
void NotifyControllerAnimationStarted();
void StopCompositorAnimation();
void NotifyControllerAnimationStopped(ScreenIntCoord aHeight);
void RequestComposite();
void PostToolbarReady();
void UpdateFrameMetrics(ScreenPoint aScrollOffset,
CSSToScreenScale aScale,
CSSRect aCssPageRect);
- bool IsEnoughPageToHideToolbar(ScreenIntCoord delta);
+ // Returns true if the page is too small to animate the toolbar
+ // Also ensures the toolbar is visible.
+ bool PageTooSmallEnsureToolbarVisible();
void ShowToolbarIfNotVisible(StaticToolbarState aCurrentToolbarState);
void TranslateTouchEvent(MultiTouchInput& aTouchEvent);
ScreenIntCoord GetFixedLayerMarginsBottom();
void NotifyControllerSnapshotFailed();
void CheckForResetOnNextMove(ScreenIntCoord aCurrentTouch);
+ // Returns true if the page scroll offset is near the bottom.
+ bool ScrollOffsetNearBottom() const;
+ // Returns true if toolbar is not completely visible nor completely hidden.
+ bool ToolbarInTransition();
void QueueMessage(int32_t aMessage);
// Read only Compositor and Controller threads after Initialize()
uint64_t mRootLayerTreeId;
// Read/Write Compositor Thread, Read only Controller thread
Atomic<StaticToolbarState> mToolbarState; // Current toolbar state.
Atomic<uint32_t> mPinnedFlags; // The toolbar should not be moved or animated unless no flags are set
@@ -173,16 +179,17 @@ protected:
// mControllerDragThresholdReached, and mControllerLastDragDirection to be reset on next move
ScreenIntCoord mControllerStartTouch; // The Y position where the touch started
ScreenIntCoord mControllerPreviousTouch; // The previous Y position of the touch
ScreenIntCoord mControllerTotalDistance; // Total distance travel during the current touch
ScreenIntCoord mControllerMaxToolbarHeight; // Max height of the toolbar
ScreenIntCoord mControllerToolbarHeight; // Current height of the toolbar
ScreenIntCoord mControllerSurfaceHeight; // Current height of the render surface
ScreenIntCoord mControllerCompositionHeight; // Current height of the visible page
+ ScreenCoord mControllerRootScrollY; // Current scroll Y value of the root scroll frame
int32_t mControllerLastDragDirection; // Direction of movement of the previous touch move event
int32_t mControllerTouchCount; // Counts the number of current touches.
uint32_t mControllerLastEventTimeStamp; // Time stamp for the previous touch event received
ControllerThreadState mControllerState; // Contains the expected pending state of the mToolbarState
// Contains the values from the last steady state root content FrameMetrics
struct FrameMetricsState {
ScreenPoint mScrollOffset;
@@ -192,35 +199,37 @@ protected:
// Returns true if any of the values have changed.
bool Update(const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aScale,
const CSSRect& aCssPageRect);
};
// Controller thread only
- FrameMetricsState mControllerFrameMetrics;
+ FrameMetricsState mControllerFrameMetrics; // Updated when frame metrics are in a steady state.
class QueuedMessage : public LinkedListElement<QueuedMessage> {
public:
explicit QueuedMessage(int32_t aMessage) :
mMessage(aMessage) {}
int32_t mMessage;
private:
QueuedMessage() = delete;
QueuedMessage(const QueuedMessage&) = delete;
QueuedMessage& operator=(const QueuedMessage&) = delete;
};
// Compositor thread only
- bool mCompositorShutdown; // Set to true when the compositor has been shutdown
- bool mCompositorAnimationDeferred; // An animation has been deferred until the toolbar is unlocked
- bool mCompositorLayersUpdateEnabled; // Flag set to true when the UI thread is expecting to be notified when a layer has been updated
- bool mCompositorAnimationStarted; // Set to true when the compositor has actually started animating the static snapshot.
- bool mCompositorReceivedFirstPaint; // Set to true when a first paint occurs. Used by toolbar animator to detect a new page load.
+ bool mCompositorShutdown; // Set to true when the compositor has been shutdown
+ bool mCompositorAnimationDeferred; // An animation has been deferred until the toolbar is unlocked
+ bool mCompositorLayersUpdateEnabled; // Flag set to true when the UI thread is expecting to be notified when a layer has been updated
+ bool mCompositorAnimationStarted; // Set to true when the compositor has actually started animating the static snapshot.
+ bool mCompositorReceivedFirstPaint; // Set to true when a first paint occurs. Used by toolbar animator to detect a new page load.
+ bool mCompositorWaitForPageResize; // Set to true if the bottom of the page has been reached and the toolbar animator should wait for the page to resize before ending animation.
+ bool mCompositorToolbarShowRequested; // Set to true if the animator has already requested the real toolbar chrome be shown
AnimationStyle mCompositorAnimationStyle; // Set to true when the snap should be immediately hidden or shown in the animation update
ScreenIntCoord mCompositorMaxToolbarHeight; // Should contain the same value as mControllerMaxToolbarHeight
ScreenIntCoord mCompositorToolbarHeight; // This value is only updated by the compositor thread when the mToolbarState == ToolbarAnimating
ScreenIntCoord mCompositorSurfaceHeight; // Current height of the render surface
ScreenIntSize mCompositorCompositionSize; // Current size of the visible page
int32_t mCompositorAnimationDirection; // Direction the snapshot should be animated
ScreenIntCoord mCompositorAnimationStartHeight; // The height of the snapshot at the start of an animation
ScreenIntSize mCompositorToolbarPixelsSize; // Size of the received toolbar pixels