summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
blob: 02f9b3948f7894e31e652cb411d642b3b0fb1d69 (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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COMPOSITING_PAINT_ARTIFACT_COMPOSITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COMPOSITING_PAINT_ARTIFACT_COMPOSITOR_H_

#include <memory>

#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "cc/input/layer_selection_bound.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/layer_collections.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/property_tree.h"
#include "third_party/blink/renderer/platform/graphics/compositing/layers_as_json.h"
#include "third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h"
#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

#if DCHECK_IS_ON()
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#endif

namespace cc {
class ScrollbarLayerBase;
class DocumentTransitionRequest;
}

namespace blink {

class ContentLayerClientImpl;
class GraphicsLayer;
class JSONObject;
class SynthesizedClip;

using CompositorScrollCallbacks = cc::ScrollCallbacks;

// Information of a composited layer that is created during compositing update
// in pre-CompositeAfterPaint. In CompositeAfterPaint, this is expected to
// contain all paint chunks, as if we created one root layer that needs to be
// future layerized.
struct PreCompositedLayerInfo {
  // For now this is used only when graphics_layer == nullptr. This will also
  // contain the paint chunks for the graphics layer when we unify
  // PaintController for pre-CAP and CAP.
  PaintChunkSubset chunks;
  // If this is not nullptr, we should use the composited layer created by the
  // GraphicsLayer. Otherwise we should layerize |chunks|. A GraphicsLayer with
  // ShouldCreateLayersAfterPaint() == true should set this field to nullptr.
  const GraphicsLayer* graphics_layer = nullptr;
};

class LayerListBuilder {
 public:
  void Add(scoped_refptr<cc::Layer>);
  cc::LayerList Finalize();

 private:
  // The list becomes invalid once |Finalize| is called.
  bool list_valid_ = true;
  cc::LayerList list_;
#if DCHECK_IS_ON()
  HashSet<int> layer_ids_;
#endif
};

// This class maintains unique stable cc effect IDs (and optionally a persistent
// mask layer) for reuse across compositing cycles. The mask layer paints a
// rounded rect, which is an updatable parameter of the class. The caller is
// responsible for inserting the mask layer into layer list and associating with
// property nodes. The mask layer may be omitted if the caller determines it is
// not necessary (e.g. because there is no content to mask).
//
// The typical application of the mask layer is to create an isolating effect
// node to paint the clipped contents, and at the end draw the mask layer with
// a kDstIn blend effect. This is why two stable cc effect IDs are provided.
// Even if the mask layer is not present, it's important for the isolation
// effect node to be stable, to minimize render surface damage.
class SynthesizedClip : private cc::ContentLayerClient {
 public:
  SynthesizedClip() : layer_(nullptr) {
    mask_isolation_id_ =
        CompositorElementIdFromUniqueObjectId(NewUniqueObjectId());
    mask_effect_id_ =
        CompositorElementIdFromUniqueObjectId(NewUniqueObjectId());
  }
  ~SynthesizedClip() override {
    if (layer_)
      layer_->ClearClient();
  }

  void UpdateLayer(bool needs_layer,
                   const ClipPaintPropertyNode&,
                   const TransformPaintPropertyNode&);

  cc::PictureLayer* Layer() { return layer_.get(); }
  CompositorElementId GetMaskIsolationId() const { return mask_isolation_id_; }
  CompositorElementId GetMaskEffectId() const { return mask_effect_id_; }

 private:
  // ContentLayerClient implementation.
  gfx::Rect PaintableRegion() const final {
    return gfx::Rect(layer_->bounds());
  }
  scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList() final;
  bool FillsBoundsCompletely() const final { return false; }

 private:
  scoped_refptr<cc::PictureLayer> layer_;
  GeometryMapper::Translation2DOrMatrix translation_2d_or_matrix_;
  bool rrect_is_local_ = false;
  SkRRect rrect_;
  scoped_refptr<const RefCountedPath> path_;
  CompositorElementId mask_isolation_id_;
  CompositorElementId mask_effect_id_;
};

// Responsible for managing compositing in terms of a PaintArtifact.
//
// Owns a subtree of the compositor layer tree, and updates it in response to
// changes in the paint artifact.
//
// PaintArtifactCompositor is the successor to PaintLayerCompositor, reflecting
// the new home of compositing decisions after paint with CompositeAfterPaint.
class PLATFORM_EXPORT PaintArtifactCompositor final
    : private PropertyTreeManagerClient {
  USING_FAST_MALLOC(PaintArtifactCompositor);

 public:
  PaintArtifactCompositor(
      base::WeakPtr<CompositorScrollCallbacks> scroll_callbacks);
  ~PaintArtifactCompositor() override;

  struct ViewportProperties {
    const TransformPaintPropertyNode* overscroll_elasticity_transform = nullptr;
    const TransformPaintPropertyNode* page_scale = nullptr;
    const TransformPaintPropertyNode* inner_scroll_translation = nullptr;
    const ClipPaintPropertyNode* outer_clip = nullptr;
    const TransformPaintPropertyNode* outer_scroll_translation = nullptr;
  };

  // Updates the layer tree to match the provided |pre_composited_layers|.
  // In pre-CompositeAfterPaint, |pre_composited_layers| contains information
  // from the GraphicsLayer tree. Some of the pre-composited layers may need
  // additional layerization. In CompositeAfterPaint, |pre_composited_layers|
  // should contain just one entry, and we will do a full layerization.
  //
  // |scroll_translation_nodes| is the complete set of scroll nodes, including
  // noncomposited nodes, and is used for Scroll Unification to generate scroll
  // nodes for noncomposited scrollers to complete the compositor's scroll
  // property tree.
  void Update(
      const Vector<PreCompositedLayerInfo>&,
      const ViewportProperties& viewport_properties,
      const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes,
      Vector<std::unique_ptr<cc::DocumentTransitionRequest>> requests);

  void UpdateRepaintedLayerProperties() const;

  bool DirectlyUpdateCompositedOpacityValue(const EffectPaintPropertyNode&);
  bool DirectlyUpdateScrollOffsetTransform(const TransformPaintPropertyNode&);
  bool DirectlyUpdateTransform(const TransformPaintPropertyNode&);
  bool DirectlyUpdatePageScaleTransform(const TransformPaintPropertyNode&);

  // Directly sets cc::ScrollTree::current_scroll_offset. This doesn't affect
  // cc::TransformNode::scroll_offset (which will be synched with blink
  // transform node in DirectlyUpdateScrollOffsetTransform() or Update()).
  bool DirectlySetScrollOffset(CompositorElementId,
                               const FloatPoint& scroll_offset);

  // The root layer of the tree managed by this object.
  cc::Layer* RootLayer() const { return root_layer_.get(); }

  void SetTracksRasterInvalidations(bool);

  // Called when the local frame view that owns this compositor is
  // going to be removed from its frame.
  void WillBeRemovedFromFrame();

  std::unique_ptr<JSONArray> GetPendingLayersAsJSON() const;

  std::unique_ptr<JSONObject> GetLayersAsJSON(LayerTreeFlags) const;

#if DCHECK_IS_ON()
  void ShowDebugData();
#endif

  const Vector<std::unique_ptr<ContentLayerClientImpl>>&
  ContentLayerClientsForTesting() const {
    return content_layer_clients_;
  }

  void SetNeedsUpdate() { needs_update_ = true; }
  bool NeedsUpdate() const { return needs_update_; }
  void ClearNeedsUpdateForTesting() { needs_update_ = false; }

  // Returns true if a property tree node associated with |element_id| exists
  // on any of the PropertyTrees constructed by |Update|.
  bool HasComposited(CompositorElementId element_id) const;

  void SetLayerDebugInfoEnabled(bool);

  Vector<cc::Layer*> SynthesizedClipLayersForTesting() const;

  void ClearPropertyTreeChangedState();

  size_t ApproximateUnsharedMemoryUsage() const;

 private:
  // A pending layer is a collection of paint chunks that will end up in
  // the same cc::Layer.
  struct PLATFORM_EXPORT PendingLayer {
    enum CompositingType {
      kScrollHitTestLayer,
      kPreCompositedLayer,
      kForeignLayer,
      kScrollbarLayer,
      kOverlap,
      kOther,
    };

    PendingLayer(const PaintChunkSubset&,
                 const PaintChunkIterator&,
                 CompositingType compositng_type = kOther);
    explicit PendingLayer(const PreCompositedLayerInfo&);

    // Merges |guest| into |this| if it can, by appending chunks of |guest|
    // after chunks of |this|, with appropriate space conversion applied to
    // both layers from their original property tree states to |merged_state|.
    // Returns whether the merge is successful.
    bool Merge(const PendingLayer& guest);

    // Returns true if |guest| can be merged into |this|, and sets the output
    // parameters with the property tree state and bounds of the merged layer.
    // |guest_state| is for cases that we want to check if we can merge |guest|
    // if it has |guest_state| in the future (which may be different from its
    // current state).
    bool CanMerge(const PendingLayer& guest,
                  const PropertyTreeState& guest_state,
                  PropertyTreeState* out_merged_state = nullptr,
                  FloatRect* out_guest_bounds = nullptr,
                  FloatRect* out_merged_bounds = nullptr) const;

    // Mutate this layer's property tree state to a more general (shallower)
    // state, thus the name "upcast". The concrete effect of this is to
    // "decomposite" some of the properties, so that fewer properties will be
    // applied by the compositor, and more properties will be applied internally
    // to the chunks as Skia commands.
    void Upcast(const PropertyTreeState&);

    const PaintChunk& FirstPaintChunk() const;
    const DisplayItem& FirstDisplayItem() const;

    // Returns the largest rect known to be opaque given two opaque rects.
    static FloatRect UniteRectsKnownToBeOpaque(const FloatRect&,
                                               const FloatRect&);
    FloatRect MapRectKnownToBeOpaque(const PropertyTreeState&) const;

    std::unique_ptr<JSONObject> ToJSON() const;

    FloatRect VisualRectForOverlapTesting() const;

    bool MayDrawContent() const;

    bool RequiresOwnLayer() const {
      return compositing_type != kOverlap && compositing_type != kOther;
    }

    bool PropertyTreeStateChanged() const;

    // The rects are in the space of property_tree_state.
    FloatRect bounds;
    FloatRect rect_known_to_be_opaque;
    bool text_known_to_be_on_opaque_background;
    PaintChunkSubset chunks;
    PropertyTreeState property_tree_state;
    FloatPoint offset_of_decomposited_transforms;
    PaintPropertyChangeType change_of_decomposited_transforms =
        PaintPropertyChangeType::kUnchanged;
    const GraphicsLayer* graphics_layer = nullptr;
    CompositingType compositing_type;
  };

  static void UpdateLayerProperties(cc::Layer&,
                                    const PendingLayer&,
                                    cc::LayerSelection& layer_selection,
                                    PropertyTreeManager* = nullptr);

  void DecompositeTransforms();

  // Collects the PaintChunks into groups which will end up in the same
  // cc layer. This is the entry point of the layerization algorithm.
  void CollectPendingLayers(const Vector<PreCompositedLayerInfo>&);

  // This is the internal recursion of collectPendingLayers. This function
  // loops over the list of paint chunks, scoped by an isolated group
  // (i.e. effect node). Inside of the loop, chunks are tested for overlap
  // and merge compatibility. Subgroups are handled by recursion, and will
  // be tested for "decompositing" upon return.
  // Merge compatibility means consecutive chunks may be layerized into the
  // same backing (i.e. merged) if their property states don't cross
  // direct-compositing boundary.
  // Non-consecutive chunks that are nevertheless compatible may still be
  // merged, if reordering of the chunks won't affect the ultimate result.
  // This is determined by overlap testing such that chunks can be safely
  // reordered if their effective bounds in screen space can't overlap.
  // The recursion only tests merge & overlap for chunks scoped by the same
  // group. This is where "decompositing" came in. Upon returning from a
  // recursion, the layerization of the subgroup may be tested for merge &
  // overlap with other chunks in the parent group, if grouping requirement
  // can be satisfied (and the effect node has no direct reason).
  void LayerizeGroup(const PaintChunkSubset&,
                     const EffectPaintPropertyNode&,
                     PaintChunkIterator& chunk_cursor);
  static bool MightOverlap(const PendingLayer&, const PendingLayer&);
  bool DecompositeEffect(const EffectPaintPropertyNode& parent_effect,
                         wtf_size_t first_layer_in_parent_group_index,
                         const EffectPaintPropertyNode& effect,
                         wtf_size_t layer_index);

  // Builds a leaf layer that represents a single paint chunk.
  scoped_refptr<cc::Layer> CompositedLayerForPendingLayer(
      const PendingLayer&,
      Vector<std::unique_ptr<ContentLayerClientImpl>>&
          new_content_layer_clients,
      Vector<scoped_refptr<cc::Layer>>& new_scroll_hit_test_layers,
      Vector<scoped_refptr<cc::ScrollbarLayerBase>>& new_scrollbar_layers);

  const TransformPaintPropertyNode& NearestScrollTranslationForLayer(
      const PendingLayer&);

  // If the pending layer has scroll hit test data, return the associated
  // scroll translation node.
  const TransformPaintPropertyNode* ScrollTranslationForLayer(
      const PendingLayer&);

  // Returns the cc::Layer if the pending layer contains a foreign layer or a
  // wrapper of a GraphicsLayer. If it's the latter and the graphics layer has
  // been repainted, also updates the layer properties.
  scoped_refptr<cc::Layer> WrappedCcLayerForPendingLayer(const PendingLayer&);

  // Finds an existing or creates a new scroll hit test layer for the pending
  // layer, returning nullptr if the layer is not a scroll hit test layer.
  scoped_refptr<cc::Layer> ScrollHitTestLayerForPendingLayer(
      const PendingLayer&);

  // Finds an existing or creates a new scrollbar layer for the pending layer,
  // returning nullptr if the layer is not a scrollbar layer.
  scoped_refptr<cc::ScrollbarLayerBase> ScrollbarLayerForPendingLayer(
      const PendingLayer&);

  // Finds a client among the current vector of clients that matches the paint
  // chunk's id, or otherwise allocates a new one.
  std::unique_ptr<ContentLayerClientImpl> ClientForPaintChunk(
      const PaintChunk&);

  // if |needs_layer| is false, no cc::Layer is created, |mask_effect_id| is
  // not set, and the Layer() method on the returned SynthesizedClip returns
  // nullptr.
  // However, |mask_isolation_id| is always set.
  SynthesizedClip& CreateOrReuseSynthesizedClipLayer(
      const ClipPaintPropertyNode&,
      const TransformPaintPropertyNode&,
      bool needs_layer,
      CompositorElementId& mask_isolation_id,
      CompositorElementId& mask_effect_id) final;

  static void UpdateRenderSurfaceForEffects(
      cc::EffectTree&,
      const cc::LayerList&,
      const Vector<const EffectPaintPropertyNode*>&);

  bool CanDirectlyUpdateProperties() const;

  CompositingReasons GetCompositingReasons(
      const PendingLayer& layer,
      const PendingLayer* previous_layer) const;

  void UpdateDebugInfo() const;

  // For notifying blink of composited scrolling.
  base::WeakPtr<CompositorScrollCallbacks> scroll_callbacks_;

  bool tracks_raster_invalidations_ = false;
  bool needs_update_ = true;
  bool layer_debug_info_enabled_ = false;

  scoped_refptr<cc::Layer> root_layer_;
  Vector<std::unique_ptr<ContentLayerClientImpl>> content_layer_clients_;
  struct SynthesizedClipEntry {
    const ClipPaintPropertyNode* key;
    std::unique_ptr<SynthesizedClip> synthesized_clip;
    bool in_use;
  };
  Vector<SynthesizedClipEntry> synthesized_clip_cache_;

  Vector<scoped_refptr<cc::Layer>> scroll_hit_test_layers_;
  Vector<scoped_refptr<cc::ScrollbarLayerBase>> scrollbar_layers_;

  Vector<PendingLayer, 0> pending_layers_;

  friend class StubChromeClientForCAP;
  friend class PaintArtifactCompositorTest;

  DISALLOW_COPY_AND_ASSIGN(PaintArtifactCompositor);
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COMPOSITING_PAINT_ARTIFACT_COMPOSITOR_H_