author | Botond Ballo <botond@mozilla.com> |
Tue, 10 Jun 2014 19:43:20 -0400 | |
changeset 188744 | 4b5b1689e3a00605c087c17d3e59babc0b12f64a |
parent 188743 | 2d592384ef8c106b65c47b209efecae400db4a57 |
child 188745 | 8b3794b7e1dc2f517a7666a9db11d889f247da5c |
push id | 44899 |
push user | bballo@mozilla.com |
push date | Sat, 14 Jun 2014 04:40:46 +0000 |
treeherder | mozilla-inbound@4b5b1689e3a0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | kats |
bugs | 1022719 |
milestone | 33.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -35,16 +35,17 @@ namespace layers { float APZCTreeManager::sDPI = 160.0; // Pref that enables printing of the APZC tree for debugging. static bool gPrintApzcTree = false; APZCTreeManager::APZCTreeManager() : mTreeLock("APZCTreeLock"), mInOverscrolledApzc(false), + mRetainedTouchIdentifier(-1), mTouchCount(0), mApzcTreeLog("apzctree") { MOZ_ASSERT(NS_IsMainThread()); AsyncPanZoomController::InitializeGlobalState(); Preferences::AddBoolVarCache(&gPrintApzcTree, "apz.printtree", gPrintApzcTree); mApzcTreeLog.ConditionOnPref(&gPrintApzcTree); } @@ -374,16 +375,26 @@ APZCTreeManager::ReceiveInputEvent(const { nsEventStatus result = nsEventStatus_eIgnore; gfx3DMatrix transformToApzc; gfx3DMatrix transformToGecko; switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput(); if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) { + // If we are in an overscrolled state and a second finger goes down, + // ignore that second touch point completely. The touch-start for it is + // dropped completely; subsequent touch events until the touch-end for it + // will have this touch point filtered out. + if (mApzcForInputBlock && mApzcForInputBlock->IsOverscrolled()) { + if (mRetainedTouchIdentifier == -1) { + mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier(); + } + return nsEventStatus_eConsumeNoDefault; + } // MULTITOUCH_START input contains all active touches of the current // session thus resetting mTouchCount. mTouchCount = multiTouchInput.mTouches.Length(); mInOverscrolledApzc = false; mApzcForInputBlock = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint), &mInOverscrolledApzc); if (multiTouchInput.mTouches.Length() == 1) { // If we have one touch point, this might be the start of a pan. @@ -407,23 +418,53 @@ APZCTreeManager::ReceiveInputEvent(const mCachedTransformToApzcForInputBlock = transformToApzc; } else { // Reset the cached apz transform mCachedTransformToApzcForInputBlock = gfx3DMatrix(); } } else if (mApzcForInputBlock) { APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get()); } + + // If we receive a touch-cancel, it means all touches are finished, so we + // can stop ignoring any that we were ignoring. + if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) { + mRetainedTouchIdentifier = -1; + } + if (mApzcForInputBlock) { mApzcForInputBlock->GetGuid(aOutTargetGuid); // Use the cached transform to compute the point to send to the APZC. // This ensures that the sequence of touch points an APZC sees in an // input block are all in the same coordinate space. transformToApzc = mCachedTransformToApzcForInputBlock; + + // Make a copy of the input event that we pass, with some modifications, + // to the target APZC. MultiTouchInput inputForApzc(multiTouchInput); + + // If we are currently ignoring any touch points, filter them out from + // the set of touch points included in this event. + if (mRetainedTouchIdentifier != -1) { + for (size_t j = 0; j < inputForApzc.mTouches.Length(); ++j) { + if (inputForApzc.mTouches[j].mIdentifier != mRetainedTouchIdentifier) { + // TODO(botond): Once we get rid of ReceiveInputEvent(WidgetInputEvent), + // the signature of this function will change to take the InputData + // via non-const reference. We can then remove the touch point from + // multiTouchInput rather than the copy (inputForApzc), so that + // content doesn't get it either. + inputForApzc.mTouches.RemoveElementAt(j); + --j; + } + } + if (inputForApzc.mTouches.IsEmpty()) { + return nsEventStatus_eConsumeNoDefault; + } + } + for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) { ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc); } mApzcForInputBlock->ReceiveInputEvent(inputForApzc); } result = mInOverscrolledApzc ? nsEventStatus_eConsumeNoDefault : mApzcForInputBlock ? nsEventStatus_eConsumeDoDefault : nsEventStatus_eIgnore; @@ -436,16 +477,17 @@ APZCTreeManager::ReceiveInputEvent(const NS_WARNING("Got an unexpected touchend/touchcancel"); mTouchCount = 0; } // If we have an mApzcForInputBlock and it's the end of the touch sequence // then null it out so we don't keep a dangling reference and leak things. if (mTouchCount == 0) { mApzcForInputBlock = nullptr; mInOverscrolledApzc = false; + mRetainedTouchIdentifier = -1; ClearOverscrollHandoffChain(); } } break; } case PANGESTURE_INPUT: { const PanGestureInput& panInput = aEvent.AsPanGestureInput(); bool inOverscrolledApzc = false; nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint, @@ -533,31 +575,63 @@ APZCTreeManager::ProcessTouchEvent(Widge ScrollableLayerGuid* aOutTargetGuid) { MOZ_ASSERT(NS_IsMainThread()); if (!aEvent.touches.Length()) { return nsEventStatus_eIgnore; } if (aEvent.message == NS_TOUCH_START) { + // If we are in an overscrolled state and a second finger goes down, + // ignore that second touch point completely. The touch-start for it is + // dropped completely; subsequent touch events until the touch-end for it + // will have this touch point filtered out. + if (mApzcForInputBlock && mApzcForInputBlock->IsOverscrolled()) { + if (mRetainedTouchIdentifier == -1) { + mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier(); + } + return nsEventStatus_eConsumeNoDefault; + } // NS_TOUCH_START event contains all active touches of the current // session thus resetting mTouchCount. mTouchCount = aEvent.touches.Length(); mInOverscrolledApzc = false; mApzcForInputBlock = GetTouchInputBlockAPZC(aEvent, &mInOverscrolledApzc); if (mApzcForInputBlock) { // Cache apz transform so it can be used for future events in this block. gfx3DMatrix transformToGecko; GetInputTransforms(mApzcForInputBlock, mCachedTransformToApzcForInputBlock, transformToGecko); } else { // Reset the cached apz transform mCachedTransformToApzcForInputBlock = gfx3DMatrix(); } } + // If we receive a touch-cancel, it means all touches are finished, so we + // can stop ignoring any that we were ignoring. + if (aEvent.message == NS_TOUCH_CANCEL) { + mRetainedTouchIdentifier = -1; + } + + // If we are currently ignoring any touch points, filter them out from the + // set of touch points included in this event. Note that we modify aEvent + // itself, so that the touch points are also filtered out when the caller + // passes the event on to content. + if (mRetainedTouchIdentifier != -1) { + for (size_t j = 0; j < aEvent.touches.Length(); ++j) { + if (aEvent.touches[j]->Identifier() != mRetainedTouchIdentifier) { + aEvent.touches.RemoveElementAt(j); + --j; + } + } + if (aEvent.touches.IsEmpty()) { + return nsEventStatus_eConsumeNoDefault; + } + } + if (mApzcForInputBlock) { mApzcForInputBlock->GetGuid(aOutTargetGuid); // For computing the input for the APZC, used the cached transform. // This ensures that the sequence of touch points an APZC sees in an // input block are all in the same coordinate space. gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock; MultiTouchInput inputForApzc(aEvent); for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) { @@ -587,16 +661,17 @@ APZCTreeManager::ProcessTouchEvent(Widge mTouchCount -= aEvent.touches.Length(); } else { NS_WARNING("Got an unexpected touchend/touchcancel"); mTouchCount = 0; } if (mTouchCount == 0) { mApzcForInputBlock = nullptr; mInOverscrolledApzc = false; + mRetainedTouchIdentifier = -1; ClearOverscrollHandoffChain(); } } return result; } void APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
--- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -372,16 +372,21 @@ private: * touch events delivered to the same initial APZC. This will only ever be touched on the * input delivery thread, and so does not require locking. */ nsRefPtr<AsyncPanZoomController> mApzcForInputBlock; /* Whether the current input event block is being ignored because the touch-start * was inside an overscrolled APZC. */ bool mInOverscrolledApzc; + /* Sometimes we want to ignore all touches except one. In such cases, this + * is set to the identifier of the touch we are not ignoring; in other cases, + * this is set to -1. + */ + int32_t mRetainedTouchIdentifier; /* The number of touch points we are tracking that are currently on the screen. */ uint32_t mTouchCount; /* The transform from root screen coordinates into mApzcForInputBlock's * screen coordinates, as returned through the 'aTransformToApzcOut' parameter * of GetInputTransform(), at the start of the input block. This is cached * because this transform can change over the course of the input block, * but for some operations we need to use the initial transform. * Meaningless if mApzcForInputBlock is nullptr.
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -1837,16 +1837,21 @@ void AsyncPanZoomController::FlushRepain UpdateSharedCompositorFrameMetrics(); } bool AsyncPanZoomController::IsPannable() const { ReentrantMonitorAutoEnter lock(mMonitor); return mX.CanScroll() || mY.CanScroll(); } +int32_t AsyncPanZoomController::GetLastTouchIdentifier() const { + nsRefPtr<GestureEventListener> listener = GetGestureEventListener(); + return listener ? listener->GetLastTouchIdentifier() : -1; +} + void AsyncPanZoomController::RequestContentRepaint() { RequestContentRepaint(mFrameMetrics); } void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) { aFrameMetrics.SetDisplayPortMargins( CalculatePendingDisplayPort(aFrameMetrics, GetVelocityVector(),
--- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -313,16 +313,23 @@ public: */ bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; } /** * Returns whether this APZC has room to be panned (in any direction). */ bool IsPannable() const; + /** + * Returns the identifier of the touch in the last touch event processed by + * this APZC. This should only be called when the last touch event contained + * only one touch. + */ + int32_t GetLastTouchIdentifier() const; + protected: enum PanZoomState { NOTHING, /* no touch-start events received */ FLING, /* all touches removed, but we're still scrolling page */ TOUCHING, /* one touch-start event received */ PANNING, /* panning the frame */ PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */
--- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -101,16 +101,26 @@ nsEventStatus GestureEventListener::Hand mTouches.Clear(); rv = HandleInputTouchCancel(); break; } return rv; } +int32_t GestureEventListener::GetLastTouchIdentifier() const +{ + if (mTouches.Length() != 1) { + NS_WARNING("GetLastTouchIdentifier() called when last touch event " + "did not have one touch"); + } + return mTouches.IsEmpty() ? -1 : mTouches[0].mIdentifier; +} + + nsEventStatus GestureEventListener::HandleInputTouchSingleStart() { switch (mState) { case GESTURE_NONE: SetState(GESTURE_FIRST_SINGLE_TOUCH_DOWN); mTouchStartPosition = mLastTouchInput.mTouches[0].mScreenPoint; CreateLongTapTimeoutTask();
--- a/gfx/layers/apz/src/GestureEventListener.h +++ b/gfx/layers/apz/src/GestureEventListener.h @@ -48,16 +48,23 @@ public: /** * General input handler for a touch event. If the touch event is not a part * of a gesture, then we pass it along to AsyncPanZoomController. Otherwise, * it gets consumed here and never forwarded along. */ nsEventStatus HandleInputEvent(const MultiTouchInput& aEvent); + /** + * Returns the identifier of the touch in the last touch event processed by + * this GestureEventListener. This should only be called when the last touch + * event contained only one touch. + */ + int32_t GetLastTouchIdentifier() const; + private: // Private destructor, to discourage deletion outside of Release(): ~GestureEventListener(); /** * States of GEL finite-state machine. */ enum GestureState {