tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

APZInputBridgeChild.cpp (9820B)


      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 "mozilla/layers/APZInputBridgeChild.h"
      8 
      9 #include "InputData.h"  // for InputData, etc
     10 #include "mozilla/gfx/GPUProcessManager.h"
     11 #include "mozilla/ipc/Endpoint.h"
     12 #include "mozilla/layers/APZThreadUtils.h"
     13 #include "mozilla/layers/SynchronousTask.h"
     14 
     15 #include "mozilla/layers/GeckoContentController.h"  // for GeckoContentController
     16 #include "mozilla/layers/DoubleTapToZoom.h"  // for DoubleTapToZoomMetrics
     17 #include "mozilla/layers/RemoteCompositorSession.h"  // for RemoteCompositorSession
     18 #include "mozilla/dom/BrowserParent.h"               // for BrowserParent
     19 #ifdef MOZ_WIDGET_ANDROID
     20 #  include "mozilla/jni/Utils.h"  // for DispatchToGeckoPriorityQueue
     21 #endif
     22 
     23 namespace mozilla {
     24 namespace layers {
     25 
     26 /* static */
     27 RefPtr<APZInputBridgeChild> APZInputBridgeChild::Create(
     28    const uint64_t& aProcessToken, Endpoint<PAPZInputBridgeChild>&& aEndpoint) {
     29  RefPtr<APZInputBridgeChild> child = new APZInputBridgeChild(aProcessToken);
     30 
     31  MOZ_ASSERT(APZThreadUtils::IsControllerThreadAlive());
     32 
     33  APZThreadUtils::RunOnControllerThread(
     34      NewRunnableMethod<Endpoint<PAPZInputBridgeChild>&&>(
     35          "layers::APZInputBridgeChild::Open", child,
     36          &APZInputBridgeChild::Open, std::move(aEndpoint)));
     37 
     38  return child;
     39 }
     40 
     41 APZInputBridgeChild::APZInputBridgeChild(const uint64_t& aProcessToken)
     42    : mIsOpen(false),
     43      mProcessToken(aProcessToken),
     44      mCompositorSession(nullptr) {
     45  MOZ_ASSERT(XRE_IsParentProcess());
     46  MOZ_ASSERT(NS_IsMainThread());
     47 }
     48 
     49 APZInputBridgeChild::~APZInputBridgeChild() = default;
     50 
     51 void APZInputBridgeChild::SetCompositorSession(
     52    RemoteCompositorSession* aSession) {
     53  mCompositorSession = aSession;
     54 }
     55 
     56 void APZInputBridgeChild::Open(Endpoint<PAPZInputBridgeChild>&& aEndpoint) {
     57  APZThreadUtils::AssertOnControllerThread();
     58 
     59  mIsOpen = aEndpoint.Bind(this);
     60 
     61  if (!mIsOpen) {
     62    // The GPU Process Manager might be gone if we receive ActorDestroy very
     63    // late in shutdown.
     64    if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) {
     65      gpm->NotifyRemoteActorDestroyed(mProcessToken);
     66    }
     67    return;
     68  }
     69 }
     70 
     71 void APZInputBridgeChild::Destroy() {
     72  MOZ_ASSERT(XRE_IsParentProcess());
     73  MOZ_ASSERT(NS_IsMainThread());
     74 
     75  // Destroy will get called from the main thread, so we must synchronously
     76  // dispatch to the controller thread to close the bridge.
     77  layers::SynchronousTask task("layers::APZInputBridgeChild::Destroy");
     78  APZThreadUtils::RunOnControllerThread(
     79      NS_NewRunnableFunction("layers::APZInputBridgeChild::Destroy", [&]() {
     80        APZThreadUtils::AssertOnControllerThread();
     81        AutoCompleteTask complete(&task);
     82 
     83        // Clear the process token so that we don't notify the GPUProcessManager
     84        // about an abnormal shutdown, thereby tearing down the GPU process.
     85        mProcessToken = 0;
     86 
     87        if (mIsOpen) {
     88          PAPZInputBridgeChild::Close();
     89          mIsOpen = false;
     90        }
     91      }));
     92 
     93  task.Wait();
     94 }
     95 
     96 void APZInputBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
     97  mIsOpen = false;
     98 
     99  if (mProcessToken) {
    100    gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    101    mProcessToken = 0;
    102  }
    103 }
    104 
    105 APZEventResult APZInputBridgeChild::ReceiveInputEvent(
    106    InputData& aEvent, InputBlockCallback&& aCallback) {
    107  MOZ_ASSERT(mIsOpen);
    108  APZThreadUtils::AssertOnControllerThread();
    109 
    110  APZEventResult res;
    111  switch (aEvent.mInputType) {
    112    case MULTITOUCH_INPUT: {
    113      MultiTouchInput& event = aEvent.AsMultiTouchInput();
    114      MultiTouchInput processedEvent;
    115 
    116      SendReceiveMultiTouchInputEvent(event, !!aCallback, &res,
    117                                      &processedEvent);
    118 
    119      event = processedEvent;
    120      break;
    121    }
    122    case MOUSE_INPUT: {
    123      MouseInput& event = aEvent.AsMouseInput();
    124      MouseInput processedEvent;
    125 
    126      SendReceiveMouseInputEvent(event, !!aCallback, &res, &processedEvent);
    127 
    128      event = processedEvent;
    129      break;
    130    }
    131    case PANGESTURE_INPUT: {
    132      PanGestureInput& event = aEvent.AsPanGestureInput();
    133      PanGestureInput processedEvent;
    134 
    135      SendReceivePanGestureInputEvent(event, !!aCallback, &res,
    136                                      &processedEvent);
    137 
    138      event = processedEvent;
    139      break;
    140    }
    141    case PINCHGESTURE_INPUT: {
    142      PinchGestureInput& event = aEvent.AsPinchGestureInput();
    143      PinchGestureInput processedEvent;
    144 
    145      SendReceivePinchGestureInputEvent(event, !!aCallback, &res,
    146                                        &processedEvent);
    147 
    148      event = processedEvent;
    149      break;
    150    }
    151    case TAPGESTURE_INPUT: {
    152      TapGestureInput& event = aEvent.AsTapGestureInput();
    153      TapGestureInput processedEvent;
    154 
    155      SendReceiveTapGestureInputEvent(event, !!aCallback, &res,
    156                                      &processedEvent);
    157 
    158      event = processedEvent;
    159      break;
    160    }
    161    case SCROLLWHEEL_INPUT: {
    162      ScrollWheelInput& event = aEvent.AsScrollWheelInput();
    163      ScrollWheelInput processedEvent;
    164 
    165      SendReceiveScrollWheelInputEvent(event, !!aCallback, &res,
    166                                       &processedEvent);
    167 
    168      event = processedEvent;
    169      break;
    170    }
    171    case KEYBOARD_INPUT: {
    172      KeyboardInput& event = aEvent.AsKeyboardInput();
    173      KeyboardInput processedEvent;
    174 
    175      SendReceiveKeyboardInputEvent(event, !!aCallback, &res, &processedEvent);
    176 
    177      event = processedEvent;
    178      break;
    179    }
    180    default: {
    181      MOZ_ASSERT_UNREACHABLE("Invalid InputData type.");
    182      res.SetStatusAsConsumeNoDefault();
    183      break;
    184    }
    185  }
    186 
    187  if (aCallback && res.WillHaveDelayedResult()) {
    188    mInputBlockCallbacks.emplace(res.mInputBlockId, std::move(aCallback));
    189  }
    190 
    191  return res;
    192 }
    193 
    194 void APZInputBridgeChild::HandleTapOnMainThread(
    195    const TapType& aType, const LayoutDevicePoint& aPoint,
    196    const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid,
    197    const uint64_t& aInputBlockId,
    198    const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
    199  if (mCompositorSession &&
    200      mCompositorSession->RootLayerTreeId() == aGuid.mLayersId &&
    201      mCompositorSession->GetContentController()) {
    202    RefPtr<GeckoContentController> controller =
    203        mCompositorSession->GetContentController();
    204    controller->HandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId,
    205                          aDoubleTapToZoomMetrics);
    206    return;
    207  }
    208  dom::BrowserParent* tab =
    209      dom::BrowserParent::GetBrowserParentFromLayersId(aGuid.mLayersId);
    210  if (tab) {
    211 #ifdef MOZ_WIDGET_ANDROID
    212    // On Android, touch events are dispatched from the UI thread to the main
    213    // thread using the Android priority queue. It is possible that this tap has
    214    // made it to the GPU process and back before they have been processed. We
    215    // must therefore dispatch this message to the same queue, otherwise the tab
    216    // may receive the tap event before the touch events that synthesized it.
    217    mozilla::jni::DispatchToGeckoPriorityQueue(
    218        NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
    219                          ScrollableLayerGuid, uint64_t,
    220                          Maybe<DoubleTapToZoomMetrics>>(
    221            "dom::BrowserParent::SendHandleTap", tab,
    222            &dom::BrowserParent::SendHandleTap, aType, aPoint, aModifiers,
    223            aGuid, aInputBlockId, aDoubleTapToZoomMetrics));
    224 #else
    225    tab->SendHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId,
    226                       aDoubleTapToZoomMetrics);
    227 #endif
    228  }
    229 }
    230 
    231 mozilla::ipc::IPCResult APZInputBridgeChild::RecvHandleTap(
    232    const TapType& aType, const LayoutDevicePoint& aPoint,
    233    const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid,
    234    const uint64_t& aInputBlockId,
    235    const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
    236  if (NS_IsMainThread()) {
    237    HandleTapOnMainThread(aType, aPoint, aModifiers, aGuid, aInputBlockId,
    238                          aDoubleTapToZoomMetrics);
    239  } else {
    240    NS_DispatchToMainThread(
    241        NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
    242                          ScrollableLayerGuid, uint64_t,
    243                          Maybe<DoubleTapToZoomMetrics>>(
    244            "layers::APZInputBridgeChild::HandleTapOnMainThread", this,
    245            &APZInputBridgeChild::HandleTapOnMainThread, aType, aPoint,
    246            aModifiers, aGuid, aInputBlockId, aDoubleTapToZoomMetrics));
    247  }
    248  return IPC_OK();
    249 }
    250 
    251 mozilla::ipc::IPCResult APZInputBridgeChild::RecvCallInputBlockCallback(
    252    uint64_t aInputBlockId, const APZHandledResult& aHandledResult) {
    253  auto it = mInputBlockCallbacks.find(aInputBlockId);
    254  if (it != mInputBlockCallbacks.end()) {
    255    it->second(aInputBlockId, aHandledResult);
    256    // The callback is one-shot; discard it after calling it.
    257    mInputBlockCallbacks.erase(it);
    258  }
    259 
    260  return IPC_OK();
    261 }
    262 
    263 void APZInputBridgeChild::ProcessUnhandledEvent(
    264    LayoutDeviceIntPoint* aRefPoint, ScrollableLayerGuid* aOutTargetGuid,
    265    uint64_t* aOutFocusSequenceNumber, LayersId* aOutLayersId) {
    266  MOZ_ASSERT(mIsOpen);
    267  APZThreadUtils::AssertOnControllerThread();
    268 
    269  SendProcessUnhandledEvent(*aRefPoint, aRefPoint, aOutTargetGuid,
    270                            aOutFocusSequenceNumber, aOutLayersId);
    271 }
    272 
    273 void APZInputBridgeChild::UpdateWheelTransaction(
    274    LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage,
    275    const Maybe<ScrollableLayerGuid>& aTargetGuid) {
    276  MOZ_ASSERT(mIsOpen);
    277  APZThreadUtils::AssertOnControllerThread();
    278 
    279  SendUpdateWheelTransaction(aRefPoint, aEventMessage, aTargetGuid);
    280 }
    281 
    282 }  // namespace layers
    283 }  // namespace mozilla