CoalescedTouchData.cpp (5522B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CoalescedTouchData.h" 8 9 #include "BrowserChild.h" 10 #include "mozilla/dom/PointerEventHandler.h" 11 12 using namespace mozilla; 13 using namespace mozilla::dom; 14 15 static const uint32_t sMaxTouchMoveIdentifiers = 10; 16 17 void CoalescedTouchData::CreateCoalescedTouchEvent( 18 const WidgetTouchEvent& aEvent) { 19 MOZ_ASSERT(IsEmpty()); 20 mCoalescedInputEvent = MakeUnique<WidgetTouchEvent>(aEvent); 21 for (size_t i = 0; i < mCoalescedInputEvent->mTouches.Length(); i++) { 22 const RefPtr<Touch>& touch = mCoalescedInputEvent->mTouches[i]; 23 touch->mCoalescedWidgetEvents = MakeAndAddRef<WidgetPointerEventHolder>(); 24 // Add an initial event into coalesced events, so 25 // the relevant pointer event would at least contain one coalesced event. 26 WidgetPointerEvent* event = 27 touch->mCoalescedWidgetEvents->mEvents.AppendElement(WidgetPointerEvent( 28 aEvent.IsTrusted(), ePointerMove, aEvent.mWidget)); 29 PointerEventHandler::InitPointerEventFromTouch(*event, aEvent, *touch); 30 event->mFlags.mBubbles = false; 31 event->mFlags.mCancelable = false; 32 event->convertToPointerRawUpdate = false; 33 } 34 } 35 36 void CoalescedTouchData::Coalesce(const WidgetTouchEvent& aEvent, 37 const ScrollableLayerGuid& aGuid, 38 const uint64_t& aInputBlockId, 39 const nsEventStatus& aApzResponse) { 40 MOZ_ASSERT(aEvent.mMessage == eTouchMove); 41 if (IsEmpty()) { 42 CreateCoalescedTouchEvent(aEvent); 43 mGuid = aGuid; 44 mInputBlockId = aInputBlockId; 45 mApzResponse = aApzResponse; 46 } else { 47 MOZ_ASSERT(mGuid == aGuid); 48 MOZ_ASSERT(mInputBlockId == aInputBlockId); 49 MOZ_ASSERT(mCoalescedInputEvent->mModifiers == aEvent.mModifiers); 50 MOZ_ASSERT(mCoalescedInputEvent->mInputSource == aEvent.mInputSource); 51 52 for (const RefPtr<Touch>& touch : aEvent.mTouches) { 53 // Get the same touch in the original event 54 const RefPtr<Touch> sameTouch = GetTouch(touch->Identifier()); 55 // The checks in CoalescedTouchData::CanCoalesce ensure it should never 56 // be null. 57 MOZ_ASSERT(sameTouch); 58 MOZ_ASSERT(sameTouch->mCoalescedWidgetEvents); 59 MOZ_ASSERT(!sameTouch->mCoalescedWidgetEvents->mEvents.IsEmpty()); 60 if (!sameTouch->Equals(touch)) { 61 sameTouch->SetSameAs(touch); 62 sameTouch->convertToPointerRawUpdate = touch->convertToPointerRawUpdate; 63 WidgetPointerEvent* event = 64 sameTouch->mCoalescedWidgetEvents->mEvents.AppendElement( 65 WidgetPointerEvent(aEvent.IsTrusted(), ePointerMove, 66 aEvent.mWidget)); 67 PointerEventHandler::InitPointerEventFromTouch(*event, aEvent, *touch); 68 event->mFlags.mBubbles = false; 69 event->mFlags.mCancelable = false; 70 } 71 } 72 73 mCoalescedInputEvent->mTimeStamp = aEvent.mTimeStamp; 74 } 75 } 76 77 void CoalescedTouchData::NotifyTouchRawUpdateOfHandled( 78 const WidgetTouchEvent& aEvent) { 79 if (IsEmpty()) { 80 return; 81 } 82 for (const RefPtr<Touch>& touch : aEvent.mTouches) { 83 if (const RefPtr<Touch> sameTouch = GetTouch(touch->Identifier())) { 84 sameTouch->convertToPointerRawUpdate = false; 85 } 86 } 87 } 88 89 bool CoalescedTouchData::CanCoalesce(const WidgetTouchEvent& aEvent, 90 const ScrollableLayerGuid& aGuid, 91 const uint64_t& aInputBlockId, 92 const nsEventStatus& aApzResponse) { 93 MOZ_ASSERT(!IsEmpty()); 94 if (mGuid != aGuid || mInputBlockId != aInputBlockId || 95 mCoalescedInputEvent->mModifiers != aEvent.mModifiers || 96 mCoalescedInputEvent->mInputSource != aEvent.mInputSource || 97 aEvent.mTouches.Length() > sMaxTouchMoveIdentifiers) { 98 return false; 99 } 100 101 // Ensures both touchmove events have the same touches 102 if (aEvent.mTouches.Length() != mCoalescedInputEvent->mTouches.Length()) { 103 return false; 104 } 105 for (const RefPtr<Touch>& touch : aEvent.mTouches) { 106 if (!GetTouch(touch->Identifier())) { 107 return false; 108 } 109 } 110 111 // If one of them is eIgnore and the other one is eConsumeDoDefault, 112 // we always coalesce them to eConsumeDoDefault. 113 if (mApzResponse != aApzResponse) { 114 if (mApzResponse == nsEventStatus::nsEventStatus_eIgnore && 115 aApzResponse == nsEventStatus::nsEventStatus_eConsumeDoDefault) { 116 mApzResponse = aApzResponse; 117 } else if (mApzResponse != nsEventStatus::nsEventStatus_eConsumeDoDefault || 118 aApzResponse != nsEventStatus::nsEventStatus_eIgnore) { 119 return false; 120 } 121 } 122 123 return true; 124 } 125 126 Touch* CoalescedTouchData::GetTouch(int32_t aIdentifier) { 127 for (const RefPtr<Touch>& touch : mCoalescedInputEvent->mTouches) { 128 if (touch->Identifier() == aIdentifier) { 129 return touch; 130 } 131 } 132 return nullptr; 133 } 134 135 void CoalescedTouchMoveFlusher::WillRefresh(mozilla::TimeStamp aTime) { 136 MOZ_ASSERT(mRefreshDriver); 137 mBrowserChild->ProcessPendingCoalescedTouchData(); 138 } 139 140 CoalescedTouchMoveFlusher::CoalescedTouchMoveFlusher( 141 BrowserChild* aBrowserChild) 142 : CoalescedInputFlusher(aBrowserChild) {} 143 144 CoalescedTouchMoveFlusher::~CoalescedTouchMoveFlusher() { RemoveObserver(); }