summaryrefslogtreecommitdiffstats
path: root/gfx/ipc/CrossProcessPaint.h
blob: 55dc9a8b048342ab1e57c8a5b3f8f30f7432eb17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* -*- 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/gfx/Point.h"
#include "mozilla/gfx/RecordedEvent.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ipc/ByteBuf.h"
#include "nsColor.h"
#include "nsTHashMap.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsTHashSet.h"

class nsIDocShell;

namespace IPC {
template <typename T>
struct ParamTraits;
}  // namespace IPC

namespace mozilla {

namespace dom {
class CanonicalBrowsingContext;
class DOMRect;
class Promise;
class WindowGlobalParent;
}  // namespace dom

namespace gfx {

class CrossProcessPaint;

enum class CrossProcessPaintFlags {
  None = 0,
  DrawView = 1 << 1,
  ResetScrollPosition = 1 << 2,
  UseHighQualityScaling = 1 << 3,
};

MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CrossProcessPaintFlags)

/**
 * A fragment of a paint of a cross process document tree.
 */
class PaintFragment final {
 public:
  /// Initializes an empty PaintFragment
  PaintFragment() = default;

  /**
   * Creates a paint fragment by recording the draw commands and dependent tabs
   * for a BrowsingContext.
   *
   * @param aBrowsingContext The frame to record.
   * @param aRect The rectangle relative to the viewport to use. If no
   *   rectangle is specified, then the whole viewport will be used.
   * @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(dom::BrowsingContext* aBc,
                              const Maybe<IntRect>& aRect, float aScale,
                              nscolor aBackgroundColor,
                              CrossProcessPaintFlags aFlags);

  /// Returns whether this paint fragment contains a valid recording.
  bool IsEmpty() const;

  PaintFragment(PaintFragment&&) = default;
  PaintFragment& operator=(PaintFragment&&) = default;

 protected:
  friend struct mozilla::ipc::IPDLParamTraits<PaintFragment>;
  friend CrossProcessPaint;

  typedef mozilla::ipc::ByteBuf ByteBuf;

  PaintFragment(IntSize, ByteBuf&&, nsTHashSet<uint64_t>&&);

  IntSize mSize;
  ByteBuf mRecording;
  nsTHashSet<uint64_t> mDependencies;
};

/**
 * An object for painting a cross process document tree.
 */
class CrossProcessPaint final {
  NS_INLINE_DECL_REFCOUNTING(CrossProcessPaint);

 public:
  typedef nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>
      ResolvedFragmentMap;
  typedef MozPromise<ResolvedFragmentMap, nsresult, true> ResolvePromise;
  /**
   * Begin an asynchronous paint of a cross process document tree starting at
   * a WindowGlobalParent. A maybe-async paint for the root WGP will be done,
   * 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 aRoot The WindowGlobalParent to paint.
   * @param aRect The rectangle relative to the viewport to use, or null to
   *   render the whole viewport.
   * @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.
   *
   * @returns Whether the paint was able to be initiated or not.
   */
  static bool Start(dom::WindowGlobalParent* aRoot, const dom::DOMRect* aRect,
                    float aScale, nscolor aBackgroundColor,
                    CrossProcessPaintFlags aFlags, dom::Promise* aPromise);

  static RefPtr<ResolvePromise> Start(nsTHashSet<uint64_t>&& aDependencies);

  void ReceiveFragment(dom::WindowGlobalParent* aWGP,
                       PaintFragment&& aFragment);
  void LostFragment(dom::WindowGlobalParent* aWGP);

 private:
  typedef nsTHashMap<nsUint64HashKey, PaintFragment> ReceivedFragmentMap;

  CrossProcessPaint(float aScale, dom::TabId aRoot,
                    CrossProcessPaintFlags aFlags);
  ~CrossProcessPaint();

  void QueueDependencies(const nsTHashSet<uint64_t>& aDependencies);

  void QueuePaint(
      dom::WindowGlobalParent* aWGP, const Maybe<IntRect>& aRect,
      nscolor aBackgroundColor = NS_RGBA(0, 0, 0, 0),
      CrossProcessPaintFlags aFlags = CrossProcessPaintFlags::DrawView);

  void QueuePaint(dom::CanonicalBrowsingContext* aBc);

  /// Clear the state of this paint so that it cannot be resolved or receive
  /// any paint fragments.
  void Clear(nsresult aStatus);

  /// 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();
  nsresult ResolveInternal(dom::TabId aTabId, ResolvedFragmentMap* aResolved);

  RefPtr<ResolvePromise> Init() {
    MOZ_ASSERT(mPromise.IsEmpty());
    return mPromise.Ensure(__func__);
  }

  // UseHighQualityScaling is the only flag that dependencies inherit, and we
  // always want to use DrawView for dependencies.
  CrossProcessPaintFlags GetFlagsForDependencies() const {
    return (mFlags & CrossProcessPaintFlags::UseHighQualityScaling) |
           CrossProcessPaintFlags::DrawView;
  }

  MozPromiseHolder<ResolvePromise> mPromise;
  dom::TabId mRoot;
  float mScale;
  uint32_t mPendingFragments;
  ReceivedFragmentMap mReceivedFragments;
  CrossProcessPaintFlags mFlags;
};

}  // namespace gfx
}  // namespace mozilla

#endif  // _include_mozilla_gfx_ipc_CrossProcessPaint_h_