gfx/layers/ipc/RemoteContentController.cpp
author Bas Schouten <bschouten@mozilla.com>
Thu, 13 Dec 2018 15:59:22 +0100
changeset 509994 4c1fade7ceeb6407592d43ad0276c4b8090c3e7a
parent 505383 6f3709b3878117466168c40affa7bca0b60cf75b
child 521268 91d0c9066fd139285e025b0b87a70f61823281af
permissions -rw-r--r--
Bug 1501442 - Part 1: Add CompositionPayload type and allow submitting it as part of a transaction. r=mstange

/* -*- 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/RemoteContentController.h"

#include "base/message_loop.h"
#include "base/task.h"
#include "MainThreadUtils.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/Unused.h"
#include "Units.h"

namespace mozilla {
namespace layers {

using namespace mozilla::gfx;

RemoteContentController::RemoteContentController()
    : mCompositorThread(MessageLoop::current()), mCanSend(true) {}

RemoteContentController::~RemoteContentController() {}

void RemoteContentController::RequestContentRepaint(
    const RepaintRequest& aRequest) {
  MOZ_ASSERT(IsRepaintThread());

  if (mCanSend) {
    Unused << SendRequestContentRepaint(aRequest);
  }
}

void RemoteContentController::HandleTapOnMainThread(TapType aTapType,
                                                    LayoutDevicePoint aPoint,
                                                    Modifiers aModifiers,
                                                    ScrollableLayerGuid aGuid,
                                                    uint64_t aInputBlockId) {
  MOZ_ASSERT(NS_IsMainThread());

  dom::TabParent* tab =
      dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
  if (tab) {
    tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
  }
}

void RemoteContentController::HandleTapOnCompositorThread(
    TapType aTapType, LayoutDevicePoint aPoint, Modifiers aModifiers,
    ScrollableLayerGuid aGuid, uint64_t aInputBlockId) {
  MOZ_ASSERT(XRE_IsGPUProcess());
  MOZ_ASSERT(MessageLoop::current() == mCompositorThread);

  // The raw pointer to APZCTreeManagerParent is ok here because we are on the
  // compositor thread.
  APZCTreeManagerParent* apzctmp =
      CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
  if (apzctmp) {
    Unused << apzctmp->SendHandleTap(aTapType, aPoint, aModifiers, aGuid,
                                     aInputBlockId);
  }
}

void RemoteContentController::HandleTap(TapType aTapType,
                                        const LayoutDevicePoint& aPoint,
                                        Modifiers aModifiers,
                                        const ScrollableLayerGuid& aGuid,
                                        uint64_t aInputBlockId) {
  APZThreadUtils::AssertOnControllerThread();

  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
    if (MessageLoop::current() == mCompositorThread) {
      HandleTapOnCompositorThread(aTapType, aPoint, aModifiers, aGuid,
                                  aInputBlockId);
    } else {
      // We have to send messages from the compositor thread
      mCompositorThread->PostTask(
          NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
                            ScrollableLayerGuid, uint64_t>(
              "layers::RemoteContentController::HandleTapOnCompositorThread",
              this, &RemoteContentController::HandleTapOnCompositorThread,
              aTapType, aPoint, aModifiers, aGuid, aInputBlockId));
    }
    return;
  }

  MOZ_ASSERT(XRE_IsParentProcess());

  if (NS_IsMainThread()) {
    HandleTapOnMainThread(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
  } else {
    // We don't want to get the TabParent or call TabParent::SendHandleTap()
    // from a non-main thread (this might happen on Android, where this is
    // called from the Java UI thread)
    NS_DispatchToMainThread(
        NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
                          ScrollableLayerGuid, uint64_t>(
            "layers::RemoteContentController::HandleTapOnMainThread", this,
            &RemoteContentController::HandleTapOnMainThread, aTapType, aPoint,
            aModifiers, aGuid, aInputBlockId));
  }
}

void RemoteContentController::NotifyPinchGestureOnCompositorThread(
    PinchGestureInput::PinchGestureType aType, const ScrollableLayerGuid& aGuid,
    LayoutDeviceCoord aSpanChange, Modifiers aModifiers) {
  MOZ_ASSERT(MessageLoop::current() == mCompositorThread);

  // The raw pointer to APZCTreeManagerParent is ok here because we are on the
  // compositor thread.
  APZCTreeManagerParent* apzctmp =
      CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
  if (apzctmp) {
    Unused << apzctmp->SendNotifyPinchGesture(aType, aGuid, aSpanChange,
                                              aModifiers);
  }
}

void RemoteContentController::NotifyPinchGesture(
    PinchGestureInput::PinchGestureType aType, const ScrollableLayerGuid& aGuid,
    LayoutDeviceCoord aSpanChange, Modifiers aModifiers) {
  APZThreadUtils::AssertOnControllerThread();

  // For now we only ever want to handle this NotifyPinchGesture message in
  // the parent process, even if the APZ is sending it to a content process.

  // If we're in the GPU process, try to find a handle to the parent process
  // and send it there.
  if (XRE_IsGPUProcess()) {
    if (MessageLoop::current() == mCompositorThread) {
      NotifyPinchGestureOnCompositorThread(aType, aGuid, aSpanChange,
                                           aModifiers);
    } else {
      mCompositorThread->PostTask(
          NewRunnableMethod<PinchGestureInput::PinchGestureType,
                            ScrollableLayerGuid, LayoutDeviceCoord, Modifiers>(
              "layers::RemoteContentController::"
              "NotifyPinchGestureOnCompositorThread",
              this,
              &RemoteContentController::NotifyPinchGestureOnCompositorThread,
              aType, aGuid, aSpanChange, aModifiers));
    }
    return;
  }

  // If we're in the parent process, handle it directly. We don't have a handle
  // to the widget though, so we fish out the ChromeProcessController and
  // delegate to that instead.
  if (XRE_IsParentProcess()) {
    MOZ_ASSERT(NS_IsMainThread());
    RefPtr<GeckoContentController> rootController =
        CompositorBridgeParent::GetGeckoContentControllerForRoot(
            aGuid.mLayersId);
    if (rootController) {
      rootController->NotifyPinchGesture(aType, aGuid, aSpanChange, aModifiers);
    }
  }
}

void RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask,
                                              int aDelayMs) {
  (MessageLoop::current() ? MessageLoop::current() : mCompositorThread)
      ->PostDelayedTask(std::move(aTask), aDelayMs);
}

bool RemoteContentController::IsRepaintThread() {
  return MessageLoop::current() == mCompositorThread;
}

void RemoteContentController::DispatchToRepaintThread(
    already_AddRefed<Runnable> aTask) {
  mCompositorThread->PostTask(std::move(aTask));
}

void RemoteContentController::NotifyAPZStateChange(
    const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg) {
  if (MessageLoop::current() != mCompositorThread) {
    // We have to send messages from the compositor thread
    mCompositorThread->PostTask(
        NewRunnableMethod<ScrollableLayerGuid, APZStateChange, int>(
            "layers::RemoteContentController::NotifyAPZStateChange", this,
            &RemoteContentController::NotifyAPZStateChange, aGuid, aChange,
            aArg));
    return;
  }

  if (mCanSend) {
    Unused << SendNotifyAPZStateChange(aGuid, aChange, aArg);
  }
}

void RemoteContentController::UpdateOverscrollVelocity(float aX, float aY,
                                                       bool aIsRootContent) {
  if (MessageLoop::current() != mCompositorThread) {
    mCompositorThread->PostTask(NewRunnableMethod<float, float, bool>(
        "layers::RemoteContentController::UpdateOverscrollVelocity", this,
        &RemoteContentController::UpdateOverscrollVelocity, aX, aY,
        aIsRootContent));
    return;
  }
  if (mCanSend) {
    Unused << SendUpdateOverscrollVelocity(aX, aY, aIsRootContent);
  }
}

void RemoteContentController::UpdateOverscrollOffset(float aX, float aY,
                                                     bool aIsRootContent) {
  if (MessageLoop::current() != mCompositorThread) {
    mCompositorThread->PostTask(NewRunnableMethod<float, float, bool>(
        "layers::RemoteContentController::UpdateOverscrollOffset", this,
        &RemoteContentController::UpdateOverscrollOffset, aX, aY,
        aIsRootContent));
    return;
  }
  if (mCanSend) {
    Unused << SendUpdateOverscrollOffset(aX, aY, aIsRootContent);
  }
}

void RemoteContentController::NotifyMozMouseScrollEvent(
    const ScrollableLayerGuid::ViewID& aScrollId, const nsString& aEvent) {
  if (MessageLoop::current() != mCompositorThread) {
    // We have to send messages from the compositor thread
    mCompositorThread->PostTask(
        NewRunnableMethod<ScrollableLayerGuid::ViewID, nsString>(
            "layers::RemoteContentController::NotifyMozMouseScrollEvent", this,
            &RemoteContentController::NotifyMozMouseScrollEvent, aScrollId,
            aEvent));
    return;
  }

  if (mCanSend) {
    Unused << SendNotifyMozMouseScrollEvent(aScrollId, aEvent);
  }
}

void RemoteContentController::NotifyFlushComplete() {
  MOZ_ASSERT(IsRepaintThread());

  if (mCanSend) {
    Unused << SendNotifyFlushComplete();
  }
}

void RemoteContentController::NotifyAsyncScrollbarDragInitiated(
    uint64_t aDragBlockId, const ScrollableLayerGuid::ViewID& aScrollId,
    ScrollDirection aDirection) {
  if (MessageLoop::current() != mCompositorThread) {
    // We have to send messages from the compositor thread
    mCompositorThread->PostTask(NewRunnableMethod<uint64_t,
                                                  ScrollableLayerGuid::ViewID,
                                                  ScrollDirection>(
        "layers::RemoteContentController::NotifyAsyncScrollbarDragInitiated",
        this, &RemoteContentController::NotifyAsyncScrollbarDragInitiated,
        aDragBlockId, aScrollId, aDirection));
    return;
  }

  if (mCanSend) {
    Unused << SendNotifyAsyncScrollbarDragInitiated(aDragBlockId, aScrollId,
                                                    aDirection);
  }
}

void RemoteContentController::NotifyAsyncScrollbarDragRejected(
    const ScrollableLayerGuid::ViewID& aScrollId) {
  if (MessageLoop::current() != mCompositorThread) {
    // We have to send messages from the compositor thread
    mCompositorThread->PostTask(NewRunnableMethod<ScrollableLayerGuid::ViewID>(
        "layers::RemoteContentController::NotifyAsyncScrollbarDragRejected",
        this, &RemoteContentController::NotifyAsyncScrollbarDragRejected,
        aScrollId));
    return;
  }

  if (mCanSend) {
    Unused << SendNotifyAsyncScrollbarDragRejected(aScrollId);
  }
}

void RemoteContentController::NotifyAsyncAutoscrollRejected(
    const ScrollableLayerGuid::ViewID& aScrollId) {
  if (MessageLoop::current() != mCompositorThread) {
    // We have to send messages from the compositor thread
    mCompositorThread->PostTask(NewRunnableMethod<ScrollableLayerGuid::ViewID>(
        "layers::RemoteContentController::NotifyAsyncAutoscrollRejected", this,
        &RemoteContentController::NotifyAsyncAutoscrollRejected, aScrollId));
    return;
  }

  if (mCanSend) {
    Unused << SendNotifyAsyncAutoscrollRejected(aScrollId);
  }
}

void RemoteContentController::CancelAutoscroll(
    const ScrollableLayerGuid& aGuid) {
  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
    CancelAutoscrollCrossProcess(aGuid);
  } else {
    CancelAutoscrollInProcess(aGuid);
  }
}

void RemoteContentController::CancelAutoscrollInProcess(
    const ScrollableLayerGuid& aGuid) {
  MOZ_ASSERT(XRE_IsParentProcess());

  if (!NS_IsMainThread()) {
    NS_DispatchToMainThread(NewRunnableMethod<ScrollableLayerGuid>(
        "layers::RemoteContentController::CancelAutoscrollInProcess", this,
        &RemoteContentController::CancelAutoscrollInProcess, aGuid));
    return;
  }

  APZCCallbackHelper::CancelAutoscroll(aGuid.mScrollId);
}

void RemoteContentController::CancelAutoscrollCrossProcess(
    const ScrollableLayerGuid& aGuid) {
  MOZ_ASSERT(XRE_IsGPUProcess());

  if (MessageLoop::current() != mCompositorThread) {
    mCompositorThread->PostTask(NewRunnableMethod<ScrollableLayerGuid>(
        "layers::RemoteContentController::CancelAutoscrollCrossProcess", this,
        &RemoteContentController::CancelAutoscrollCrossProcess, aGuid));
    return;
  }

  // The raw pointer to APZCTreeManagerParent is ok here because we are on the
  // compositor thread.
  if (APZCTreeManagerParent* parent =
          CompositorBridgeParent::GetApzcTreeManagerParentForRoot(
              aGuid.mLayersId)) {
    Unused << parent->SendCancelAutoscroll(aGuid.mScrollId);
  }
}

void RemoteContentController::ActorDestroy(ActorDestroyReason aWhy) {
  // This controller could possibly be kept alive longer after this
  // by a RefPtr, but it is no longer valid to send messages.
  mCanSend = false;
}

void RemoteContentController::Destroy() {
  if (mCanSend) {
    mCanSend = false;
    Unused << SendDestroy();
  }
}

}  // namespace layers
}  // namespace mozilla