blob: 69d1a3fc1f2203bcb879f1ab995ce7aad7ac1850 [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_CLIP_PAINT_PROPERTY_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_CLIP_PAINT_PROPERTY_NODE_H_
#include <algorithm>
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/platform_export.h"
namespace blink {
class GeometryMapperClipCache;
class PropertyTreeState;
// A clip rect created by a css property such as "overflow" or "clip".
// Along with a reference to the transform space the clip rect is based on,
// and a parent ClipPaintPropertyNode for inherited clips.
//
// The clip tree is rooted at a node with no parent. This root node should
// not be modified.
class ClipPaintPropertyNode;
class PLATFORM_EXPORT ClipPaintPropertyNodeOrAlias
: public PaintPropertyNode<ClipPaintPropertyNodeOrAlias,
ClipPaintPropertyNode> {
public:
// Checks if the accumulated clip from |this| to |relative_to_state.Clip()|
// has changed, at least significance of |change|, in the space of
// |relative_to_state.Transform()|. We check for changes of not only clip
// nodes, but also LocalTransformSpace relative to |relative_to_state
// .Transform()| of the clip nodes. |transform_not_to_check| specifies a
// transform node that the caller has checked or will check its change in
// other ways and this function should treat it as unchanged.
bool Changed(
PaintPropertyChangeType change,
const PropertyTreeState& relative_to_state,
const TransformPaintPropertyNodeOrAlias* transform_not_to_check) const;
protected:
using PaintPropertyNode::PaintPropertyNode;
};
class ClipPaintPropertyNodeAlias : public ClipPaintPropertyNodeOrAlias {
public:
static scoped_refptr<ClipPaintPropertyNodeAlias> Create(
const ClipPaintPropertyNodeOrAlias& parent) {
return base::AdoptRef(new ClipPaintPropertyNodeAlias(parent));
}
PaintPropertyChangeType SetParent(
const ClipPaintPropertyNodeOrAlias& parent) {
DCHECK(IsParentAlias());
return PaintPropertyNode::SetParent(parent);
}
private:
explicit ClipPaintPropertyNodeAlias(
const ClipPaintPropertyNodeOrAlias& parent)
: ClipPaintPropertyNodeOrAlias(parent, kParentAlias) {}
};
class PLATFORM_EXPORT ClipPaintPropertyNode
: public ClipPaintPropertyNodeOrAlias {
public:
// 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 {
State(scoped_refptr<const TransformPaintPropertyNodeOrAlias>
local_transform_space,
const FloatRoundedRect& clip_rect)
: State(std::move(local_transform_space), clip_rect, clip_rect) {}
State(scoped_refptr<const TransformPaintPropertyNodeOrAlias>
local_transform_space,
const FloatRoundedRect& clip_rect,
const FloatRoundedRect& pixel_snapped_clip_rect)
: local_transform_space(std::move(local_transform_space)) {
SetClipRect(clip_rect, pixel_snapped_clip_rect);
}
scoped_refptr<const TransformPaintPropertyNodeOrAlias>
local_transform_space;
base::Optional<FloatClipRect> clip_rect_excluding_overlay_scrollbars;
scoped_refptr<const RefCountedPath> clip_path;
void SetClipRect(const FloatRoundedRect& clip_rect_arg,
const FloatRoundedRect& pixel_snapped_clip_rect_arg) {
clip_rect = clip_rect_arg;
pixel_snapped_clip_rect = pixel_snapped_clip_rect_arg;
}
PaintPropertyChangeType ComputeChange(const State& other) const {
if (local_transform_space != other.local_transform_space ||
pixel_snapped_clip_rect != other.pixel_snapped_clip_rect ||
clip_path != other.clip_path) {
return PaintPropertyChangeType::kChangedOnlyValues;
}
if (clip_rect_excluding_overlay_scrollbars !=
other.clip_rect_excluding_overlay_scrollbars) {
return PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
}
return PaintPropertyChangeType::kUnchanged;
}
friend class ClipPaintPropertyNode;
private:
FloatRoundedRect clip_rect;
FloatRoundedRect pixel_snapped_clip_rect;
};
// This node is really a sentinel, and does not represent a real clip space.
static const ClipPaintPropertyNode& Root();
static scoped_refptr<ClipPaintPropertyNode> Create(
const ClipPaintPropertyNodeOrAlias& parent,
State&& state) {
return base::AdoptRef(new ClipPaintPropertyNode(&parent, std::move(state)));
}
// The empty AnimationState struct is to meet the requirement of
// ObjectPaintProperties.
struct AnimationState {};
PaintPropertyChangeType Update(const ClipPaintPropertyNodeOrAlias& parent,
State&& state,
const AnimationState& = AnimationState()) {
auto parent_changed = SetParent(parent);
auto state_changed = state_.ComputeChange(state);
if (state_changed != PaintPropertyChangeType::kUnchanged) {
state_ = std::move(state);
AddChanged(state_changed);
}
return std::max(parent_changed, state_changed);
}
const ClipPaintPropertyNode& Unalias() const = delete;
bool IsParentAlias() const = delete;
const TransformPaintPropertyNodeOrAlias& LocalTransformSpace() const {
return *state_.local_transform_space;
}
// The pixel-snapped clip rect may be the same as the unsnapped one, in cases
// where pixel snapping is not desirable for a clip, such as for SVG.
const FloatRoundedRect& PixelSnappedClipRect() const {
return state_.pixel_snapped_clip_rect;
}
const FloatRoundedRect UnsnappedClipRect() const { return state_.clip_rect; }
const FloatClipRect UnsnappedClipRectExcludingOverlayScrollbars() const {
return state_.clip_rect_excluding_overlay_scrollbars
? *state_.clip_rect_excluding_overlay_scrollbars
: FloatClipRect(state_.clip_rect);
}
const RefCountedPath* ClipPath() const { return state_.clip_path.get(); }
std::unique_ptr<JSONObject> ToJSON() const;
private:
friend class PaintPropertyNode<ClipPaintPropertyNodeOrAlias,
ClipPaintPropertyNode>;
ClipPaintPropertyNode(const ClipPaintPropertyNodeOrAlias* parent,
State&& state)
: ClipPaintPropertyNodeOrAlias(parent), state_(std::move(state)) {}
void AddChanged(PaintPropertyChangeType changed) {
// TODO(crbug.com/814815): This is a workaround of the bug. When the bug is
// fixed, change the following condition to
// DCHECK(!clip_cache_ || !clip_cache_->IsValid());
DCHECK_NE(PaintPropertyChangeType::kUnchanged, changed);
if (clip_cache_ && clip_cache_->IsValid()) {
DLOG(WARNING) << "Clip tree changed without invalidating the cache.";
GeometryMapperClipCache::ClearCache();
}
PaintPropertyNode::AddChanged(changed);
}
// For access to GetClipCache();
friend class GeometryMapper;
friend class GeometryMapperTest;
GeometryMapperClipCache& GetClipCache() const {
return const_cast<ClipPaintPropertyNode*>(this)->GetClipCache();
}
GeometryMapperClipCache& GetClipCache() {
if (!clip_cache_)
clip_cache_.reset(new GeometryMapperClipCache());
return *clip_cache_.get();
}
State state_;
std::unique_ptr<GeometryMapperClipCache> clip_cache_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_CLIP_PAINT_PROPERTY_NODE_H_