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