/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/layers/APZInputBridgeChild.h" #include "InputData.h" // for InputData, etc #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/ipc/Endpoint.h" #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/SynchronousTask.h" namespace mozilla { namespace layers { /* static */ RefPtr APZInputBridgeChild::Create( const uint64_t& aProcessToken, Endpoint&& aEndpoint) { RefPtr child = new APZInputBridgeChild(aProcessToken); MOZ_ASSERT(APZThreadUtils::IsControllerThreadAlive()); APZThreadUtils::RunOnControllerThread( NewRunnableMethod&&>( "layers::APZInputBridgeChild::Open", child, &APZInputBridgeChild::Open, std::move(aEndpoint))); return child; } APZInputBridgeChild::APZInputBridgeChild(const uint64_t& aProcessToken) : mIsOpen(false), mProcessToken(aProcessToken) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); } APZInputBridgeChild::~APZInputBridgeChild() = default; void APZInputBridgeChild::Open(Endpoint&& aEndpoint) { APZThreadUtils::AssertOnControllerThread(); mIsOpen = aEndpoint.Bind(this); if (!mIsOpen) { // The GPU Process Manager might be gone if we receive ActorDestroy very // late in shutdown. if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) { gpm->NotifyRemoteActorDestroyed(mProcessToken); } return; } } void APZInputBridgeChild::Destroy() { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); // Destroy will get called from the main thread, so we must synchronously // dispatch to the controller thread to close the bridge. layers::SynchronousTask task("layers::APZInputBridgeChild::Destroy"); APZThreadUtils::RunOnControllerThread( NS_NewRunnableFunction("layers::APZInputBridgeChild::Destroy", [&]() { APZThreadUtils::AssertOnControllerThread(); AutoCompleteTask complete(&task); // Clear the process token so that we don't notify the GPUProcessManager // about an abnormal shutdown, thereby tearing down the GPU process. mProcessToken = 0; if (mIsOpen) { PAPZInputBridgeChild::Close(); mIsOpen = false; } })); task.Wait(); } void APZInputBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { mIsOpen = false; if (mProcessToken) { gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); mProcessToken = 0; } } APZEventResult APZInputBridgeChild::ReceiveInputEvent( InputData& aEvent, InputBlockCallback&& aCallback) { MOZ_ASSERT(mIsOpen); APZThreadUtils::AssertOnControllerThread(); APZEventResult res; switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { MultiTouchInput& event = aEvent.AsMultiTouchInput(); MultiTouchInput processedEvent; SendReceiveMultiTouchInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case MOUSE_INPUT: { MouseInput& event = aEvent.AsMouseInput(); MouseInput processedEvent; SendReceiveMouseInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case PANGESTURE_INPUT: { PanGestureInput& event = aEvent.AsPanGestureInput(); PanGestureInput processedEvent; SendReceivePanGestureInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case PINCHGESTURE_INPUT: { PinchGestureInput& event = aEvent.AsPinchGestureInput(); PinchGestureInput processedEvent; SendReceivePinchGestureInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case TAPGESTURE_INPUT: { TapGestureInput& event = aEvent.AsTapGestureInput(); TapGestureInput processedEvent; SendReceiveTapGestureInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case SCROLLWHEEL_INPUT: { ScrollWheelInput& event = aEvent.AsScrollWheelInput(); ScrollWheelInput processedEvent; SendReceiveScrollWheelInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } case KEYBOARD_INPUT: { KeyboardInput& event = aEvent.AsKeyboardInput(); KeyboardInput processedEvent; SendReceiveKeyboardInputEvent(event, !!aCallback, &res, &processedEvent); event = processedEvent; break; } default: { MOZ_ASSERT_UNREACHABLE("Invalid InputData type."); res.SetStatusAsConsumeNoDefault(); break; } } if (aCallback && res.WillHaveDelayedResult()) { mInputBlockCallbacks.emplace(res.mInputBlockId, std::move(aCallback)); } return res; } mozilla::ipc::IPCResult APZInputBridgeChild::RecvCallInputBlockCallback( uint64_t aInputBlockId, const APZHandledResult& aHandledResult) { auto it = mInputBlockCallbacks.find(aInputBlockId); if (it != mInputBlockCallbacks.end()) { it->second(aInputBlockId, aHandledResult); // The callback is one-shot; discard it after calling it. mInputBlockCallbacks.erase(it); } return IPC_OK(); } void APZInputBridgeChild::ProcessUnhandledEvent( LayoutDeviceIntPoint* aRefPoint, ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutFocusSequenceNumber, LayersId* aOutLayersId) { MOZ_ASSERT(mIsOpen); APZThreadUtils::AssertOnControllerThread(); SendProcessUnhandledEvent(*aRefPoint, aRefPoint, aOutTargetGuid, aOutFocusSequenceNumber, aOutLayersId); } void APZInputBridgeChild::UpdateWheelTransaction( LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage, const Maybe& aTargetGuid) { MOZ_ASSERT(mIsOpen); APZThreadUtils::AssertOnControllerThread(); SendUpdateWheelTransaction(aRefPoint, aEventMessage, aTargetGuid); } } // namespace layers } // namespace mozilla