gecko-dev/gfx/ipc/CrossProcessPaint.h
Ryan Hunt 84bbf4f7d0 Bug 1475139 part 11 - Add CrossProcessPaint implementation. r=mattwoodrow
This commit adds a CrossProcessPaint class which can be used to paint a
cross process document tree. This API is async, as we cannot block on child
processes, and initially geared towards servicing a JS API and not internal
consumers. The API can only be used in the chrome process for security
reasons.

The class is implemented as a recursive resolver, requesting a root paint,
gathering dependent frames to be painted, then requesting paints from those
tabs. Once all paints have been completed, the dependency tree is rasterized
in a bottom up fashion.

Future improvements can be made here. Currently, the rasterization is
performed on the main thread which could cause jank. We also transmit
recordings directly over IPDl, and no effort is made to minimize the
recordings from child layer trees.

Differential Revision: https://phabricator.services.mozilla.com/D6790

--HG--
extra : rebase_source : b213de269b33486552ddc0be17207f9fb3f78c9c
2018-09-24 21:48:02 -05:00

171 lines
5.8 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/. */
#ifndef _include_mozilla_gfx_ipc_CrossProcessPaint_h_
#define _include_mozilla_gfx_ipc_CrossProcessPaint_h_
#include "nsISupportsImpl.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/ipc/ByteBuf.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsTHashtable.h"
namespace IPC {
template<typename T> struct ParamTraits;
} // namespace IPC
namespace mozilla {
namespace gfx {
class CrossProcessPaint;
/**
* A fragment of a paint of a cross process document tree.
*/
class PaintFragment
{
public:
/// Initializes an empty PaintFragment
PaintFragment() = default;
/**
* Creates a paint fragment by recording the draw commands and dependent tabs
* for an nsIDocShell.
*
* @param aDocShell The document shell to record.
* @param aRect The rectangle relative to the viewport to use.
* @param aScale The coordinate scale to use. The size of the resolved
* surface will be `aRect.Size() * aScale`, with aScale clamped to
* at least kMinPaintScale.
* @param aBackgroundColor The background color to use.
*
* @return A paint fragment. The paint fragment may be `empty` if rendering
* was unable to be accomplished for some reason.
*/
static PaintFragment Record(nsIDocShell* aDocShell,
const IntRect& aRect,
float aScale,
nscolor aBackgroundColor);
/// Returns whether this paint fragment contains a valid recording.
bool IsEmpty() const;
PaintFragment(PaintFragment&&) = default;
PaintFragment& operator=(PaintFragment&&) = default;
protected:
friend struct IPC::ParamTraits<PaintFragment>;
friend CrossProcessPaint;
typedef mozilla::ipc::ByteBuf ByteBuf;
PaintFragment(IntSize, ByteBuf&&, nsTHashtable<nsUint64HashKey>&&);
IntSize mSize;
ByteBuf mRecording;
nsTHashtable<nsUint64HashKey> mDependencies;
};
/**
* An object for painting a cross process document tree.
*/
class CrossProcessPaint
{
NS_INLINE_DECL_REFCOUNTING(CrossProcessPaint);
public:
/**
* Begin an asynchronous paint of a cross process document tree starting at
* a local document shell. The local document will be painted, then async
* paints will be queued for remote subframes. Once all subframes have been
* recorded, the final image will be resolved, and the promise will be
* resolved with a dom::ImageBitmap.
*
* @param aDocShell The document shell to paint.
* @param aRect The rectangle relative to the viewport to use.
* @param aScale The coordinate scale to use. The size of the resolved
* surface will be `aRect.Size() * aScale`, with aScale clamped to
* at least kMinPaintScale. See the implementation for the current
* minimum value.
* @param aBackgroundColor The background color to use.
* @param aPromise The promise to resolve with a dom::ImageBitmap.
*/
static void StartLocal(nsIDocShell* aRoot,
const IntRect& aRect,
float aScale,
nscolor aBackgroundColor,
dom::Promise* aPromise);
/**
* Begin an asynchronous paint of a cross process document tree starting at
* a remote tab. An async paint for the remote tab will be queued, then async
* paints will be recursively queued for remote subframes. Once all subframes
* have been recorded, the final image will be resolved, and the promise will
* be resolved with a dom::ImageBitmap.
*
* @param aDocShell The document shell to paint.
* @param aRect The rectangle relative to the viewport to use.
* @param aScale The coordinate scale to use. The size of the resolved
* surface will be `aRect.Size() * aScale`, with aScale clamped to
* at least kMinPaintScale. See the implementation for the current
* minimum value.
* @param aBackgroundColor The background color to use.
* @param aPromise The promise to resolve with a dom::ImageBitmap.
*/
static void StartRemote(dom::TabId aRoot,
const IntRect& aRect,
float aScale,
nscolor aBackgroundColor,
dom::Promise* aPromise);
void ReceiveFragment(dom::TabId aId, PaintFragment&& aFragment);
void LostFragment(dom::TabId aId);
private:
typedef nsRefPtrHashtable<nsUint64HashKey, SourceSurface> ResolvedSurfaceMap;
typedef nsDataHashtable<nsUint64HashKey, PaintFragment> ReceivedFragmentMap;
CrossProcessPaint(dom::Promise* aPromise,
float aScale,
nscolor aBackgroundColor,
dom::TabId aRootId);
~CrossProcessPaint();
void QueueRootPaint(dom::TabId aId,
const IntRect& aRect,
float aScale,
nscolor aBackgroundColor);
void QueueSubPaint(dom::TabId aId);
/// Clear the state of this paint so that it cannot be resolved or receive
/// any paint fragments.
void Clear();
/// Returns if this paint has been cleared.
bool IsCleared() const;
/// Resolves the paint fragments if we have none pending and resolves the
/// promise.
void MaybeResolve();
bool ResolveInternal(dom::TabId aId,
ResolvedSurfaceMap* aResolved);
RefPtr<dom::Promise> mPromise;
dom::TabId mRootId;
float mScale;
nscolor mBackgroundColor;
uint32_t mPendingFragments;
ReceivedFragmentMap mReceivedFragments;
};
} // namespace gfx
} // namespace mozilla
#endif // _include_mozilla_gfx_ipc_CrossProcessPaint_h_