blob: 50245944f7f28ce80087f42b74cd901bb565cbbe [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_CORE_PAINT_PAINT_PROPERTY_TREE_BUILDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_PROPERTY_TREE_BUILDER_H_
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
namespace blink {
class FragmentData;
class LayoutObject;
class LocalFrameView;
class PaintLayer;
// The context for PaintPropertyTreeBuilder.
// It's responsible for bookkeeping tree state in other order, for example, the
// most recent position container seen.
struct PaintPropertyTreeBuilderFragmentContext {
USING_FAST_MALLOC(PaintPropertyTreeBuilderFragmentContext);
public:
// Initializes all property tree nodes to the roots.
PaintPropertyTreeBuilderFragmentContext();
// State that propagates on the containing block chain (and so is adjusted
// when an absolute or fixed position object is encountered).
struct ContainingBlockContext {
// The combination of a transform and paint offset describes a linear space.
// When a layout object recur to its children, the main context is expected
// to refer the object's border box, then the callee will derive its own
// border box by translating the space with its own layout location.
const TransformPaintPropertyNode* transform = nullptr;
// Corresponds to LayoutObject::PaintOffset, which does not include
// fragmentation offsets. See FragmentContext for the fragmented version.
LayoutPoint paint_offset;
// The PaintLayer corresponding to the origin of |paint_offset|.
const LayoutObject* paint_offset_root = nullptr;
// Whether newly created children should flatten their inherited transform
// (equivalently, draw into the plane of their parent). Should generally
// be updated whenever |transform| is; flattening only needs to happen
// to immediate children.
bool should_flatten_inherited_transform = false;
// Rendering context for 3D sorting. See
// TransformPaintPropertyNode::renderingContextId.
unsigned rendering_context_id = 0;
// The clip node describes the accumulated raster clip for the current
// subtree. Note that the computed raster region in canvas space for a clip
// node is independent from the transform and paint offset above. Also the
// actual raster region may be affected by layerization and occlusion
// tracking.
const ClipPaintPropertyNode* clip = nullptr;
// The scroll node contains information for scrolling such as the parent
// scroll space, the extent that can be scrolled, etc. Because scroll nodes
// reference a scroll offset transform, scroll nodes should be updated if
// the transform tree changes.
const ScrollPaintPropertyNode* scroll = nullptr;
// True if any fixed-position children within this context are fixed to the
// root of the FrameView (and hence above its scroll).
bool fixed_position_children_fixed_to_root = false;
};
ContainingBlockContext current;
// Separate context for out-of-flow positioned and fixed positioned elements
// are needed because they don't use DOM parent as their containing block.
// These additional contexts normally pass through untouched, and are only
// copied from the main context when the current element serves as the
// containing block of corresponding positioned descendants. Overflow clips
// are also inherited by containing block tree instead of DOM tree, thus they
// are included in the additional context too.
ContainingBlockContext absolute_position;
ContainingBlockContext fixed_position;
// This is the same as current.paintOffset except when a floating object has
// non-block ancestors under its containing block. Paint offsets of the
// non-block ancestors should not be accumulated for the floating object.
LayoutPoint paint_offset_for_float;
// The effect hierarchy is applied by the stacking context tree. It is
// guaranteed that every DOM descendant is also a stacking context descendant.
// Therefore, we don't need extra bookkeeping for effect nodes and can
// generate the effect tree from a DOM-order traversal.
const EffectPaintPropertyNode* current_effect;
// If the object is a flow thread, this records the clip rect for this
// fragment.
base::Optional<LayoutRect> fragment_clip;
// If the object is fragmented, this records the logical top of this fragment
// in the flow thread.
LayoutUnit logical_top_in_flow_thread;
// A repeating object paints at multiple places in the flow thread, once in
// each fragment. The repeated paintings need to add an adjustment to the
// calculated paint offset to paint at the desired place.
LayoutSize repeating_paint_offset_adjustment;
};
struct PaintPropertyTreeBuilderContext {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
PaintPropertyTreeBuilderContext() = default;
Vector<PaintPropertyTreeBuilderFragmentContext, 1> fragments;
const LayoutObject* container_for_absolute_position = nullptr;
const LayoutObject* container_for_fixed_position = nullptr;
// True if a change has forced all properties in a subtree to be updated. This
// can be set due to paint offset changes or when the structure of the
// property tree changes (i.e., a node is added or removed).
bool force_subtree_update = false;
// Whether a clip paint property node appeared, disappeared, or changed
// its clip since this variable was last set to false. This is used
// to find out whether a clip changed since the last transform update.
// Code outside of this class resets clip_changed to false when transforms
// change.
bool clip_changed = false;
#if DCHECK_IS_ON()
// When DCHECK_IS_ON() we create PaintPropertyTreeBuilderContext even if not
// needed. See FindPaintOffsetAndVisualRectNeedingUpdate.h.
bool is_actually_needed = true;
#endif
PaintLayer* painting_layer = nullptr;
// In a fragmented context, some objects (e.g. repeating table headers and
// footers) and their descendants in paint order) repeatedly paint in all
// fragments after the fragment where the object first appears.
bool is_repeating_in_flow_thread = false;
// When printing, fixed-position objects and their descendants need to repeat
// in each page.
bool is_repeating_fixed_position = false;
// True if the current subtree is underneath a LayoutSVGHiddenContainer
// ancestor.
bool has_svg_hidden_container_ancestor = false;
// The physical bounding box of all appearances of the repeating object
// in the flow thread.
LayoutRect repeating_bounding_box_in_flow_thread;
};
// Creates paint property tree nodes for non-local effects in the layout tree.
// Non-local effects include but are not limited to: overflow clip, transform,
// fixed-pos, animation, mask, filters, etc. It expects to be invoked for each
// layout tree node in DOM order during the PrePaint lifecycle phase.
class PaintPropertyTreeBuilder {
public:
static void SetupContextForFrame(LocalFrameView&,
PaintPropertyTreeBuilderContext&);
PaintPropertyTreeBuilder(const LayoutObject& object,
PaintPropertyTreeBuilderContext& context)
: object_(object), context_(context) {}
// Update the paint properties that affect this object (e.g., properties like
// paint offset translation) and ensure the context is up to date. Also
// handles updating the object's paintOffset.
// Returns true if any paint property of the object has changed.
bool UpdateForSelf();
// Update the paint properties that affect children of this object (e.g.,
// scroll offset transform) and ensure the context is up to date.
// Returns true if any paint property of the object has changed.
bool UpdateForChildren();
private:
ALWAYS_INLINE void InitFragmentPaintProperties(
FragmentData&,
bool needs_paint_properties,
const LayoutPoint& pagination_offset = LayoutPoint(),
LayoutUnit logical_top_in_flow_thread = LayoutUnit());
ALWAYS_INLINE void InitSingleFragmentFromParent(bool needs_paint_properties);
ALWAYS_INLINE bool ObjectTypeMightNeedPaintProperties() const;
ALWAYS_INLINE void UpdateCompositedLayerPaginationOffset();
ALWAYS_INLINE PaintPropertyTreeBuilderFragmentContext
ContextForFragment(const base::Optional<LayoutRect>& fragment_clip,
LayoutUnit logical_top_in_flow_thread) const;
ALWAYS_INLINE void CreateFragmentContextsInFlowThread(
bool needs_paint_properties);
ALWAYS_INLINE void CreateFragmentContextsForRepeatingFixedPosition();
ALWAYS_INLINE void CreateFragmentDataForRepeatingFixedPosition(
bool needs_paint_properties);
// Returns whether ObjectPaintProperties were allocated or deleted.
ALWAYS_INLINE bool UpdateFragments();
ALWAYS_INLINE void UpdatePaintingLayer();
ALWAYS_INLINE void UpdateRepeatingPaintOffsetAdjustment();
ALWAYS_INLINE void UpdateRepeatingTableHeaderPaintOffsetAdjustment();
ALWAYS_INLINE void UpdateRepeatingTableFooterPaintOffsetAdjustment();
const LayoutObject& object_;
PaintPropertyTreeBuilderContext& context_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_PROPERTY_TREE_BUILDER_H_