diff options
Diffstat (limited to 'widget/gonk/GeckoTouchDispatcher.cpp')
-rw-r--r-- | widget/gonk/GeckoTouchDispatcher.cpp | 358 |
1 files changed, 0 insertions, 358 deletions
diff --git a/widget/gonk/GeckoTouchDispatcher.cpp b/widget/gonk/GeckoTouchDispatcher.cpp deleted file mode 100644 index 0b18c91a1..000000000 --- a/widget/gonk/GeckoTouchDispatcher.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* Copyright 2014 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "FrameMetrics.h" -#include "GeckoProfiler.h" -#include "GeckoTouchDispatcher.h" -#include "InputData.h" -#include "ProfilerMarkers.h" -#include "base/basictypes.h" -#include "gfxPrefs.h" -#include "libui/Input.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Mutex.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/dom/Touch.h" -#include "mozilla/layers/APZThreadUtils.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "nsAppShell.h" -#include "nsDebug.h" -#include "nsThreadUtils.h" -#include "nsWindow.h" -#include <sys/types.h> -#include <unistd.h> -#include <utils/Timers.h> - -#undef LOG -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - -// uncomment to print log resample data -// #define LOG_RESAMPLE_DATA 1 - -namespace mozilla { - -// Amount of time in MS before an input is considered expired. -static const uint64_t kInputExpirationThresholdMs = 1000; - -static StaticRefPtr<GeckoTouchDispatcher> sTouchDispatcher; - -/* static */ GeckoTouchDispatcher* -GeckoTouchDispatcher::GetInstance() -{ - if (!sTouchDispatcher) { - sTouchDispatcher = new GeckoTouchDispatcher(); - ClearOnShutdown(&sTouchDispatcher); - } - return sTouchDispatcher; -} - -GeckoTouchDispatcher::GeckoTouchDispatcher() - : mTouchQueueLock("GeckoTouchDispatcher::mTouchQueueLock") - , mHavePendingTouchMoves(false) - , mInflightNonMoveEvents(0) - , mTouchEventsFiltered(false) -{ - // Since GeckoTouchDispatcher is initialized when input is initialized - // and reads gfxPrefs, it is the first thing to touch gfxPrefs. - // The first thing to touch gfxPrefs MUST occur on the main thread and init - // the singleton - MOZ_ASSERT(sTouchDispatcher == nullptr); - MOZ_ASSERT(NS_IsMainThread()); - gfxPrefs::GetSingleton(); - - mEnabledUniformityInfo = gfxPrefs::UniformityInfo(); - mVsyncAdjust = TimeDuration::FromMilliseconds(gfxPrefs::TouchVsyncSampleAdjust()); - mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict()); - mMinDelta = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMinDelta()); - mOldTouchThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleOldTouchThreshold()); - mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold()); -} - -void -GeckoTouchDispatcher::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver) -{ - MOZ_ASSERT(NS_IsMainThread()); - // We assume on b2g that there is only 1 CompositorBridgeParent - MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - mCompositorVsyncScheduler = aObserver; -} - -void -GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - DispatchTouchMoveEvents(aVsyncTimestamp); -} - -// Touch data timestamps are in milliseconds, aEventTime is in nanoseconds -void -GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime) -{ - if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetNeedsComposite(); - } - - if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) { - MutexAutoLock lock(mTouchQueueLock); - if (mInflightNonMoveEvents > 0) { - // If we have any pending non-move events, we shouldn't resample the - // move events because we might end up dispatching events out of order. - // Instead, fall back to a non-resampling in-order dispatch until we're - // done processing the non-move events. - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod<MultiTouchInput>( - this, &GeckoTouchDispatcher::DispatchTouchEvent, aTouch)); - return; - } - - mTouchMoveEvents.push_back(aTouch); - mHavePendingTouchMoves = true; - } else { - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents++; - } - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod<MultiTouchInput>( - this, &GeckoTouchDispatcher::DispatchTouchNonMoveEvent, aTouch)); - } -} - -void -GeckoTouchDispatcher::DispatchTouchNonMoveEvent(MultiTouchInput aInput) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - - // Flush pending touch move events, if there are any - // (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and - // bail out if there's nothing to be done). - NotifyVsync(TimeStamp::Now()); - DispatchTouchEvent(aInput); - - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents--; - MOZ_ASSERT(mInflightNonMoveEvents >= 0); - } -} - -void -GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime) -{ - MultiTouchInput touchMove; - - { - MutexAutoLock lock(mTouchQueueLock); - if (!mHavePendingTouchMoves) { - return; - } - mHavePendingTouchMoves = false; - - int touchCount = mTouchMoveEvents.size(); - TimeDuration vsyncTouchDiff = aVsyncTime - mTouchMoveEvents.back().mTimeStamp; - // The delay threshold is a positive pref, but we're testing to see if the - // vsync time is delayed from the touch, so add a negative sign. - bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold; - bool isOldTouch = vsyncTouchDiff > mOldTouchThreshold; - bool resample = (touchCount > 1) && !isDelayedVsyncEvent && !isOldTouch; - - if (!resample) { - touchMove = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - if (!isDelayedVsyncEvent && !isOldTouch) { - mTouchMoveEvents.push_back(touchMove); - } - } else { - ResampleTouchMoves(touchMove, aVsyncTime); - } - } - - DispatchTouchEvent(touchMove); -} - -static int -Interpolate(int start, int end, TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - return start + (((end - start) * aFrameDiff.ToMicroseconds()) / aTouchDiff.ToMicroseconds()); -} - -static const SingleTouchData& -GetTouchByID(const SingleTouchData& aCurrentTouch, MultiTouchInput& aOtherTouch) -{ - int32_t index = aOtherTouch.IndexOfTouch(aCurrentTouch.mIdentifier); - if (index < 0) { - // We can have situations where a previous touch event had 2 fingers - // and we lift 1 finger off. In those cases, we won't find the touch event - // with given id, so just return the current touch, which will be resampled - // without modification and dispatched. - return aCurrentTouch; - } - return aOtherTouch.mTouches[index]; -} - - -// aTouchDiff is the duration between the base and current touch times -// aFrameDiff is the duration between the base and the time we're resampling to -static void -ResampleTouch(MultiTouchInput& aOutTouch, - MultiTouchInput& aBase, MultiTouchInput& aCurrent, - TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - aOutTouch = aCurrent; - - // Make sure we only resample the correct finger. - for (size_t i = 0; i < aOutTouch.mTouches.Length(); i++) { - const SingleTouchData& current = aCurrent.mTouches[i]; - const SingleTouchData& base = GetTouchByID(current, aBase); - - const ScreenIntPoint& baseTouchPoint = base.mScreenPoint; - const ScreenIntPoint& currentTouchPoint = current.mScreenPoint; - - ScreenIntPoint newSamplePoint; - newSamplePoint.x = Interpolate(baseTouchPoint.x, currentTouchPoint.x, aFrameDiff, aTouchDiff); - newSamplePoint.y = Interpolate(baseTouchPoint.y, currentTouchPoint.y, aFrameDiff, aTouchDiff); - - aOutTouch.mTouches[i].mScreenPoint = newSamplePoint; - -#ifdef LOG_RESAMPLE_DATA - const char* type = "extrapolate"; - if (aFrameDiff < aTouchDiff) { - type = "interpolate"; - } - - float alpha = aFrameDiff / aTouchDiff; - LOG("%s base (%d, %d), current (%d, %d) to (%d, %d) alpha %f, touch diff %d, frame diff %d\n", - type, - baseTouchPoint.x, baseTouchPoint.y, - currentTouchPoint.x, currentTouchPoint.y, - newSamplePoint.x, newSamplePoint.y, - alpha, (int)aTouchDiff.ToMilliseconds(), (int)aFrameDiff.ToMilliseconds()); -#endif - } -} - -/* - * +> Base touch (The touch before current touch) - * | - * | +> Current touch (Latest touch) - * | | - * | | +> Maximum resample time - * | | | - * +-----+------+--------------------> Time - * ^ ^ - * | | - * +------+--> Potential vsync events which the touches are resampled to - * | | - * | +> Extrapolation - * | - * +> Interpolation - */ - -void -GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp aVsyncTime) -{ - MOZ_RELEASE_ASSERT(mTouchMoveEvents.size() >= 2); - mTouchQueueLock.AssertCurrentThreadOwns(); - - MultiTouchInput currentTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.pop_back(); - MultiTouchInput baseTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - mTouchMoveEvents.push_back(currentTouch); - - TimeStamp sampleTime = aVsyncTime - mVsyncAdjust; - TimeDuration touchDiff = currentTouch.mTimeStamp - baseTouch.mTimeStamp; - - if (touchDiff < mMinDelta) { - aOutTouch = currentTouch; - #ifdef LOG_RESAMPLE_DATA - LOG("The touches are too close, skip resampling\n"); - #endif - return; - } - - if (currentTouch.mTimeStamp < sampleTime) { - TimeDuration maxResampleTime = std::min(touchDiff / int64_t(2), mMaxPredict); - TimeStamp maxTimestamp = currentTouch.mTimeStamp + maxResampleTime; - if (sampleTime > maxTimestamp) { - sampleTime = maxTimestamp; - #ifdef LOG_RESAMPLE_DATA - LOG("Overshot extrapolation time, adjusting sample time\n"); - #endif - } - } - - ResampleTouch(aOutTouch, baseTouch, currentTouch, sampleTime - baseTouch.mTimeStamp, touchDiff); - - // Both mTimeStamp and mTime are being updated to sampleTime here. - // mTime needs to be updated using a delta since TimeStamp doesn't - // provide a way to obtain a raw value. - aOutTouch.mTime += (sampleTime - aOutTouch.mTimeStamp).ToMilliseconds(); - aOutTouch.mTimeStamp = sampleTime; -} - -static bool -IsExpired(const MultiTouchInput& aTouch) -{ - // No pending events, the filter state can be updated. - uint64_t timeNowMs = systemTime(SYSTEM_TIME_MONOTONIC) / 1000000; - return (timeNowMs - aTouch.mTime) > kInputExpirationThresholdMs; -} -void -GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput aMultiTouch) -{ - if ((aMultiTouch.mType == MultiTouchInput::MULTITOUCH_END || - aMultiTouch.mType == MultiTouchInput::MULTITOUCH_CANCEL) && - aMultiTouch.mTouches.Length() == 1) { - MutexAutoLock lock(mTouchQueueLock); - mTouchMoveEvents.clear(); - } else if (aMultiTouch.mType == MultiTouchInput::MULTITOUCH_START && - aMultiTouch.mTouches.Length() == 1) { - mTouchEventsFiltered = IsExpired(aMultiTouch); - } - - if (mTouchEventsFiltered) { - return; - } - - nsWindow::DispatchTouchInput(aMultiTouch); - - if (mEnabledUniformityInfo && profiler_is_active()) { - const char* touchAction = "Invalid"; - switch (aMultiTouch.mType) { - case MultiTouchInput::MULTITOUCH_START: - touchAction = "Touch_Event_Down"; - break; - case MultiTouchInput::MULTITOUCH_MOVE: - touchAction = "Touch_Event_Move"; - break; - case MultiTouchInput::MULTITOUCH_END: - case MultiTouchInput::MULTITOUCH_CANCEL: - touchAction = "Touch_Event_Up"; - break; - case MultiTouchInput::MULTITOUCH_SENTINEL: - MOZ_ASSERT_UNREACHABLE("Invalid MultTouchInput."); - break; - } - - const ScreenIntPoint& touchPoint = aMultiTouch.mTouches[0].mScreenPoint; - TouchDataPayload* payload = new TouchDataPayload(touchPoint); - PROFILER_MARKER_PAYLOAD(touchAction, payload); - } -} - -} // namespace mozilla |