Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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
#include "UiCompositorControllerParent.h"
#if defined(MOZ_WIDGET_ANDROID)
# include "apz/src/APZCTreeManager.h"
# include "mozilla/widget/AndroidCompositorWidget.h"
#endif
#include <utility>
#include "FrameMetrics.h"
#include "SynchronousTask.h"
#include "mozilla/Unused.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
namespace mozilla {
namespace layers {
typedef CompositorBridgeParent::LayerTreeState LayerTreeState;
/* static */
RefPtr<UiCompositorControllerParent>
UiCompositorControllerParent::GetFromRootLayerTreeId(
const LayersId& aRootLayerTreeId) {
RefPtr<UiCompositorControllerParent> controller;
CompositorBridgeParent::CallWithIndirectShadowTree(
aRootLayerTreeId, [&](LayerTreeState& aState) -> void {
controller = aState.mUiControllerParent;
});
return controller;
}
/* static */
RefPtr<UiCompositorControllerParent> UiCompositorControllerParent::Start(
const LayersId& aRootLayerTreeId,
Endpoint<PUiCompositorControllerParent>&& aEndpoint) {
RefPtr<UiCompositorControllerParent> parent =
new UiCompositorControllerParent(aRootLayerTreeId);
RefPtr<Runnable> task =
NewRunnableMethod<Endpoint<PUiCompositorControllerParent>&&>(
"layers::UiCompositorControllerParent::Open", parent,
&UiCompositorControllerParent::Open, std::move(aEndpoint));
CompositorThread()->Dispatch(task.forget());
return parent;
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvPause() {
CompositorBridgeParent* parent =
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
mRootLayerTreeId);
if (parent) {
parent->PauseComposition();
}
return IPC_OK();
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvResume(
bool* aOutResumed) {
*aOutResumed = false;
CompositorBridgeParent* parent =
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
mRootLayerTreeId);
if (parent) {
*aOutResumed = parent->ResumeComposition();
}
return IPC_OK();
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvResumeAndResize(
const int32_t& aX, const int32_t& aY, const int32_t& aWidth,
const int32_t& aHeight, bool* aOutResumed) {
*aOutResumed = false;
CompositorBridgeParent* parent =
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
mRootLayerTreeId);
if (parent) {
// Front-end expects a first paint callback upon resume/resize.
parent->ForceIsFirstPaint();
#if defined(MOZ_WIDGET_ANDROID)
parent->GetWidget()->AsAndroid()->NotifyClientSizeChanged(
LayoutDeviceIntSize(aWidth, aHeight));
#endif
*aOutResumed = parent->ResumeCompositionAndResize(aX, aY, aWidth, aHeight);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
UiCompositorControllerParent::RecvInvalidateAndRender() {
CompositorBridgeParent* parent =
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
mRootLayerTreeId);
if (parent) {
parent->ScheduleComposition(wr::RenderReasons::OTHER);
}
return IPC_OK();
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvMaxToolbarHeight(
const int32_t& aHeight) {
mMaxToolbarHeight = aHeight;
return IPC_OK();
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvFixedBottomOffset(
const int32_t& aOffset) {
#if defined(MOZ_WIDGET_ANDROID)
CompositorBridgeParent* parent =
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
mRootLayerTreeId);
if (parent) {
parent->SetFixedLayerMargins(0, aOffset);
}
#endif // defined(MOZ_WIDGET_ANDROID)
return IPC_OK();
}
mozilla::ipc::IPCResult UiCompositorControllerParent::RecvDefaultClearColor(
const uint32_t& aColor) {
LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
if (state && state->mWrBridge) {
state->mWrBridge->SetClearColor(gfx::DeviceColor::UnusualFromARGB(aColor));
}
return IPC_OK();
}
mozilla::ipc::IPCResult
UiCompositorControllerParent::RecvRequestScreenPixels() {
#if defined(MOZ_WIDGET_ANDROID)
LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
if (state && state->mWrBridge) {
state->mWrBridge->RequestScreenPixels(this);
state->mWrBridge->ScheduleForcedGenerateFrame(wr::RenderReasons::OTHER);
}
#endif // defined(MOZ_WIDGET_ANDROID)
return IPC_OK();
}
mozilla::ipc::IPCResult
UiCompositorControllerParent::RecvEnableLayerUpdateNotifications(
const bool& aEnable) {
#if defined(MOZ_WIDGET_ANDROID)
// Layers updates are need by Robocop test which enables them
mCompositorLayersUpdateEnabled = aEnable;
#endif // defined(MOZ_WIDGET_ANDROID)
return IPC_OK();
}
void UiCompositorControllerParent::ActorDestroy(ActorDestroyReason aWhy) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
Shutdown();
}
void UiCompositorControllerParent::ToolbarAnimatorMessageFromCompositor(
int32_t aMessage) {
// This function can be call from ether compositor or controller thread.
if (!CompositorThreadHolder::IsInCompositorThread()) {
CompositorThread()->Dispatch(NewRunnableMethod<int32_t>(
"layers::UiCompositorControllerParent::"
"ToolbarAnimatorMessageFromCompositor",
this,
&UiCompositorControllerParent::ToolbarAnimatorMessageFromCompositor,
aMessage));
return;
}
Unused << SendToolbarAnimatorMessageFromCompositor(aMessage);
}
bool UiCompositorControllerParent::AllocPixelBuffer(const int32_t aSize,
ipc::Shmem* aMem) {
MOZ_ASSERT(aSize > 0);
return AllocShmem(aSize, aMem);
}
void UiCompositorControllerParent::NotifyLayersUpdated() {
#ifdef MOZ_WIDGET_ANDROID
if (mCompositorLayersUpdateEnabled) {
ToolbarAnimatorMessageFromCompositor(LAYERS_UPDATED);
}
#endif
}
void UiCompositorControllerParent::NotifyFirstPaint() {
ToolbarAnimatorMessageFromCompositor(FIRST_PAINT);
}
void UiCompositorControllerParent::NotifyUpdateScreenMetrics(
const GeckoViewMetrics& aMetrics) {
#if defined(MOZ_WIDGET_ANDROID)
// TODO: Need to handle different x-and y-scales.
CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(
aMetrics.mZoom, PixelCastJustification::ScreenIsParentLayerForRoot);
ScreenPoint scrollOffset = aMetrics.mVisualScrollOffset * scale;
CompositorThread()->Dispatch(NewRunnableMethod<ScreenPoint, CSSToScreenScale>(
"UiCompositorControllerParent::SendRootFrameMetrics", this,
&UiCompositorControllerParent::SendRootFrameMetrics, scrollOffset,
scale));
#endif
}
UiCompositorControllerParent::UiCompositorControllerParent(
const LayersId& aRootLayerTreeId)
: mRootLayerTreeId(aRootLayerTreeId)
#ifdef MOZ_WIDGET_ANDROID
,
mCompositorLayersUpdateEnabled(false)
#endif
,
mMaxToolbarHeight(0) {
MOZ_COUNT_CTOR(UiCompositorControllerParent);
}
UiCompositorControllerParent::~UiCompositorControllerParent() {
MOZ_COUNT_DTOR(UiCompositorControllerParent);
}
void UiCompositorControllerParent::InitializeForSameProcess() {
// This function is called by UiCompositorControllerChild in the main thread.
// So dispatch to the compositor thread to Initialize.
if (!CompositorThreadHolder::IsInCompositorThread()) {
SetOtherEndpointProcInfo(ipc::EndpointProcInfo::Current());
SynchronousTask task(
"UiCompositorControllerParent::InitializeForSameProcess");
CompositorThread()->Dispatch(NS_NewRunnableFunction(
"UiCompositorControllerParent::InitializeForSameProcess", [&]() {
AutoCompleteTask complete(&task);
InitializeForSameProcess();
}));
task.Wait();
return;
}
Initialize();
}
void UiCompositorControllerParent::InitializeForOutOfProcess() {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
Initialize();
}
void UiCompositorControllerParent::Initialize() {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
MOZ_ASSERT(state);
MOZ_ASSERT(state->mParent);
if (!state || !state->mParent) {
return;
}
state->mUiControllerParent = this;
}
void UiCompositorControllerParent::Open(
Endpoint<PUiCompositorControllerParent>&& aEndpoint) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
if (!aEndpoint.Bind(this)) {
// We can't recover from this.
MOZ_CRASH("Failed to bind UiCompositorControllerParent to endpoint");
}
InitializeForOutOfProcess();
}
void UiCompositorControllerParent::Shutdown() {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
if (state) {
state->mUiControllerParent = nullptr;
}
}
} // namespace layers
} // namespace mozilla