blob: 397e345c0138da31fc367ce33062ae7726852400 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// 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_PAINT_PAINT_PROPERTY_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINT_PROPERTY_NODE_H_
#include <algorithm>
#include <iosfwd>
#include "base/check_op.h"
#include "base/dcheck_is_on.h"
#include "base/memory/scoped_refptr.h"
#include "cc/trees/property_tree.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#if DCHECK_IS_ON()
#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#endif
namespace blink {
class ClipPaintPropertyNodeOrAlias;
class EffectPaintPropertyNodeOrAlias;
class ScrollPaintPropertyNode;
class TransformPaintPropertyNodeOrAlias;
// Used to report whether and how paint properties have changed. The order is
// important - it must go from no change to the most significant change.
enum class PaintPropertyChangeType : unsigned char {
// Nothing has changed.
kUnchanged,
// We only changed values that are either mutated by compositor animations
// which are updated automatically during the compositor-side animation tick,
// or have been updated directly on the associated compositor node during the
// PrePaint lifecycle phase.
kChangedOnlyCompositedValues,
// We only changed values that don't require re-raster (e.g. compositor
// element id changed).
kChangedOnlyNonRerasterValues,
// We only changed values and not the hierarchy of the tree, and we know that
// the value changes are 'simple' in that they don't cause cascading changes.
// For example, they do not cause a new render surface to be created, which
// may otherwise cause tree changes elsewhere. An example of this is opacity
// changing in the [0, 1) range. PaintPropertyTreeBuilder may try to directly
// update the associated compositor node through PaintArtifactCompositor::
// DirectlyUpdate*(), and if that's successful, the change will be downgraded
// to kChangeOnlyCompositedValues.
kChangedOnlySimpleValues,
// We only changed values and not the hierarchy of the tree, but nothing is
// known about the kind of value change. The difference between
// kChangedOnlySimpleValues and kChangedOnlyValues is only meaningful in
// PaintPropertyTreeBuilder for eligibility of direct update of compositor
// node. Otherwise we should never distinguish between them.
kChangedOnlyValues,
// We have directly modified the tree topology by adding or removing a node.
kNodeAddedOrRemoved,
};
PLATFORM_EXPORT const char* PaintPropertyChangeTypeToString(
PaintPropertyChangeType);
class PLATFORM_EXPORT PaintPropertyNode : public RefCounted<PaintPropertyNode> {
USING_FAST_MALLOC(PaintPropertyNode);
public:
PaintPropertyNode(const PaintPropertyNode&) = delete;
PaintPropertyNode& operator=(const PaintPropertyNode&) = delete;
virtual ~PaintPropertyNode() = default;
bool IsRoot() const { return !parent_; }
// Returns true if this node is an alias for its parent. A parent alias is a
// node which on its own does not contribute to the rendering output, and only
// exists to enforce a particular structure of the paint property tree. Its
// value is ignored during display item list generation, instead the parent
// value is used. See Unalias().
bool IsParentAlias() const { return is_parent_alias_; }
void CompositorSimpleValuesUpdated() const {
if (changed_ == PaintPropertyChangeType::kChangedOnlySimpleValues)
changed_ = PaintPropertyChangeType::kChangedOnlyCompositedValues;
}
String ToString() const {
String s = ToJSON()->ToJSONString();
#if DCHECK_IS_ON()
return debug_name_ + String::Format(" %p ", this) + s;
#else
return s;
#endif
}
virtual std::unique_ptr<JSONObject> ToJSON() const;
int CcNodeId(int sequence_number) const {
return cc_sequence_number_ == sequence_number ? cc_node_id_
: cc::kInvalidPropertyNodeId;
}
void SetCcNodeId(int sequence_number, int id) const {
cc_sequence_number_ = sequence_number;
cc_node_id_ = id;
}
PaintPropertyChangeType NodeChanged() const { return changed_; }
bool NodeChangeAffectsRaster() const {
return changed_ != PaintPropertyChangeType::kUnchanged &&
changed_ != PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
}
#if DCHECK_IS_ON()
String ToTreeString() const;
String DebugName() const { return debug_name_; }
void SetDebugName(const String& name) { debug_name_ = name; }
#endif
// In this class the tag is to distinguish the constructor for parent alias.
// In subclasses for parent alias types, the tag is to distinguish the
// constructors from the copy constructors (deleted in this class).
enum ParentAliasTag { kParentAlias };
protected:
explicit PaintPropertyNode(const PaintPropertyNode* parent)
: changed_(parent ? PaintPropertyChangeType::kNodeAddedOrRemoved
: PaintPropertyChangeType::kUnchanged),
parent_(parent) {}
// A parent alias node must have a parent, so ensure that we can always find
// a unaliased ancestor for any node.
PaintPropertyNode(const PaintPropertyNode& parent, ParentAliasTag)
: is_parent_alias_(true),
changed_(PaintPropertyChangeType::kNodeAddedOrRemoved),
parent_(&parent) {}
PaintPropertyChangeType SetParent(const PaintPropertyNode& parent) {
DCHECK(!IsRoot());
DCHECK_NE(&parent, this);
if (&parent == parent_) {
return PaintPropertyChangeType::kUnchanged;
}
parent_ = &parent;
AddChanged(PaintPropertyChangeType::kChangedOnlyValues);
return PaintPropertyChangeType::kChangedOnlyValues;
}
// Parent property node, or nullptr if this is the root node.
const PaintPropertyNode* Parent() const { return parent_.get(); }
// Returns the first node up the parent chain that is not an alias; return the
// root node if every node is an alias.
const PaintPropertyNode& Unalias() const {
const auto* node = this;
while (node->Parent() && node->IsParentAlias()) {
node = node->Parent();
}
return *node;
}
const PaintPropertyNode* UnaliasedParent() const {
return Parent() ? &Parent()->Unalias() : nullptr;
}
bool IsAncestorOf(const PaintPropertyNode& other) const {
for (const auto* node = &other; node != this; node = node->Parent()) {
if (!node) {
return false;
}
}
return true;
}
const PaintPropertyNode& LowestCommonAncestor(
const PaintPropertyNode& other) const {
// Fast path of common cases.
if (this == &other || !Parent() || other.Parent() == this) {
DCHECK(IsAncestorOf(other));
return *this;
}
if (!other.Parent() || Parent() == &other) {
DCHECK(other.IsAncestorOf(*this));
return other;
}
return LowestCommonAncestorInternal(other);
}
virtual void AddChanged(PaintPropertyChangeType changed) {
DCHECK(!IsRoot());
changed_ = std::max(changed_, changed);
}
// The following two functions are for subclasses to implement
// ClearChangedToRoot() which should clear changed flags along the path to
// the root, and set sequence number.
// For information about |sequence_number|, see: |changed_sequence_number_|.
void ClearChanged(int sequence_number) const {
DCHECK_NE(changed_sequence_number_, sequence_number);
changed_ = PaintPropertyChangeType::kUnchanged;
changed_sequence_number_ = sequence_number;
}
int ChangedSequenceNumber() const { return changed_sequence_number_; }
private:
friend class PaintPropertyNodeTest;
friend class PropertyTreePrinter;
// Returns -1 if `maybe_ancestor` is found in the ancestor chain, or returns
// the depth of the node from the root.
int NodeDepthOrFoundAncestor(const PaintPropertyNode& maybe_ancestor) const;
const PaintPropertyNode& LowestCommonAncestorInternal(
const PaintPropertyNode& other) const;
// Indicates whether this node is an alias for its parent. Parent aliases are
// nodes that do not affect rendering and are ignored for the purposes of
// display item list generation.
bool is_parent_alias_ = false;
// Indicates that the paint property value changed in the last update in the
// prepaint lifecycle step. This is used for raster invalidation and damage
// in the compositor. This value is cleared through ClearChangedToRoot().
mutable PaintPropertyChangeType changed_;
// The changed sequence number is an optimization to avoid an O(n^2) to O(n^4)
// treewalk when clearing the changed bits for the entire tree. When starting
// to clear the changed bits, a new (unique) number is selected for the entire
// tree, and |changed_sequence_number_| is set to this number if the node (and
// ancestors) have already been visited for clearing.
mutable int changed_sequence_number_ = 0;
// Caches the id of the associated cc property node. It's valid only when
// cc_sequence_number_ matches the sequence number of the cc property tree.
mutable int cc_node_id_ = cc::kInvalidPropertyNodeId;
mutable int cc_sequence_number_ = 0;
scoped_refptr<const PaintPropertyNode> parent_;
#if DCHECK_IS_ON()
String debug_name_;
#endif
};
template <typename NodeTypeOrAlias, typename NodeType>
class PaintPropertyNodeBase : public PaintPropertyNode {
public:
PaintPropertyChangeType SetParent(const NodeTypeOrAlias& parent) {
return PaintPropertyNode::SetParent(parent);
}
const NodeTypeOrAlias* Parent() const {
return static_cast<const NodeTypeOrAlias*>(PaintPropertyNode::Parent());
}
const NodeType& Unalias() const {
return static_cast<const NodeType&>(PaintPropertyNode::Unalias());
}
const NodeType* UnaliasedParent() const {
return static_cast<const NodeType*>(PaintPropertyNode::UnaliasedParent());
}
bool IsAncestorOf(const NodeTypeOrAlias& other) const {
return PaintPropertyNode::IsAncestorOf(other);
}
const NodeTypeOrAlias& LowestCommonAncestor(
const NodeTypeOrAlias& other) const {
return static_cast<const NodeTypeOrAlias&>(
PaintPropertyNode::LowestCommonAncestor(other));
}
protected:
explicit PaintPropertyNodeBase(const NodeTypeOrAlias* parent)
: PaintPropertyNode(parent) {}
PaintPropertyNodeBase(const NodeTypeOrAlias& parent, ParentAliasTag tag)
: PaintPropertyNode(parent, tag) {}
};
#if DCHECK_IS_ON()
class PLATFORM_EXPORT PropertyTreePrinter {
STACK_ALLOCATED();
public:
void AddNode(const PaintPropertyNode* node);
String NodesAsTreeString();
String PathAsString(const PaintPropertyNode& last_node);
private:
void BuildTreeString(StringBuilder& string_builder,
const PaintPropertyNode& node,
unsigned indent);
const PaintPropertyNode& RootNode();
LinkedHashSet<const PaintPropertyNode*> nodes_;
};
#endif // DCHECK_IS_ON()
inline std::ostream& operator<<(std::ostream& os,
const PaintPropertyNode& node) {
return os << node.ToString().Utf8();
}
inline std::ostream& operator<<(std::ostream& os,
PaintPropertyChangeType change) {
return os << PaintPropertyChangeTypeToString(change);
}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_PAINT_PROPERTY_NODE_H_