| // 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_PRE_PAINT_TREE_WALK_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PRE_PAINT_TREE_WALK_H_ |
| |
| #include "third_party/blink/renderer/core/paint/clip_rect.h" |
| #include "third_party/blink/renderer/core/paint/paint_invalidator.h" |
| #include "third_party/blink/renderer/core/paint/paint_property_tree_builder.h" |
| |
| namespace blink { |
| |
| class LayoutObject; |
| class LocalFrameView; |
| |
| // This class walks the whole layout tree, beginning from the root |
| // LocalFrameView, across frame boundaries. Helper classes are called for each |
| // tree node to perform actual actions. It expects to be invoked in InPrePaint |
| // phase. |
| class CORE_EXPORT PrePaintTreeWalk { |
| public: |
| PrePaintTreeWalk() = default; |
| void WalkTree(LocalFrameView& root_frame); |
| |
| private: |
| friend PaintInvalidatorContext::ParentContextAccessor; |
| |
| // PrePaintTreewalkContext is large and can lead to stack overflows |
| // when recursion is deep so these context objects are allocated on the heap. |
| // See: https://crbug.com/698653. |
| struct PrePaintTreeWalkContext { |
| PrePaintTreeWalkContext() { tree_builder_context.emplace(); } |
| PrePaintTreeWalkContext( |
| const PrePaintTreeWalkContext& parent_context, |
| const PaintInvalidatorContext::ParentContextAccessor& |
| parent_context_accessor, |
| bool needs_tree_builder_context) |
| : paint_invalidator_context(parent_context_accessor), |
| ancestor_overflow_paint_layer( |
| parent_context.ancestor_overflow_paint_layer), |
| inside_blocking_touch_event_handler( |
| parent_context.inside_blocking_touch_event_handler), |
| effective_whitelisted_touch_action_changed( |
| parent_context.effective_whitelisted_touch_action_changed) { |
| if (needs_tree_builder_context || DCHECK_IS_ON()) { |
| DCHECK(parent_context.tree_builder_context); |
| tree_builder_context.emplace(*parent_context.tree_builder_context); |
| } |
| #if DCHECK_IS_ON() |
| if (needs_tree_builder_context) |
| DCHECK(parent_context.tree_builder_context->is_actually_needed); |
| tree_builder_context->is_actually_needed = needs_tree_builder_context; |
| #endif |
| } |
| |
| base::Optional<PaintPropertyTreeBuilderContext> tree_builder_context; |
| PaintInvalidatorContext paint_invalidator_context; |
| |
| // The ancestor in the PaintLayer tree which has overflow clip, or |
| // is the root layer. Note that it is tree ancestor, not containing |
| // block or stacking ancestor. |
| PaintLayer* ancestor_overflow_paint_layer = nullptr; |
| |
| // Whether there is a blocking touch event handler on any ancestor. |
| bool inside_blocking_touch_event_handler = false; |
| |
| // When the effective whitelisted touch action changes on an ancestor, the |
| // entire subtree may need to update. |
| bool effective_whitelisted_touch_action_changed = false; |
| }; |
| |
| const PrePaintTreeWalkContext& ContextAt(wtf_size_t index) { |
| DCHECK_LT(index, context_storage_.size()); |
| return context_storage_[index]; |
| } |
| |
| void Walk(LocalFrameView&); |
| |
| // This is to minimize stack frame usage during recursion. Modern compilers |
| // (MSVC in particular) can inline across compilation units, resulting in |
| // very big stack frames. Splitting the heavy lifting to a separate function |
| // makes sure the stack frame is freed prior to making a recursive call. |
| // See https://crbug.com/781301 . |
| NOINLINE void WalkInternal(const LayoutObject&, PrePaintTreeWalkContext&); |
| void Walk(const LayoutObject&); |
| |
| // Invalidates paint-layer painting optimizations, such as subsequence caching |
| // and empty paint phase optimizations if clips from the context have changed. |
| void InvalidatePaintLayerOptimizationsIfNeeded(const LayoutObject&, |
| PrePaintTreeWalkContext&); |
| |
| bool NeedsTreeBuilderContextUpdate(const LocalFrameView&, |
| const PrePaintTreeWalkContext&); |
| bool NeedsTreeBuilderContextUpdate(const LayoutObject&, |
| const PrePaintTreeWalkContext&); |
| void UpdateAuxiliaryObjectProperties(const LayoutObject&, |
| PrePaintTreeWalkContext&); |
| |
| bool NeedsEffectiveWhitelistedTouchActionUpdate( |
| const LayoutObject&, |
| PrePaintTreeWalkContext&) const; |
| // Updates |LayoutObject::InsideBlockingTouchEventHandler|. Also ensures |
| // |PrePaintTreeWalkContext.effective_whitelisted_touch_action_changed| is set |
| // which will ensure the subtree is updated too. |
| void UpdateEffectiveWhitelistedTouchAction(const LayoutObject&, |
| PrePaintTreeWalkContext&); |
| bool NeedsHitTestingPaintInvalidation(const LayoutObject&, |
| const PrePaintTreeWalkContext&) const; |
| void InvalidatePaintForHitTesting(const LayoutObject&, |
| PrePaintTreeWalkContext&); |
| |
| void ResizeContextStorageIfNeeded(); |
| |
| PaintInvalidator paint_invalidator_; |
| Vector<PrePaintTreeWalkContext> context_storage_; |
| |
| bool needs_invalidate_chrome_client_ = false; |
| |
| FRIEND_TEST_ALL_PREFIXES(PrePaintTreeWalkTest, ClipRects); |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PRE_PAINT_TREE_WALK_H_ |