tor-browser

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

RemoteContentController.cpp (21225B)


      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/RemoteContentController.h"
      8 
      9 #include "CompositorThread.h"
     10 #include "MainThreadUtils.h"
     11 #include "ipc/RemoteContentController.h"
     12 #include "mozilla/dom/BrowserParent.h"
     13 #include "mozilla/layers/APZCCallbackHelper.h"
     14 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
     15 #include "mozilla/layers/APZThreadUtils.h"
     16 #include "mozilla/layers/DoubleTapToZoom.h"
     17 #include "mozilla/layers/CompositorBridgeParent.h"
     18 #include "mozilla/layers/MatrixMessage.h"
     19 #include "mozilla/gfx/GPUProcessManager.h"
     20 #include "Units.h"
     21 #ifdef MOZ_WIDGET_ANDROID
     22 #  include "mozilla/jni/Utils.h"
     23 #endif
     24 
     25 static mozilla::LazyLogModule sApzRemoteLog("apz.cc.remote");
     26 
     27 namespace mozilla {
     28 namespace layers {
     29 
     30 using namespace mozilla::gfx;
     31 
     32 RemoteContentController::RemoteContentController()
     33    : mCompositorThread(NS_GetCurrentThread()), mCanSend(true) {
     34  MOZ_ASSERT(CompositorThread()->IsOnCurrentThread());
     35 }
     36 
     37 RemoteContentController::~RemoteContentController() = default;
     38 
     39 void RemoteContentController::NotifyLayerTransforms(
     40    nsTArray<MatrixMessage>&& aTransforms) {
     41  if (!mCompositorThread->IsOnCurrentThread()) {
     42    // We have to send messages from the compositor thread
     43    mCompositorThread->Dispatch(
     44        NewRunnableMethod<StoreCopyPassByRRef<nsTArray<MatrixMessage>>>(
     45            "layers::RemoteContentController::NotifyLayerTransforms", this,
     46            &RemoteContentController::NotifyLayerTransforms,
     47            std::move(aTransforms)));
     48    return;
     49  }
     50 
     51  if (mCanSend) {
     52    (void)SendLayerTransforms(aTransforms);
     53  }
     54 }
     55 
     56 void RemoteContentController::RequestContentRepaint(
     57    const RepaintRequest& aRequest) {
     58  MOZ_ASSERT(IsRepaintThread());
     59 
     60  if (mCanSend) {
     61    (void)SendRequestContentRepaint(aRequest);
     62  }
     63 }
     64 
     65 void RemoteContentController::HandleTapOnParentProcessMainThread(
     66    TapType aTapType, LayoutDevicePoint aPoint, Modifiers aModifiers,
     67    ScrollableLayerGuid aGuid, uint64_t aInputBlockId,
     68    const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
     69  MOZ_LOG(sApzRemoteLog, LogLevel::Debug,
     70          ("HandleTapOnMainThread(%d)", (int)aTapType));
     71  MOZ_ASSERT(NS_IsMainThread());
     72 
     73  dom::BrowserParent* tab =
     74      dom::BrowserParent::GetBrowserParentFromLayersId(aGuid.mLayersId);
     75  if (tab) {
     76    tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId,
     77                       aDoubleTapToZoomMetrics);
     78  }
     79 }
     80 
     81 void RemoteContentController::HandleTapOnGPUProcessMainThread(
     82    TapType aTapType, LayoutDevicePoint aPoint, Modifiers aModifiers,
     83    ScrollableLayerGuid aGuid, uint64_t aInputBlockId,
     84    const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
     85  MOZ_ASSERT(XRE_IsGPUProcess());
     86  MOZ_ASSERT(NS_IsMainThread());
     87 
     88  // Send a message to the controller thread to handle the single-tap gesture.
     89  APZInputBridgeParent* apzib =
     90      CompositorBridgeParent::GetApzInputBridgeParentForRoot(aGuid.mLayersId);
     91  if (apzib) {
     92    (void)apzib->SendHandleTap(aTapType, aPoint, aModifiers, aGuid,
     93                               aInputBlockId, aDoubleTapToZoomMetrics);
     94  }
     95 }
     96 
     97 void RemoteContentController::HandleTap(
     98    TapType aTapType, const LayoutDevicePoint& aPoint, Modifiers aModifiers,
     99    const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId,
    100    const Maybe<DoubleTapToZoomMetrics>& aDoubleTapToZoomMetrics) {
    101  MOZ_LOG(sApzRemoteLog, LogLevel::Debug, ("HandleTap(%d)", (int)aTapType));
    102  APZThreadUtils::AssertOnControllerThread();
    103 
    104  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
    105    if (NS_IsMainThread()) {
    106      HandleTapOnGPUProcessMainThread(aTapType, aPoint, aModifiers, aGuid,
    107                                      aInputBlockId, aDoubleTapToZoomMetrics);
    108    } else {
    109      NS_DispatchToMainThread(NewRunnableMethod<TapType, LayoutDevicePoint,
    110                                                Modifiers, ScrollableLayerGuid,
    111                                                uint64_t,
    112                                                Maybe<DoubleTapToZoomMetrics>>(
    113          "layers::RemoteContentController::HandleTapOnGPUProcessMainThread",
    114          this, &RemoteContentController::HandleTapOnGPUProcessMainThread,
    115          aTapType, aPoint, aModifiers, aGuid, aInputBlockId,
    116          aDoubleTapToZoomMetrics));
    117    }
    118    return;
    119  }
    120 
    121  MOZ_ASSERT(XRE_IsParentProcess());
    122 
    123  if (NS_IsMainThread()) {
    124    HandleTapOnParentProcessMainThread(aTapType, aPoint, aModifiers, aGuid,
    125                                       aInputBlockId, aDoubleTapToZoomMetrics);
    126  } else {
    127    // We must be on Android, running on the Java UI thread
    128 #ifndef MOZ_WIDGET_ANDROID
    129    MOZ_ASSERT(false);
    130 #else
    131    // We don't want to get the BrowserParent or call
    132    // BrowserParent::SendHandleTap() from a non-main thread, so we need to
    133    // redispatch to the main thread. However, we should use the same
    134    // mechanism that the Android widget uses when dispatching input events
    135    // to Gecko, which is nsAppShell::PostEvent. Note in particular that
    136    // using NS_DispatchToMainThread would post to a different message loop,
    137    // and introduces the possibility of this tap event getting processed
    138    // out of order with respect to the touch events that synthesized it.
    139    mozilla::jni::DispatchToGeckoPriorityQueue(NewRunnableMethod<
    140                                               TapType, LayoutDevicePoint,
    141                                               Modifiers, ScrollableLayerGuid,
    142                                               uint64_t,
    143                                               Maybe<DoubleTapToZoomMetrics>>(
    144        "layers::RemoteContentController::HandleTapOnParentProcessMainThread",
    145        this, &RemoteContentController::HandleTapOnParentProcessMainThread,
    146        aTapType, aPoint, aModifiers, aGuid, aInputBlockId,
    147        aDoubleTapToZoomMetrics));
    148 #endif
    149  }
    150 }
    151 
    152 void RemoteContentController::NotifyPinchGestureOnCompositorThread(
    153    PinchGestureInput::PinchGestureType aType, const ScrollableLayerGuid& aGuid,
    154    const LayoutDevicePoint& aFocusPoint, LayoutDeviceCoord aSpanChange,
    155    Modifiers aModifiers) {
    156  MOZ_ASSERT(mCompositorThread->IsOnCurrentThread());
    157 
    158  // The raw pointer to APZCTreeManagerParent is ok here because we are on
    159  // the compositor thread.
    160  APZCTreeManagerParent* apzctmp =
    161      CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
    162  if (apzctmp) {
    163    (void)apzctmp->SendNotifyPinchGesture(aType, aGuid, aFocusPoint,
    164                                          aSpanChange, aModifiers);
    165  }
    166 }
    167 
    168 void RemoteContentController::NotifyPinchGesture(
    169    PinchGestureInput::PinchGestureType aType, const ScrollableLayerGuid& aGuid,
    170    const LayoutDevicePoint& aFocusPoint, LayoutDeviceCoord aSpanChange,
    171    Modifiers aModifiers) {
    172  APZThreadUtils::AssertOnControllerThread();
    173 
    174  // For now we only ever want to handle this NotifyPinchGesture message in
    175  // the parent process, even if the APZ is sending it to a content process.
    176 
    177  // If we're in the GPU process, try to find a handle to the parent process
    178  // and send it there.
    179  if (XRE_IsGPUProcess()) {
    180    if (mCompositorThread->IsOnCurrentThread()) {
    181      NotifyPinchGestureOnCompositorThread(aType, aGuid, aFocusPoint,
    182                                           aSpanChange, aModifiers);
    183    } else {
    184      mCompositorThread->Dispatch(
    185          NewRunnableMethod<PinchGestureInput::PinchGestureType,
    186                            ScrollableLayerGuid, LayoutDevicePoint,
    187                            LayoutDeviceCoord, Modifiers>(
    188              "layers::RemoteContentController::"
    189              "NotifyPinchGestureOnCompositorThread",
    190              this,
    191              &RemoteContentController::NotifyPinchGestureOnCompositorThread,
    192              aType, aGuid, aFocusPoint, aSpanChange, aModifiers));
    193    }
    194    return;
    195  }
    196 
    197  // If we're in the parent process, handle it directly. We don't have a
    198  // handle to the widget though, so we fish out the ChromeProcessController
    199  // and delegate to that instead.
    200  if (XRE_IsParentProcess()) {
    201    MOZ_ASSERT(NS_IsMainThread());
    202    RefPtr<GeckoContentController> rootController =
    203        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    204            aGuid.mLayersId);
    205    if (rootController) {
    206      rootController->NotifyPinchGesture(aType, aGuid, aFocusPoint, aSpanChange,
    207                                         aModifiers);
    208    }
    209  }
    210 }
    211 
    212 bool RemoteContentController::IsRepaintThread() {
    213  return mCompositorThread->IsOnCurrentThread();
    214 }
    215 
    216 void RemoteContentController::DispatchToRepaintThread(
    217    already_AddRefed<Runnable> aTask) {
    218  mCompositorThread->Dispatch(std::move(aTask));
    219 }
    220 
    221 void RemoteContentController::NotifyAPZStateChange(
    222    const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg,
    223    Maybe<uint64_t> aInputBlockId) {
    224  if (!mCompositorThread->IsOnCurrentThread()) {
    225    // We have to send messages from the compositor thread
    226    mCompositorThread->Dispatch(
    227        NewRunnableMethod<ScrollableLayerGuid, APZStateChange, int,
    228                          Maybe<uint64_t>>(
    229            "layers::RemoteContentController::NotifyAPZStateChange", this,
    230            &RemoteContentController::NotifyAPZStateChange, aGuid, aChange,
    231            aArg, aInputBlockId));
    232    return;
    233  }
    234 
    235  if (mCanSend) {
    236    (void)SendNotifyAPZStateChange(aGuid, aChange, aArg, aInputBlockId);
    237  }
    238 }
    239 
    240 void RemoteContentController::UpdateOverscrollVelocity(
    241    const ScrollableLayerGuid& aGuid, float aX, float aY, bool aIsRootContent) {
    242  if (XRE_IsParentProcess()) {
    243 #ifdef MOZ_WIDGET_ANDROID
    244    // We always want these to go to the parent process on Android
    245    if (!NS_IsMainThread()) {
    246      mozilla::jni::DispatchToGeckoPriorityQueue(
    247          NewRunnableMethod<ScrollableLayerGuid, float, float, bool>(
    248              "layers::RemoteContentController::UpdateOverscrollVelocity", this,
    249              &RemoteContentController::UpdateOverscrollVelocity, aGuid, aX, aY,
    250              aIsRootContent));
    251      return;
    252    }
    253 #endif
    254 
    255    MOZ_RELEASE_ASSERT(NS_IsMainThread());
    256    RefPtr<GeckoContentController> rootController =
    257        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    258            aGuid.mLayersId);
    259    if (rootController) {
    260      rootController->UpdateOverscrollVelocity(aGuid, aX, aY, aIsRootContent);
    261    }
    262  } else if (XRE_IsGPUProcess()) {
    263    if (!mCompositorThread->IsOnCurrentThread()) {
    264      mCompositorThread->Dispatch(
    265          NewRunnableMethod<ScrollableLayerGuid, float, float, bool>(
    266              "layers::RemoteContentController::UpdateOverscrollVelocity", this,
    267              &RemoteContentController::UpdateOverscrollVelocity, aGuid, aX, aY,
    268              aIsRootContent));
    269      return;
    270    }
    271 
    272    MOZ_RELEASE_ASSERT(mCompositorThread->IsOnCurrentThread());
    273    GeckoContentController* rootController =
    274        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    275            aGuid.mLayersId);
    276    if (rootController) {
    277      MOZ_RELEASE_ASSERT(rootController->IsRemote());
    278      (void)static_cast<RemoteContentController*>(rootController)
    279          ->SendUpdateOverscrollVelocity(aGuid, aX, aY, aIsRootContent);
    280    }
    281  }
    282 }
    283 
    284 void RemoteContentController::UpdateOverscrollOffset(
    285    const ScrollableLayerGuid& aGuid, float aX, float aY, bool aIsRootContent) {
    286  if (XRE_IsParentProcess()) {
    287 #ifdef MOZ_WIDGET_ANDROID
    288    // We always want these to go to the parent process on Android
    289    if (!NS_IsMainThread()) {
    290      mozilla::jni::DispatchToGeckoPriorityQueue(
    291          NewRunnableMethod<ScrollableLayerGuid, float, float, bool>(
    292              "layers::RemoteContentController::UpdateOverscrollOffset", this,
    293              &RemoteContentController::UpdateOverscrollOffset, aGuid, aX, aY,
    294              aIsRootContent));
    295      return;
    296    }
    297 #endif
    298 
    299    MOZ_RELEASE_ASSERT(NS_IsMainThread());
    300    RefPtr<GeckoContentController> rootController =
    301        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    302            aGuid.mLayersId);
    303    if (rootController) {
    304      rootController->UpdateOverscrollOffset(aGuid, aX, aY, aIsRootContent);
    305    }
    306  } else if (XRE_IsGPUProcess()) {
    307    if (!mCompositorThread->IsOnCurrentThread()) {
    308      mCompositorThread->Dispatch(
    309          NewRunnableMethod<ScrollableLayerGuid, float, float, bool>(
    310              "layers::RemoteContentController::UpdateOverscrollOffset", this,
    311              &RemoteContentController::UpdateOverscrollOffset, aGuid, aX, aY,
    312              aIsRootContent));
    313      return;
    314    }
    315 
    316    MOZ_RELEASE_ASSERT(mCompositorThread->IsOnCurrentThread());
    317    GeckoContentController* rootController =
    318        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    319            aGuid.mLayersId);
    320    if (rootController) {
    321      MOZ_RELEASE_ASSERT(rootController->IsRemote());
    322      (void)static_cast<RemoteContentController*>(rootController)
    323          ->SendUpdateOverscrollOffset(aGuid, aX, aY, aIsRootContent);
    324    }
    325  }
    326 }
    327 
    328 void RemoteContentController::HideDynamicToolbar(
    329    const ScrollableLayerGuid& aGuid) {
    330  // We always want these to go to the parent process
    331  if (XRE_IsParentProcess()) {
    332 #ifdef MOZ_WIDGET_ANDROID
    333    if (!NS_IsMainThread()) {
    334      mozilla::jni::DispatchToGeckoPriorityQueue(
    335          NewRunnableMethod<ScrollableLayerGuid>(
    336              "layers::RemoteContentController::HideDynamicToolbar", this,
    337              &RemoteContentController::HideDynamicToolbar, aGuid));
    338      return;
    339    }
    340 #endif
    341 
    342    MOZ_RELEASE_ASSERT(NS_IsMainThread());
    343    RefPtr<GeckoContentController> rootController =
    344        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    345            aGuid.mLayersId);
    346    if (rootController) {
    347      rootController->HideDynamicToolbar(aGuid);
    348    }
    349  } else if (XRE_IsGPUProcess()) {
    350    if (!mCompositorThread->IsOnCurrentThread()) {
    351      mCompositorThread->Dispatch(NewRunnableMethod<ScrollableLayerGuid>(
    352          "layers::RemoteContentController::HideDynamicToolbar", this,
    353          &RemoteContentController::HideDynamicToolbar, aGuid));
    354      return;
    355    }
    356 
    357    MOZ_RELEASE_ASSERT(mCompositorThread->IsOnCurrentThread());
    358    GeckoContentController* rootController =
    359        CompositorBridgeParent::GetGeckoContentControllerForRoot(
    360            aGuid.mLayersId);
    361    if (rootController) {
    362      MOZ_RELEASE_ASSERT(rootController->IsRemote());
    363      (void)static_cast<RemoteContentController*>(rootController)
    364          ->SendHideDynamicToolbar();
    365    }
    366  }
    367 }
    368 
    369 void RemoteContentController::NotifyMozMouseScrollEvent(
    370    const ScrollableLayerGuid::ViewID& aScrollId, const nsString& aEvent) {
    371  if (!mCompositorThread->IsOnCurrentThread()) {
    372    // We have to send messages from the compositor thread
    373    mCompositorThread->Dispatch(
    374        NewRunnableMethod<ScrollableLayerGuid::ViewID, nsString>(
    375            "layers::RemoteContentController::NotifyMozMouseScrollEvent", this,
    376            &RemoteContentController::NotifyMozMouseScrollEvent, aScrollId,
    377            aEvent));
    378    return;
    379  }
    380 
    381  if (mCanSend) {
    382    (void)SendNotifyMozMouseScrollEvent(aScrollId, aEvent);
    383  }
    384 }
    385 
    386 void RemoteContentController::NotifyFlushComplete() {
    387  MOZ_ASSERT(IsRepaintThread());
    388 
    389  if (mCanSend) {
    390    (void)SendNotifyFlushComplete();
    391  }
    392 }
    393 
    394 void RemoteContentController::NotifyAsyncScrollbarDragInitiated(
    395    uint64_t aDragBlockId, const ScrollableLayerGuid::ViewID& aScrollId,
    396    ScrollDirection aDirection) {
    397  if (!mCompositorThread->IsOnCurrentThread()) {
    398    // We have to send messages from the compositor thread
    399    mCompositorThread->Dispatch(
    400        NewRunnableMethod<uint64_t, ScrollableLayerGuid::ViewID,
    401                          ScrollDirection>(
    402            "layers::RemoteContentController::"
    403            "NotifyAsyncScrollbarDragInitiated",
    404            this, &RemoteContentController::NotifyAsyncScrollbarDragInitiated,
    405            aDragBlockId, aScrollId, aDirection));
    406    return;
    407  }
    408 
    409  if (mCanSend) {
    410    (void)SendNotifyAsyncScrollbarDragInitiated(aDragBlockId, aScrollId,
    411                                                aDirection);
    412  }
    413 }
    414 
    415 void RemoteContentController::NotifyAsyncScrollbarDragRejected(
    416    const ScrollableLayerGuid::ViewID& aScrollId) {
    417  if (!mCompositorThread->IsOnCurrentThread()) {
    418    // We have to send messages from the compositor thread
    419    mCompositorThread->Dispatch(NewRunnableMethod<ScrollableLayerGuid::ViewID>(
    420        "layers::RemoteContentController::NotifyAsyncScrollbarDragRejected",
    421        this, &RemoteContentController::NotifyAsyncScrollbarDragRejected,
    422        aScrollId));
    423    return;
    424  }
    425 
    426  if (mCanSend) {
    427    (void)SendNotifyAsyncScrollbarDragRejected(aScrollId);
    428  }
    429 }
    430 
    431 void RemoteContentController::NotifyAsyncAutoscrollRejected(
    432    const ScrollableLayerGuid::ViewID& aScrollId) {
    433  if (!mCompositorThread->IsOnCurrentThread()) {
    434    // We have to send messages from the compositor thread
    435    mCompositorThread->Dispatch(NewRunnableMethod<ScrollableLayerGuid::ViewID>(
    436        "layers::RemoteContentController::NotifyAsyncAutoscrollRejected", this,
    437        &RemoteContentController::NotifyAsyncAutoscrollRejected, aScrollId));
    438    return;
    439  }
    440 
    441  if (mCanSend) {
    442    (void)SendNotifyAsyncAutoscrollRejected(aScrollId);
    443  }
    444 }
    445 
    446 void RemoteContentController::CancelAutoscroll(
    447    const ScrollableLayerGuid& aGuid) {
    448  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
    449    CancelAutoscrollCrossProcess(aGuid);
    450  } else {
    451    CancelAutoscrollInProcess(aGuid);
    452  }
    453 }
    454 
    455 void RemoteContentController::CancelAutoscrollInProcess(
    456    const ScrollableLayerGuid& aGuid) {
    457  MOZ_ASSERT(XRE_IsParentProcess());
    458  NS_DispatchToMainThread(NewRunnableFunction(
    459      "layers::CancelAutoScroll", &APZCCallbackHelper::CancelAutoscroll,
    460      aGuid.mScrollId));
    461 }
    462 
    463 void RemoteContentController::CancelAutoscrollCrossProcess(
    464    const ScrollableLayerGuid& aGuid) {
    465  MOZ_ASSERT(XRE_IsGPUProcess());
    466 
    467  if (!mCompositorThread->IsOnCurrentThread()) {
    468    mCompositorThread->Dispatch(NewRunnableMethod<ScrollableLayerGuid>(
    469        "layers::RemoteContentController::CancelAutoscrollCrossProcess", this,
    470        &RemoteContentController::CancelAutoscrollCrossProcess, aGuid));
    471    return;
    472  }
    473 
    474  // The raw pointer to APZCTreeManagerParent is ok here because we are on
    475  // the compositor thread.
    476  if (APZCTreeManagerParent* parent =
    477          CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
    478              aGuid.mLayersId)) {
    479    (void)parent->SendCancelAutoscroll(aGuid.mScrollId);
    480  }
    481 }
    482 
    483 void RemoteContentController::NotifyScaleGestureComplete(
    484    const ScrollableLayerGuid& aGuid, float aScale) {
    485  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
    486    NotifyScaleGestureCompleteCrossProcess(aGuid, aScale);
    487  } else {
    488    NotifyScaleGestureCompleteInProcess(aGuid, aScale);
    489  }
    490 }
    491 
    492 void RemoteContentController::NotifyScaleGestureCompleteInProcess(
    493    const ScrollableLayerGuid& aGuid, float aScale) {
    494  MOZ_ASSERT(XRE_IsParentProcess());
    495 
    496  if (!NS_IsMainThread()) {
    497    NS_DispatchToMainThread(NewRunnableMethod<ScrollableLayerGuid, float>(
    498        "layers::RemoteContentController::"
    499        "NotifyScaleGestureCompleteInProcess",
    500        this, &RemoteContentController::NotifyScaleGestureCompleteInProcess,
    501        aGuid, aScale));
    502    return;
    503  }
    504 
    505  RefPtr<GeckoContentController> rootController =
    506      CompositorBridgeParent::GetGeckoContentControllerForRoot(aGuid.mLayersId);
    507  if (rootController) {
    508    MOZ_ASSERT(rootController != this);
    509    if (rootController != this) {
    510      rootController->NotifyScaleGestureComplete(aGuid, aScale);
    511    }
    512  }
    513 }
    514 
    515 void RemoteContentController::NotifyScaleGestureCompleteCrossProcess(
    516    const ScrollableLayerGuid& aGuid, float aScale) {
    517  MOZ_ASSERT(XRE_IsGPUProcess());
    518 
    519  if (!mCompositorThread->IsOnCurrentThread()) {
    520    mCompositorThread->Dispatch(NewRunnableMethod<ScrollableLayerGuid, float>(
    521        "layers::RemoteContentController::"
    522        "NotifyScaleGestureCompleteCrossProcess",
    523        this, &RemoteContentController::NotifyScaleGestureCompleteCrossProcess,
    524        aGuid, aScale));
    525    return;
    526  }
    527 
    528  // The raw pointer to APZCTreeManagerParent is ok here because we are on
    529  // the compositor thread.
    530  if (APZCTreeManagerParent* parent =
    531          CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
    532              aGuid.mLayersId)) {
    533    (void)parent->SendNotifyScaleGestureComplete(aGuid.mScrollId, aScale);
    534  }
    535 }
    536 
    537 void RemoteContentController::ActorDestroy(ActorDestroyReason aWhy) {
    538  // This controller could possibly be kept alive longer after this
    539  // by a RefPtr, but it is no longer valid to send messages.
    540  mCanSend = false;
    541 }
    542 
    543 void RemoteContentController::Destroy() {
    544  if (mCanSend) {
    545    mCanSend = false;
    546    (void)SendDestroy();
    547  }
    548 }
    549 
    550 mozilla::ipc::IPCResult RemoteContentController::RecvDestroy() {
    551  // The actor on the other side is about to get destroyed, so let's not
    552  // send it any more messages.
    553  mCanSend = false;
    554  return IPC_OK();
    555 }
    556 
    557 bool RemoteContentController::IsRemote() { return true; }
    558 
    559 }  // namespace layers
    560 }  // namespace mozilla