gfx/layers/ipc/UiCompositorControllerChild.cpp
author Nathan Froyd <froydnj@mozilla.com>
Mon, 23 Apr 2018 14:13:36 -0400
changeset 415151 52f24d629711a20bf2f9717a41ae406bc6489f94
parent 409886 5d9f32557d7740c7c30f7bc6057c4de0c294d828
child 420862 b54db66223586b4e04f5cb926fccdacf8a176b91
permissions -rw-r--r--
Bug 1451363 - part 5 - remove ProtocolName virtual function; r=mccr8 ProtocolName() is only used for producing error messages and annotating crash reports. But examining actual crash reports that would have used the result of ProtocolName() indicates that we can always tell what the erroring protocol is due to the stack backtrace. So having this virtual function around just provides duplicate information, and it takes up too much space in the vtable besides. Let's get rid of it.

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

#include "mozilla/dom/ContentChild.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
#include "mozilla/layers/UiCompositorControllerParent.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/StaticPtr.h"
#include "nsBaseWidget.h"
#include "nsThreadUtils.h"

#if defined(MOZ_WIDGET_ANDROID)
#include "mozilla/widget/AndroidUiThread.h"

static RefPtr<nsThread>
GetUiThread()
{
  return mozilla::GetAndroidUiThread();
}
#else
static RefPtr<nsThread>
GetUiThread()
{
  MOZ_CRASH("Platform does not support UiCompositorController");
  return nullptr;
}
#endif // defined(MOZ_WIDGET_ANDROID)

static bool
IsOnUiThread()
{
  return GetUiThread()->SerialEventTarget()->IsOnCurrentThread();
}

namespace mozilla {
namespace layers {


// public:
/* static */ RefPtr<UiCompositorControllerChild>
UiCompositorControllerChild::CreateForSameProcess(const LayersId& aRootLayerTreeId)
{
  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(0);
  child->mParent = new UiCompositorControllerParent(aRootLayerTreeId);
  GetUiThread()->Dispatch(
    NewRunnableMethod("layers::UiCompositorControllerChild::OpenForSameProcess",
                      child,
                      &UiCompositorControllerChild::OpenForSameProcess),
    nsIThread::DISPATCH_NORMAL);
  return child;
}

/* static */ RefPtr<UiCompositorControllerChild>
UiCompositorControllerChild::CreateForGPUProcess(const uint64_t& aProcessToken,
                                                 Endpoint<PUiCompositorControllerChild>&& aEndpoint)
{
  RefPtr<UiCompositorControllerChild> child = new UiCompositorControllerChild(aProcessToken);

  RefPtr<nsIRunnable> task =
    NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>(
      "layers::UiCompositorControllerChild::OpenForGPUProcess",
      child,
      &UiCompositorControllerChild::OpenForGPUProcess,
      Move(aEndpoint));

  GetUiThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
  return child;
}

bool
UiCompositorControllerChild::Pause()
{
  if (!mIsOpen) {
    return false;
  }
  return SendPause();
}

bool
UiCompositorControllerChild::Resume()
{
  if (!mIsOpen) {
    return false;
  }
  return SendResume();
}

bool
UiCompositorControllerChild::ResumeAndResize(const int32_t& aWidth, const int32_t& aHeight)
{
  if (!mIsOpen) {
    mResize = Some(gfx::IntSize(aWidth, aHeight));
    // Since we are caching these values, pretend the call succeeded.
    return true;
  }
  return SendResumeAndResize(aWidth, aHeight);
}

bool
UiCompositorControllerChild::InvalidateAndRender()
{
  if (!mIsOpen) {
    return false;
  }
  return SendInvalidateAndRender();
}

bool
UiCompositorControllerChild::SetMaxToolbarHeight(const int32_t& aHeight)
{
  if (!mIsOpen) {
    mMaxToolbarHeight = Some(aHeight);
    // Since we are caching this value, pretend the call succeeded.
    return true;
  }
  return SendMaxToolbarHeight(aHeight);
}

bool
UiCompositorControllerChild::SetPinned(const bool& aPinned, const int32_t& aReason)
{
  if (!mIsOpen) {
    return false;
  }
  return SendPinned(aPinned, aReason);
}

bool
UiCompositorControllerChild::ToolbarAnimatorMessageFromUI(const int32_t& aMessage)
{
  if (!mIsOpen) {
    return false;
  }

  if (aMessage == IS_COMPOSITOR_CONTROLLER_OPEN) {
    RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
    return true;
  }

  return SendToolbarAnimatorMessageFromUI(aMessage);
}

bool
UiCompositorControllerChild::SetDefaultClearColor(const uint32_t& aColor)
{
  if (!mIsOpen) {
    mDefaultClearColor = Some(aColor);
    // Since we are caching this value, pretend the call succeeded.
    return true;
  }

  return SendDefaultClearColor(aColor);
}

bool
UiCompositorControllerChild::RequestScreenPixels()
{
  if (!mIsOpen) {
    return false;
  }

  return SendRequestScreenPixels();
}

bool
UiCompositorControllerChild::EnableLayerUpdateNotifications(const bool& aEnable)
{
  if (!mIsOpen) {
    mLayerUpdateEnabled = Some(aEnable);
    // Since we are caching this value, pretend the call succeeded.
    return true;
  }

  return SendEnableLayerUpdateNotifications(aEnable);
}

bool
UiCompositorControllerChild::ToolbarPixelsToCompositor(Shmem& aMem, const ScreenIntSize& aSize)
{
  if (!mIsOpen) {
    return false;
  }

  return SendToolbarPixelsToCompositor(aMem, aSize);
}

void
UiCompositorControllerChild::Destroy()
{
  if (!IsOnUiThread()) {
    GetUiThread()->Dispatch(
      NewRunnableMethod("layers::UiCompositorControllerChild::Destroy",
                        this,
                        &UiCompositorControllerChild::Destroy),
      nsIThread::DISPATCH_SYNC);
    return;
  }

  if (mIsOpen) {
    // Close the underlying IPC channel.
    PUiCompositorControllerChild::Close();
    mIsOpen = false;
  }
}

void
UiCompositorControllerChild::SetBaseWidget(nsBaseWidget* aWidget)
{
  mWidget = aWidget;
}

bool
UiCompositorControllerChild::AllocPixelBuffer(const int32_t aSize, Shmem* aMem)
{
  MOZ_ASSERT(aSize > 0);
  return AllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, aMem);
}

bool
UiCompositorControllerChild::DeallocPixelBuffer(Shmem& aMem)
{
  return DeallocShmem(aMem);
}

// protected:
void
UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy)
{
  mIsOpen = false;
  mParent = nullptr;

  if (mProcessToken) {
    gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    mProcessToken = 0;
  }
}

void
UiCompositorControllerChild::DeallocPUiCompositorControllerChild()
{
  if (mParent) {
    mParent = nullptr;
  }
  Release();
}

void
UiCompositorControllerChild::ProcessingError(Result aCode, const char* aReason)
{
  MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in UiCompositorControllerChild");
}

void
UiCompositorControllerChild::HandleFatalError(const char* aMsg) const
{
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

mozilla::ipc::IPCResult
UiCompositorControllerChild::RecvToolbarAnimatorMessageFromCompositor(const int32_t& aMessage)
{
#if defined(MOZ_WIDGET_ANDROID)
  if (mWidget) {
    mWidget->RecvToolbarAnimatorMessageFromCompositor(aMessage);
  }
#endif // defined(MOZ_WIDGET_ANDROID)

  return IPC_OK();
}

mozilla::ipc::IPCResult
UiCompositorControllerChild::RecvRootFrameMetrics(const ScreenPoint& aScrollOffset, const CSSToScreenScale& aZoom)
{
#if defined(MOZ_WIDGET_ANDROID)
  if (mWidget) {
    mWidget->UpdateRootFrameMetrics(aScrollOffset, aZoom);
  }
#endif // defined(MOZ_WIDGET_ANDROID)

  return IPC_OK();
}

mozilla::ipc::IPCResult
UiCompositorControllerChild::RecvScreenPixels(ipc::Shmem&& aMem, const ScreenIntSize& aSize)
{
#if defined(MOZ_WIDGET_ANDROID)
  if (mWidget) {
    mWidget->RecvScreenPixels(Move(aMem), aSize);
  }
#endif // defined(MOZ_WIDGET_ANDROID)

  return IPC_OK();
}

// private:
UiCompositorControllerChild::UiCompositorControllerChild(const uint64_t& aProcessToken)
 : mIsOpen(false)
 , mProcessToken(aProcessToken)
 , mWidget(nullptr)
{
}

UiCompositorControllerChild::~UiCompositorControllerChild()
{
}

void
UiCompositorControllerChild::OpenForSameProcess()
{
  MOZ_ASSERT(IsOnUiThread());

  mIsOpen = Open(mParent->GetIPCChannel(),
                 mozilla::layers::CompositorThreadHolder::Loop(),
                 mozilla::ipc::ChildSide);

  if (!mIsOpen) {
    mParent = nullptr;
    return;
  }

  mParent->InitializeForSameProcess();
  AddRef();
  SendCachedValues();
  // Let Ui thread know the connection is open;
  RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
}

void
UiCompositorControllerChild::OpenForGPUProcess(Endpoint<PUiCompositorControllerChild>&& aEndpoint)
{
  MOZ_ASSERT(IsOnUiThread());

  mIsOpen = aEndpoint.Bind(this);

  if (!mIsOpen) {
    // The GPU Process Manager might be gone if we receive ActorDestroy very
    // late in shutdown.
    if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) {
      gpm->NotifyRemoteActorDestroyed(mProcessToken);
    }
    return;
  }

  AddRef();
  SendCachedValues();
  // Let Ui thread know the connection is open;
  RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
}

void
UiCompositorControllerChild::SendCachedValues()
{
  MOZ_ASSERT(mIsOpen);
  if (mResize) {
    SendResumeAndResize(mResize.ref().width, mResize.ref().height);
    mResize.reset();
  }
  if (mMaxToolbarHeight) {
    SendMaxToolbarHeight(mMaxToolbarHeight.ref());
    mMaxToolbarHeight.reset();
  }
  if (mDefaultClearColor) {
    SendDefaultClearColor(mDefaultClearColor.ref());
    mDefaultClearColor.reset();
  }
  if (mLayerUpdateEnabled) {
    SendEnableLayerUpdateNotifications(mLayerUpdateEnabled.ref());
    mLayerUpdateEnabled.reset();
  }
}

} // namespace layers
} // namespace mozilla