gecko-dev/gfx/layers/ipc/RemoteContentController.cpp
Kartikaya Gupta d16ab46492 Bug 1445662 - Update RemoteContentController to allow the GPU process controller thread to be different from the compositor thread. r=rhunt
A couple of RemoteContentController methods get called on the controller
thread in the GPU process. This is the same as the compositor thread so
we could just do compositor-thread stuff here, but we will want to
support the controller thread being the main thread instead of the
compositor thread. So we detect those cases and bounce the message
accordingly.
2018-03-15 15:25:11 -04:00

410 lines
13 KiB
C++

/* -*- 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/ContentParent.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/layout/RenderFrameParent.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 FrameMetrics& aFrameMetrics)
{
MOZ_ASSERT(IsRepaintThread());
if (mCanSend) {
Unused << SendRequestContentRepaint(aFrameMetrics);
}
}
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(Move(aTask), aDelayMs);
}
bool
RemoteContentController::IsRepaintThread()
{
return MessageLoop::current() == mCompositorThread;
}
void
RemoteContentController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask)
{
mCompositorThread->PostTask(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 FrameMetrics::ViewID& aScrollId,
const nsString& aEvent)
{
if (MessageLoop::current() != mCompositorThread) {
// We have to send messages from the compositor thread
mCompositorThread->PostTask(
NewRunnableMethod<FrameMetrics::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::NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId)
{
if (MessageLoop::current() != mCompositorThread) {
// We have to send messages from the compositor thread
mCompositorThread->PostTask(NewRunnableMethod<FrameMetrics::ViewID>(
"layers::RemoteContentController::NotifyAsyncScrollbarDragRejected",
this,
&RemoteContentController::NotifyAsyncScrollbarDragRejected,
aScrollId));
return;
}
if (mCanSend) {
Unused << SendNotifyAsyncScrollbarDragRejected(aScrollId);
}
}
void
RemoteContentController::NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId)
{
if (MessageLoop::current() != mCompositorThread) {
// We have to send messages from the compositor thread
mCompositorThread->PostTask(NewRunnableMethod<FrameMetrics::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