blob: cfaee4d261a2748683d88022013afcc35e179c63 [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_PAINT_TRANSFORM_PAINT_PROPERTY_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_TRANSFORM_PAINT_PROPERTY_NODE_H_
#include "cc/layers/layer_sticky_position_constraint.h"
#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
namespace blink {
using CompositorStickyConstraint = cc::LayerStickyPositionConstraint;
// A transform (e.g., created by css "transform" or "perspective", or for
// internal positioning such as paint offset or scrolling) along with a
// reference to the parent TransformPaintPropertyNode. The scroll tree is
// referenced by transform nodes and a transform node with an associated scroll
// node will be a 2d transform for scroll offset.
//
// The transform tree is rooted at a node with no parent. This root node should
// not be modified.
class PLATFORM_EXPORT TransformPaintPropertyNode
: public PaintPropertyNode<TransformPaintPropertyNode> {
public:
enum class BackfaceVisibility : unsigned char {
// backface-visibility is not inherited per the css spec. However, for an
// element that don't create a new plane, for now we let the element
// inherit the parent backface-visibility.
kInherited,
// backface-visibility: hidden for the new plane.
kHidden,
// backface-visibility: visible for the new plane.
kVisible,
};
// To make it less verbose and more readable to construct and update a node,
// a struct with default values is used to represent the state.
struct State {
TransformationMatrix matrix;
scoped_refptr<const ScrollPaintPropertyNode> scroll;
FloatPoint3D origin;
bool flattens_inherited_transform = false;
// Caches value of matrix_.IsIdentityOr2DTranslation(). The caller can set
// this field to true if the matrix is known to be identity or 2d
// translation, or the field will be updated automatically.
bool is_identity_or_2d_translation = false;
bool affected_by_outer_viewport_bounds_delta = false;
BackfaceVisibility backface_visibility = BackfaceVisibility::kInherited;
unsigned rendering_context_id = 0;
CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
CompositorElementId compositor_element_id;
std::unique_ptr<CompositorStickyConstraint> sticky_constraint;
bool operator==(const State& o) const {
return matrix == o.matrix && origin == o.origin &&
flattens_inherited_transform == o.flattens_inherited_transform &&
backface_visibility == o.backface_visibility &&
rendering_context_id == o.rendering_context_id &&
direct_compositing_reasons == o.direct_compositing_reasons &&
compositor_element_id == o.compositor_element_id &&
scroll == o.scroll &&
affected_by_outer_viewport_bounds_delta ==
o.affected_by_outer_viewport_bounds_delta &&
((!sticky_constraint && !o.sticky_constraint) ||
(sticky_constraint && o.sticky_constraint &&
*sticky_constraint == *o.sticky_constraint));
}
};
// This node is really a sentinel, and does not represent a real transform
// space.
static const TransformPaintPropertyNode& Root();
static scoped_refptr<TransformPaintPropertyNode> Create(
const TransformPaintPropertyNode& parent,
State&& state) {
return base::AdoptRef(new TransformPaintPropertyNode(
&parent, std::move(state), false /* is_parent_alias */));
}
static scoped_refptr<TransformPaintPropertyNode> CreateAlias(
const TransformPaintPropertyNode& parent) {
return base::AdoptRef(new TransformPaintPropertyNode(
&parent, State{}, true /* is_parent_alias */));
}
bool Update(const TransformPaintPropertyNode& parent, State&& state) {
bool parent_changed = SetParent(&parent);
if (state == state_)
return parent_changed;
DCHECK(!IsParentAlias()) << "Changed the state of an alias node.";
state_ = std::move(state);
SetChanged();
CheckAndUpdateIsIdentityOr2DTranslation();
Validate();
return true;
}
// If |relative_to_node| is an ancestor of |this|, returns true if any node is
// marked changed along the path from |this| to |relative_to_node| (not
// included). Otherwise returns the combined changed status of the paths
// from |this| and |relative_to_node| to the root.
bool Changed(const TransformPaintPropertyNode& relative_to_node) const;
const TransformationMatrix& Matrix() const { return state_.matrix; }
const FloatPoint3D& Origin() const { return state_.origin; }
// The associated scroll node, or nullptr otherwise.
const ScrollPaintPropertyNode* ScrollNode() const {
return state_.scroll.get();
}
// If true, this node is translated by the viewport bounds delta, which is
// used to keep bottom-fixed elements appear fixed to the bottom of the
// screen in the presence of URL bar movement.
bool IsAffectedByOuterViewportBoundsDelta() const {
return state_.affected_by_outer_viewport_bounds_delta;
}
const cc::LayerStickyPositionConstraint* GetStickyConstraint() const {
return state_.sticky_constraint.get();
}
// If this is a scroll offset translation (i.e., has an associated scroll
// node), returns this. Otherwise, returns the transform node that this node
// scrolls with respect to. This can require a full ancestor traversal.
const TransformPaintPropertyNode& NearestScrollTranslationNode() const;
// If true, content with this transform node (or its descendant) appears in
// the plane of its parent. This is implemented by flattening the total
// accumulated transform from its ancestors.
bool FlattensInheritedTransform() const {
return state_.flattens_inherited_transform;
}
bool IsIdentityOr2DTranslation() const {
DCHECK_EQ(state_.is_identity_or_2d_translation,
state_.matrix.IsIdentityOr2DTranslation());
return state_.is_identity_or_2d_translation;
}
// Returns the local BackfaceVisibility value set on this node.
// See |IsBackfaceHidden()| for computing whether this transform node is
// hidden or not.
BackfaceVisibility GetBackfaceVisibility() const {
return state_.backface_visibility;
}
// Returns the first non-inherited BackefaceVisibility value along the
// transform node ancestor chain, including this node's value if it is
// non-inherited. TODO(wangxianzhu): Let PaintPropertyTreeBuilder calculate
// the value instead of walking up the tree.
bool IsBackfaceHidden() const {
const auto* node = this;
while (node &&
node->GetBackfaceVisibility() == BackfaceVisibility::kInherited)
node = node->Parent();
return node && node->GetBackfaceVisibility() == BackfaceVisibility::kHidden;
}
bool HasDirectCompositingReasons() const {
return state_.direct_compositing_reasons != CompositingReason::kNone;
}
bool RequiresCompositingForAnimation() const {
return state_.direct_compositing_reasons &
CompositingReason::kComboActiveAnimation;
}
bool RequiresCompositingForRootScroller() const {
return state_.direct_compositing_reasons & CompositingReason::kRootScroller;
}
const CompositorElementId& GetCompositorElementId() const {
return state_.compositor_element_id;
}
// Content whose transform nodes have a common rendering context ID are 3D
// sorted. If this is 0, content will not be 3D sorted.
unsigned RenderingContextId() const { return state_.rendering_context_id; }
bool HasRenderingContext() const { return state_.rendering_context_id; }
std::unique_ptr<JSONObject> ToJSON() const;
// Returns memory usage of the transform cache of this node plus ancestors.
size_t CacheMemoryUsageInBytes() const;
private:
friend class PaintPropertyNode<TransformPaintPropertyNode>;
TransformPaintPropertyNode(const TransformPaintPropertyNode* parent,
State&& state,
bool is_parent_alias)
: PaintPropertyNode(parent, is_parent_alias), state_(std::move(state)) {
CheckAndUpdateIsIdentityOr2DTranslation();
Validate();
}
void CheckAndUpdateIsIdentityOr2DTranslation() {
if (IsParentAlias()) {
DCHECK(state_.matrix.IsIdentity());
state_.is_identity_or_2d_translation = true;
} else if (state_.is_identity_or_2d_translation) {
DCHECK(state_.matrix.IsIdentityOr2DTranslation());
} else {
state_.is_identity_or_2d_translation =
state_.matrix.IsIdentityOr2DTranslation();
}
}
void Validate() const {
#if DCHECK_IS_ON()
if (state_.scroll) {
// If there is an associated scroll node, this can only be a 2d
// translation for scroll offset.
DCHECK(state_.is_identity_or_2d_translation);
// The scroll compositor element id should be stored on the scroll node.
DCHECK(!state_.compositor_element_id);
}
#endif
}
void SetChanged() {
// TODO(crbug.com/814815): This is a workaround of the bug. When the bug is
// fixed, change the following condition to
// DCHECK(!transform_cache_ || !transform_cache_->IsValid());
if (transform_cache_ && transform_cache_->IsValid()) {
DLOG(WARNING) << "Transform tree changed without invalidating the cache.";
GeometryMapperTransformCache::ClearCache();
GeometryMapperClipCache::ClearCache();
}
PaintPropertyNode::SetChanged();
}
// For access to GetTransformCache() and SetCachedTransform.
friend class GeometryMapper;
friend class GeometryMapperTest;
friend class GeometryMapperTransformCache;
friend class GeometryMapperTransformCacheTest;
const GeometryMapperTransformCache& GetTransformCache() const {
if (!transform_cache_)
transform_cache_.reset(new GeometryMapperTransformCache);
transform_cache_->UpdateIfNeeded(*this);
return *transform_cache_;
}
void UpdateScreenTransform() const {
DCHECK(transform_cache_);
transform_cache_->UpdateScreenTransform(*this);
}
State state_;
mutable std::unique_ptr<GeometryMapperTransformCache> transform_cache_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_TRANSFORM_PAINT_PROPERTY_NODE_H_