1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PRE_PAINT_TREE_WALK_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PRE_PAINT_TREE_WALK_H_ 7 8 #include "third_party/blink/renderer/core/paint/clip_rect.h" 9 #include "third_party/blink/renderer/core/paint/paint_invalidator.h" 10 #include "third_party/blink/renderer/core/paint/paint_property_tree_builder.h" 11 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 12 13 namespace blink { 14 15 class LayoutObject; 16 class LocalFrameView; 17 class NGFragmentChildIterator; 18 19 // This class walks the whole layout tree, beginning from the root 20 // LocalFrameView, across frame boundaries. Helper classes are called for each 21 // tree node to perform actual actions. It expects to be invoked in InPrePaint 22 // phase. 23 class CORE_EXPORT PrePaintTreeWalk { 24 DISALLOW_NEW(); 25 26 public: 27 PrePaintTreeWalk() = default; 28 void WalkTree(LocalFrameView& root_frame); 29 30 static bool ObjectRequiresPrePaint(const LayoutObject&); 31 static bool ObjectRequiresTreeBuilderContext(const LayoutObject&); 32 33 private: 34 friend PaintInvalidatorContext::ParentContextAccessor; 35 36 // PrePaintTreewalkContext is large and can lead to stack overflows 37 // when recursion is deep so these context objects are allocated on the heap. 38 // See: https://crbug.com/698653. 39 struct PrePaintTreeWalkContext { PrePaintTreeWalkContextPrePaintTreeWalkContext40 PrePaintTreeWalkContext() { tree_builder_context.emplace(); } PrePaintTreeWalkContextPrePaintTreeWalkContext41 PrePaintTreeWalkContext( 42 const PrePaintTreeWalkContext& parent_context, 43 const PaintInvalidatorContext::ParentContextAccessor& 44 parent_context_accessor, 45 bool needs_tree_builder_context) 46 : paint_invalidator_context(parent_context_accessor), 47 ancestor_scroll_container_paint_layer( 48 parent_context.ancestor_scroll_container_paint_layer), 49 inside_blocking_touch_event_handler( 50 parent_context.inside_blocking_touch_event_handler), 51 effective_allowed_touch_action_changed( 52 parent_context.effective_allowed_touch_action_changed), 53 inside_blocking_wheel_event_handler( 54 parent_context.inside_blocking_wheel_event_handler), 55 blocking_wheel_event_handler_changed( 56 parent_context.blocking_wheel_event_handler_changed), 57 clip_changed(parent_context.clip_changed), 58 paint_invalidation_container( 59 parent_context.paint_invalidation_container), 60 paint_invalidation_container_for_stacked_contents( 61 parent_context 62 .paint_invalidation_container_for_stacked_contents) { 63 if (needs_tree_builder_context || DCHECK_IS_ON()) { 64 DCHECK(parent_context.tree_builder_context); 65 tree_builder_context.emplace(*parent_context.tree_builder_context); 66 } 67 #if DCHECK_IS_ON() 68 if (needs_tree_builder_context) 69 DCHECK(parent_context.tree_builder_context->is_actually_needed); 70 tree_builder_context->is_actually_needed = needs_tree_builder_context; 71 #endif 72 } 73 74 base::Optional<PaintPropertyTreeBuilderContext> tree_builder_context; 75 PaintInvalidatorContext paint_invalidator_context; 76 77 // The ancestor in the PaintLayer tree which is a scroll container. Note 78 // that it is tree ancestor, not containing block or stacking ancestor. 79 PaintLayer* ancestor_scroll_container_paint_layer = nullptr; 80 81 // Whether there is a blocking touch event handler on any ancestor. 82 bool inside_blocking_touch_event_handler = false; 83 84 // When the effective allowed touch action changes on an ancestor, the 85 // entire subtree may need to update. 86 bool effective_allowed_touch_action_changed = false; 87 88 // Whether there is a blocking wheel event handler on any ancestor. 89 bool inside_blocking_wheel_event_handler = false; 90 91 // When the blocking wheel event handlers change on an ancestor, the entire 92 // subtree may need to update. 93 bool blocking_wheel_event_handler_changed = false; 94 95 // This is set to true once we see tree_builder_context->clip_changed is 96 // true. It will be propagated to descendant contexts even if we don't 97 // create tree_builder_context. 98 bool clip_changed = false; 99 100 const LayoutBoxModelObject* paint_invalidation_container = nullptr; 101 const LayoutBoxModelObject* 102 paint_invalidation_container_for_stacked_contents = nullptr; 103 }; 104 105 static bool ContextRequiresPrePaint(const PrePaintTreeWalkContext&); 106 static bool ContextRequiresTreeBuilderContext(const PrePaintTreeWalkContext&); 107 108 #if DCHECK_IS_ON() 109 void CheckTreeBuilderContextState(const LayoutObject&, 110 const PrePaintTreeWalkContext&); 111 #endif 112 ContextAt(wtf_size_t index)113 const PrePaintTreeWalkContext& ContextAt(wtf_size_t index) { 114 DCHECK_LT(index, context_storage_.size()); 115 return context_storage_[index]; 116 } 117 118 void Walk(LocalFrameView&); 119 120 // This is to minimize stack frame usage during recursion. Modern compilers 121 // (MSVC in particular) can inline across compilation units, resulting in 122 // very big stack frames. Splitting the heavy lifting to a separate function 123 // makes sure the stack frame is freed prior to making a recursive call. 124 // See https://crbug.com/781301 . 125 126 // TODO(https://crbug.com/841364): Remove is_wheel_event_regions_enabled 127 // argument once kWheelEventRegions feature flag is removed. 128 NOINLINE void WalkInternal(const LayoutObject&, 129 const NGFragmentChildIterator*, 130 PrePaintTreeWalkContext&, 131 bool is_wheel_event_regions_enabled); 132 void WalkNGChildren(const LayoutObject* parent, 133 NGFragmentChildIterator*, 134 bool is_wheel_event_regions_enabled); 135 void WalkLegacyChildren(const LayoutObject&, 136 bool is_wheel_event_regions_enabled); 137 void WalkChildren(const LayoutObject*, 138 const NGFragmentChildIterator*, 139 bool is_wheel_event_regions_enabled); 140 void Walk(const LayoutObject&, 141 const NGFragmentChildIterator*, 142 bool is_wheel_event_regions_enabled); 143 144 bool NeedsTreeBuilderContextUpdate(const LocalFrameView&, 145 const PrePaintTreeWalkContext&); 146 void UpdateAuxiliaryObjectProperties(const LayoutObject&, 147 PrePaintTreeWalkContext&); 148 // Updates |LayoutObject::InsideBlockingTouchEventHandler|. Also ensures 149 // |PrePaintTreeWalkContext.effective_allowed_touch_action_changed| is set 150 // which will ensure the subtree is updated too. 151 void UpdateEffectiveAllowedTouchAction(const LayoutObject&, 152 PrePaintTreeWalkContext&); 153 // Updates |LayoutObject::InsideBlockingWheelEventHandler|. Also ensures 154 // |PrePaintTreeWalkContext.blocking_wheel_event_handler_changed| is set 155 // which will ensure the subtree is updated too. 156 void UpdateBlockingWheelEventHandler(const LayoutObject&, 157 PrePaintTreeWalkContext&); 158 void InvalidatePaintForHitTesting(const LayoutObject&, 159 PrePaintTreeWalkContext&); 160 161 void ResizeContextStorageIfNeeded(); 162 163 void UpdatePaintInvalidationContainer(const LayoutObject& object, 164 const PaintLayer* painting_layer, 165 PrePaintTreeWalkContext& context, 166 bool is_ng_painting); 167 168 PaintInvalidator paint_invalidator_; 169 Vector<PrePaintTreeWalkContext> context_storage_; 170 171 bool needs_invalidate_chrome_client_ = false; 172 173 FRIEND_TEST_ALL_PREFIXES(PrePaintTreeWalkTest, ClipRects); 174 }; 175 176 } // namespace blink 177 178 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PRE_PAINT_TREE_WALK_H_ 179