blob: 70a43a117850c9c6219aa35a8ab2564caf08a8cf [file] [log] [blame]
// 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/callback.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "cc/layers/layer_collections.h"
#include "third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer_client.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"
namespace cc {
struct ElementId;
class Layer;
}
namespace gfx {
class Vector2dF;
class ScrollOffset;
}
namespace blink {
class ContentLayerClientImpl;
class JSONObject;
class PaintArtifact;
class SynthesizedClip;
struct PaintChunk;
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_;
};
// 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();
static std::unique_ptr<PaintArtifactCompositor> Create(
base::RepeatingCallback<void(const gfx::ScrollOffset&,
const cc::ElementId&)> scroll_callback) {
return base::WrapUnique(
new PaintArtifactCompositor(std::move(scroll_callback)));
}
// Updates the layer tree to match the provided paint artifact.
//
// Populates |composited_element_ids| with the CompositorElementId of all
// animations for which we saw a paint chunk and created a layer.
void Update(scoped_refptr<const PaintArtifact>,
CompositorElementIdSet& composited_element_ids,
TransformPaintPropertyNode* viewport_scale_node);
// The root layer of the tree managed by this object.
cc::Layer* RootLayer() const { return root_layer_.get(); }
// Returns extra information recorded during unit tests.
// While not part of the normal output of this class, this provides a simple
// way of locating the layers of interest, since there are still a slew of
// placeholder layers required.
struct PLATFORM_EXPORT ExtraDataForTesting {
cc::Layer* ScrollHitTestWebLayerAt(unsigned index);
Vector<scoped_refptr<cc::Layer>> content_layers;
Vector<scoped_refptr<cc::Layer>> synthesized_clip_layers;
Vector<scoped_refptr<cc::Layer>> scroll_hit_test_layers;
};
void EnableExtraDataForTesting();
ExtraDataForTesting* GetExtraDataForTesting() const {
return extra_data_for_testing_.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<JSONObject> LayersAsJSON(LayerTreeFlags) const;
#if DCHECK_IS_ON()
void ShowDebugData();
#endif
const Vector<std::unique_ptr<ContentLayerClientImpl>>&
ContentLayerClientsForTesting() const {
return content_layer_clients_;
}
// Update the cc::Layer's touch action region from the touch action rects of
// the paint chunks.
static void UpdateTouchActionRects(cc::Layer*,
const gfx::Vector2dF& layer_offset,
const PropertyTreeState& layer_state,
const PaintChunkSubset& paint_chunks);
private:
// A pending layer is a collection of paint chunks that will end up in
// the same cc::Layer.
struct PLATFORM_EXPORT PendingLayer {
PendingLayer(const PaintChunk& first_paint_chunk,
wtf_size_t first_chunk_index,
bool requires_own_layer);
// Merge another pending layer after this one, appending all its paint
// chunks after chunks in this layer, with appropriate space conversion
// applied. The merged layer must have a property tree state that's deeper
// than this layer, i.e. can "upcast" to this layer's state.
void Merge(const PendingLayer& guest);
bool CanMerge(const PendingLayer& guest) 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&);
FloatRect bounds;
Vector<wtf_size_t> paint_chunk_indices;
FloatRect rect_known_to_be_opaque;
PropertyTreeState property_tree_state;
bool requires_own_layer;
};
PaintArtifactCompositor(
base::RepeatingCallback<void(const gfx::ScrollOffset&,
const cc::ElementId&)> scroll_callback);
// 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 PaintArtifact&,
Vector<PendingLayer>& pending_layers);
// 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).
static void LayerizeGroup(const PaintArtifact&,
Vector<PendingLayer>& pending_layers,
const EffectPaintPropertyNode&,
Vector<PaintChunk>::const_iterator& chunk_cursor);
static bool MightOverlap(const PendingLayer&, const PendingLayer&);
static bool CanDecompositeEffect(const EffectPaintPropertyNode*,
const PendingLayer&);
// Builds a leaf layer that represents a single paint chunk.
// Note: cc::Layer API assumes the layer bounds start at (0, 0), but the
// bounding box of a paint chunk does not necessarily start at (0, 0) (and
// could even be negative). Internally the generated layer translates the
// paint chunk to align the bounding box to (0, 0) and return the actual
// origin of the paint chunk in the |layerOffset| outparam.
scoped_refptr<cc::Layer> CompositedLayerForPendingLayer(
scoped_refptr<const PaintArtifact>,
const PendingLayer&,
gfx::Vector2dF& layer_offset,
Vector<std::unique_ptr<ContentLayerClientImpl>>&
new_content_layer_clients,
Vector<scoped_refptr<cc::Layer>>& new_scroll_hit_test_layers);
bool PropertyTreeStateChanged(const PropertyTreeState&) const;
const TransformPaintPropertyNode& ScrollTranslationForPendingLayer(
const PaintArtifact&,
const PendingLayer&);
// If the pending layer is a special scroll hit test layer, return the
// associated scroll offset translation node.
const TransformPaintPropertyNode* ScrollTranslationForScrollHitTestLayer(
const PaintArtifact&,
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 PaintArtifact&,
const PendingLayer&,
gfx::Vector2dF& layer_offset);
// 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&);
cc::Layer* CreateOrReuseSynthesizedClipLayer(
const ClipPaintPropertyNode*,
CompositorElementId& mask_isolation_id,
CompositorElementId& mask_effect_id) final;
// Provides a callback for notifying blink of composited scrolling.
base::RepeatingCallback<void(const gfx::ScrollOffset&, const cc::ElementId&)>
scroll_callback_;
bool tracks_raster_invalidations_;
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;
};
std::vector<SynthesizedClipEntry> synthesized_clip_cache_;
Vector<scoped_refptr<cc::Layer>> scroll_hit_test_layers_;
bool extra_data_for_testing_enabled_ = false;
std::unique_ptr<ExtraDataForTesting> extra_data_for_testing_;
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_