1 /*
2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Dirk Mueller <mueller@kde.org>
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7 * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9 * Copyright (C) 2009 Google Inc. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
28
29 #include <algorithm>
30 #include <memory>
31 #include <utility>
32
33 #include "base/feature_list.h"
34 #include "base/memory/ptr_util.h"
35 #include "base/metrics/field_trial_params.h"
36 #include "base/numerics/safe_conversions.h"
37 #include "cc/input/main_thread_scrolling_reason.h"
38 #include "cc/layers/picture_layer.h"
39 #include "cc/tiles/frame_viewer_instrumentation.h"
40 #include "cc/trees/layer_tree_host.h"
41 #include "third_party/blink/public/common/features.h"
42 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
43 #include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
44 #include "third_party/blink/public/platform/task_type.h"
45 #include "third_party/blink/public/platform/web_rect.h"
46 #include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h"
47 #include "third_party/blink/renderer/core/accessibility/apply_dark_mode.h"
48 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
49 #include "third_party/blink/renderer/core/animation/document_animations.h"
50 #include "third_party/blink/renderer/core/css/font_face_set_document.h"
51 #include "third_party/blink/renderer/core/css/style_change_reason.h"
52 #include "third_party/blink/renderer/core/dom/static_node_list.h"
53 #include "third_party/blink/renderer/core/editing/compute_layer_selection.h"
54 #include "third_party/blink/renderer/core/editing/drag_caret.h"
55 #include "third_party/blink/renderer/core/editing/frame_selection.h"
56 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
57 #include "third_party/blink/renderer/core/events/error_event.h"
58 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
59 #include "third_party/blink/renderer/core/frame/browser_controls.h"
60 #include "third_party/blink/renderer/core/frame/find_in_page.h"
61 #include "third_party/blink/renderer/core/frame/frame_overlay.h"
62 #include "third_party/blink/renderer/core/frame/frame_view_auto_size_info.h"
63 #include "third_party/blink/renderer/core/frame/local_frame.h"
64 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
65 #include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
66 #include "third_party/blink/renderer/core/frame/location.h"
67 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
68 #include "third_party/blink/renderer/core/frame/remote_frame.h"
69 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
70 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
71 #include "third_party/blink/renderer/core/frame/settings.h"
72 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
73 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
74 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
75 #include "third_party/blink/renderer/core/html/forms/text_control_element.h"
76 #include "third_party/blink/renderer/core/html/html_frame_element.h"
77 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
78 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
79 #include "third_party/blink/renderer/core/html/portal/document_portals.h"
80 #include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
81 #include "third_party/blink/renderer/core/html/portal/portal_contents.h"
82 #include "third_party/blink/renderer/core/html_names.h"
83 #include "third_party/blink/renderer/core/input/event_handler.h"
84 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
85 #include "third_party/blink/renderer/core/intersection_observer/intersection_observation.h"
86 #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h"
87 #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
88 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
89 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
90 #include "third_party/blink/renderer/core/layout/layout_counter.h"
91 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
92 #include "third_party/blink/renderer/core/layout/layout_embedded_object.h"
93 #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
94 #include "third_party/blink/renderer/core/layout/layout_view.h"
95 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
96 #include "third_party/blink/renderer/core/layout/style_retain_scope.h"
97 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
98 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
99 #include "third_party/blink/renderer/core/layout/traced_layout_object.h"
100 #include "third_party/blink/renderer/core/loader/document_loader.h"
101 #include "third_party/blink/renderer/core/loader/frame_loader.h"
102 #include "third_party/blink/renderer/core/media_type_names.h"
103 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
104 #include "third_party/blink/renderer/core/page/chrome_client.h"
105 #include "third_party/blink/renderer/core/page/focus_controller.h"
106 #include "third_party/blink/renderer/core/page/frame_tree.h"
107 #include "third_party/blink/renderer/core/page/link_highlight.h"
108 #include "third_party/blink/renderer/core/page/page.h"
109 #include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
110 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
111 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator_context.h"
112 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
113 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
114 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
115 #include "third_party/blink/renderer/core/page/validation_message_client.h"
116 #include "third_party/blink/renderer/core/paint/block_paint_invalidator.h"
117 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
118 #include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h"
119 #include "third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.h"
120 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
121 #include "third_party/blink/renderer/core/paint/frame_painter.h"
122 #include "third_party/blink/renderer/core/paint/paint_layer.h"
123 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
124 #include "third_party/blink/renderer/core/paint/paint_timing.h"
125 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
126 #include "third_party/blink/renderer/core/paint/pre_paint_tree_walk.h"
127 #include "third_party/blink/renderer/core/probe/core_probes.h"
128 #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
129 #include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
130 #include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
131 #include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
132 #include "third_party/blink/renderer/core/style/computed_style.h"
133 #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
134 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
135 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
136 #include "third_party/blink/renderer/platform/geometry/double_rect.h"
137 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
138 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
139 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
140 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
141 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
142 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
143 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
144 #include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
145 #include "third_party/blink/renderer/platform/graphics/paint/graphics_layer_display_item.h"
146 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
147 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
148 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
149 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
150 #include "third_party/blink/renderer/platform/language.h"
151 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
152 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
153 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
154 #include "third_party/blink/renderer/platform/web_test_support.h"
155 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
156 #include "third_party/skia/include/core/SkBitmap.h"
157 #include "ui/base/cursor/cursor.h"
158 #include "ui/base/mojom/cursor_type.mojom-blink.h"
159
160 // Used to check for dirty layouts violating document lifecycle rules.
161 // If arg evaluates to true, the program will continue. If arg evaluates to
162 // false, program will crash if DCHECK_IS_ON() or return false from the current
163 // function.
164 #define CHECK_FOR_DIRTY_LAYOUT(arg) \
165 do { \
166 if (!(arg)) { \
167 NOTREACHED(); \
168 return false; \
169 } \
170 } while (false)
171
172 namespace blink {
173 namespace {
174
175 // Logs a UseCounter for the size of the cursor that will be set. This will be
176 // used for compatibility analysis to determine whether the maximum size can be
177 // reduced.
LogCursorSizeCounter(LocalFrame * frame,const ui::Cursor & cursor)178 void LogCursorSizeCounter(LocalFrame* frame, const ui::Cursor& cursor) {
179 DCHECK(frame);
180 SkBitmap bitmap = cursor.custom_bitmap();
181 if (cursor.type() != ui::mojom::blink::CursorType::kCustom || bitmap.isNull())
182 return;
183 // Should not overflow, this calculation is done elsewhere when determining
184 // whether the cursor exceeds its maximum size (see event_handler.cc).
185 auto scaled_size = IntSize(bitmap.width(), bitmap.height());
186 scaled_size.Scale(1 / cursor.image_scale_factor());
187 if (scaled_size.Width() > 64 || scaled_size.Height() > 64) {
188 UseCounter::Count(frame->GetDocument(), WebFeature::kCursorImageGT64x64);
189 } else if (scaled_size.Width() > 32 || scaled_size.Height() > 32) {
190 UseCounter::Count(frame->GetDocument(), WebFeature::kCursorImageGT32x32);
191 } else {
192 UseCounter::Count(frame->GetDocument(), WebFeature::kCursorImageLE32x32);
193 }
194 }
195
196 // Default value and parameter name for how long we want to delay the
197 // compositor commit beyond the start of document lifdecycle updates to avoid
198 // flash between navigations. The delay should be small enough so that it won't
199 // confuse users expecting a new page to appear after navigation and the omnibar
200 // has updated the url display.
201 constexpr int kPaintHoldingCommitDelayDefaultInMs = 500; // 30 frames @ 60hz
202 constexpr char kPaintHoldingCommitDelayParameterName[] = "commit_delay";
203
204 // Get the field trial parameter value for Paint Holding.
GetCommitDelayForPaintHolding()205 base::TimeDelta GetCommitDelayForPaintHolding() {
206 DCHECK(base::FeatureList::IsEnabled(blink::features::kPaintHolding));
207 return base::TimeDelta::FromMilliseconds(
208 base::GetFieldTrialParamByFeatureAsInt(
209 blink::features::kPaintHolding, kPaintHoldingCommitDelayParameterName,
210 kPaintHoldingCommitDelayDefaultInMs));
211 }
212
213 } // namespace
214
215 // The maximum number of updatePlugins iterations that should be done before
216 // returning.
217 static const unsigned kMaxUpdatePluginsIterations = 2;
218
LocalFrameView(LocalFrame & frame)219 LocalFrameView::LocalFrameView(LocalFrame& frame)
220 : LocalFrameView(frame, IntRect()) {
221 Show();
222 }
223
LocalFrameView(LocalFrame & frame,const IntSize & initial_size)224 LocalFrameView::LocalFrameView(LocalFrame& frame, const IntSize& initial_size)
225 : LocalFrameView(frame, IntRect(IntPoint(), initial_size)) {
226 SetLayoutSizeInternal(initial_size);
227 Show();
228 }
229
LocalFrameView(LocalFrame & frame,IntRect frame_rect)230 LocalFrameView::LocalFrameView(LocalFrame& frame, IntRect frame_rect)
231 : FrameView(frame_rect),
232 frame_(frame),
233 display_mode_(blink::mojom::DisplayMode::kBrowser),
234 can_have_scrollbars_(true),
235 has_pending_layout_(false),
236 layout_scheduling_enabled_(true),
237 layout_count_for_testing_(0),
238 lifecycle_update_count_for_testing_(0),
239 nested_layout_count_(0),
240 // We want plugin updates to happen in FIFO order with loading tasks.
241 update_plugins_timer_(frame.GetTaskRunner(TaskType::kInternalLoading),
242 this,
243 &LocalFrameView::UpdatePluginsTimerFired),
244 first_layout_(true),
245 base_background_color_(Color::kWhite),
246 last_zoom_factor_(1.0f),
247 media_type_(media_type_names::kScreen),
248 safe_to_propagate_scroll_to_parent_(true),
249 visually_non_empty_character_count_(0),
250 visually_non_empty_pixel_count_(0),
251 is_visually_non_empty_(false),
252 sticky_position_object_count_(0),
253 layout_size_fixed_to_frame_size_(true),
254 needs_update_geometries_(false),
255 root_layer_did_scroll_(false),
256 frame_timing_requests_dirty_(true),
257 // The compositor throttles the main frame using deferred begin main frame
258 // updates. We can't throttle it here or it seems the root compositor
259 // doesn't get setup properly.
260 lifecycle_updates_throttled_(!GetFrame().IsMainFrame()),
261 current_update_lifecycle_phases_target_state_(
262 DocumentLifecycle::kUninitialized),
263 past_layout_lifecycle_update_(false),
264 suppress_adjust_view_size_(false),
265 intersection_observation_state_(kNotNeeded),
266 needs_forced_compositing_update_(false),
267 needs_focus_on_fragment_(false),
268 in_lifecycle_update_(false),
269 main_thread_scrolling_reasons_(0),
270 forced_layout_stack_depth_(0),
271 forced_layout_start_time_(base::TimeTicks()),
272 paint_frame_count_(0),
273 unique_id_(NewUniqueObjectId()),
274 layout_shift_tracker_(std::make_unique<LayoutShiftTracker>(this)),
275 paint_timing_detector_(MakeGarbageCollected<PaintTimingDetector>(this))
276 #if DCHECK_IS_ON()
277 ,
278 is_updating_descendant_dependent_flags_(false)
279 #endif
280 {
281 // Propagate the marginwidth/height and scrolling modes to the view.
282 if (frame_->Owner() && frame_->Owner()->ScrollbarMode() ==
283 mojom::blink::ScrollbarMode::kAlwaysOff)
284 SetCanHaveScrollbars(false);
285 }
286
~LocalFrameView()287 LocalFrameView::~LocalFrameView() {
288 #if DCHECK_IS_ON()
289 DCHECK(has_been_disposed_);
290 #endif
291 }
292
Trace(Visitor * visitor)293 void LocalFrameView::Trace(Visitor* visitor) {
294 visitor->Trace(frame_);
295 visitor->Trace(fragment_anchor_);
296 visitor->Trace(scrollable_areas_);
297 visitor->Trace(animating_scrollable_areas_);
298 visitor->Trace(auto_size_info_);
299 visitor->Trace(plugins_);
300 visitor->Trace(scrollbars_);
301 visitor->Trace(viewport_scrollable_area_);
302 visitor->Trace(anchoring_adjustment_queue_);
303 visitor->Trace(scroll_event_queue_);
304 visitor->Trace(paint_timing_detector_);
305 visitor->Trace(lifecycle_observers_);
306 }
307
308 template <typename Function>
ForAllChildViewsAndPlugins(const Function & function)309 void LocalFrameView::ForAllChildViewsAndPlugins(const Function& function) {
310 for (Frame* child = frame_->Tree().FirstChild(); child;
311 child = child->Tree().NextSibling()) {
312 if (child->View())
313 function(*child->View());
314 }
315
316 for (const auto& plugin : plugins_) {
317 function(*plugin);
318 }
319
320 if (Document* document = frame_->GetDocument()) {
321 for (PortalContents* portal :
322 DocumentPortals::From(*document).GetPortals()) {
323 if (Frame* frame = portal->GetFrame())
324 function(*frame->View());
325 }
326 }
327 }
328
329 template <typename Function>
ForAllChildLocalFrameViews(const Function & function)330 void LocalFrameView::ForAllChildLocalFrameViews(const Function& function) {
331 for (Frame* child = frame_->Tree().FirstChild(); child;
332 child = child->Tree().NextSibling()) {
333 auto* child_local_frame = DynamicTo<LocalFrame>(child);
334 if (!child_local_frame)
335 continue;
336 if (LocalFrameView* child_view = child_local_frame->View())
337 function(*child_view);
338 }
339 }
340
341 // Call function for each non-throttled frame view in pre-order. If this logic
342 // is updated, consider updating |ForAllThrottledLocalFrameViews| too.
343 template <typename Function>
ForAllNonThrottledLocalFrameViews(const Function & function)344 void LocalFrameView::ForAllNonThrottledLocalFrameViews(
345 const Function& function) {
346 if (ShouldThrottleRendering())
347 return;
348
349 function(*this);
350
351 for (Frame* child = frame_->Tree().FirstChild(); child;
352 child = child->Tree().NextSibling()) {
353 auto* child_local_frame = DynamicTo<LocalFrame>(child);
354 if (!child_local_frame)
355 continue;
356 if (LocalFrameView* child_view = child_local_frame->View())
357 child_view->ForAllNonThrottledLocalFrameViews(function);
358 }
359 }
360
361 // Call function for each throttled frame view in pre-order. If this logic is
362 // updated, consider updating |ForAllNonThrottledLocalFrameViews| too.
363 template <typename Function>
ForAllThrottledLocalFrameViews(const Function & function)364 void LocalFrameView::ForAllThrottledLocalFrameViews(const Function& function) {
365 if (!ShouldThrottleRendering())
366 return;
367
368 function(*this);
369
370 for (Frame* child = frame_->Tree().FirstChild(); child;
371 child = child->Tree().NextSibling()) {
372 auto* child_local_frame = DynamicTo<LocalFrame>(child);
373 if (!child_local_frame)
374 continue;
375 if (LocalFrameView* child_view = child_local_frame->View())
376 child_view->ForAllNonThrottledLocalFrameViews(function);
377 }
378 }
379
380 template <typename Function>
ForAllRemoteFrameViews(const Function & function)381 void LocalFrameView::ForAllRemoteFrameViews(const Function& function) {
382 for (Frame* child = frame_->Tree().FirstChild(); child;
383 child = child->Tree().NextSibling()) {
384 if (child->IsLocalFrame()) {
385 To<LocalFrame>(child)->View()->ForAllRemoteFrameViews(function);
386 } else {
387 DCHECK(child->IsRemoteFrame());
388 if (RemoteFrameView* view = To<RemoteFrame>(child)->View())
389 function(*view);
390 }
391 }
392 if (Document* document = frame_->GetDocument()) {
393 for (PortalContents* portal :
394 DocumentPortals::From(*document).GetPortals()) {
395 if (RemoteFrame* frame = portal->GetFrame()) {
396 if (RemoteFrameView* view = frame->View())
397 function(*view);
398 }
399 }
400 }
401 }
402
Dispose()403 void LocalFrameView::Dispose() {
404 CHECK(!IsInPerformLayout());
405
406 // TODO(dcheng): It's wrong that the frame can be detached before the
407 // LocalFrameView. Figure out what's going on and fix LocalFrameView to be
408 // disposed with the correct timing.
409
410 // We need to clear the RootFrameViewport's animator since it gets called
411 // from non-GC'd objects and RootFrameViewport will still have a pointer to
412 // this class.
413 if (viewport_scrollable_area_)
414 viewport_scrollable_area_->ClearScrollableArea();
415
416 // Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing
417 // partially destroyed |this| via |m_autoSizeInfo->m_frameView|.
418 auto_size_info_.Clear();
419
420 // FIXME: Do we need to do something here for OOPI?
421 HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner();
422 // TODO(dcheng): It seems buggy that we can have an owner element that points
423 // to another EmbeddedContentView. This can happen when a plugin element loads
424 // a frame (EmbeddedContentView A of type LocalFrameView) and then loads a
425 // plugin (EmbeddedContentView B of type WebPluginContainerImpl). In this
426 // case, the frame's view is A and the frame element's
427 // OwnedEmbeddedContentView is B. See https://crbug.com/673170 for an example.
428 if (owner_element && owner_element->OwnedEmbeddedContentView() == this)
429 owner_element->SetEmbeddedContentView(nullptr);
430
431 ukm_aggregator_.reset();
432 layout_shift_tracker_->Dispose();
433
434 #if DCHECK_IS_ON()
435 has_been_disposed_ = true;
436 #endif
437 }
438
InvalidateAllCustomScrollbarsOnActiveChanged()439 void LocalFrameView::InvalidateAllCustomScrollbarsOnActiveChanged() {
440 bool uses_window_inactive_selector =
441 frame_->GetDocument()->GetStyleEngine().UsesWindowInactiveSelector();
442
443 ForAllChildLocalFrameViews([](LocalFrameView& frame_view) {
444 frame_view.InvalidateAllCustomScrollbarsOnActiveChanged();
445 });
446
447 for (const auto& scrollbar : scrollbars_) {
448 if (uses_window_inactive_selector && scrollbar->IsCustomScrollbar())
449 scrollbar->StyleChanged();
450 }
451 }
452
DidFirstLayout() const453 bool LocalFrameView::DidFirstLayout() const {
454 return !first_layout_;
455 }
456
LifecycleUpdatesActive() const457 bool LocalFrameView::LifecycleUpdatesActive() const {
458 return !lifecycle_updates_throttled_;
459 }
460
SetLifecycleUpdatesThrottledForTesting()461 void LocalFrameView::SetLifecycleUpdatesThrottledForTesting() {
462 lifecycle_updates_throttled_ = true;
463 }
464
InvalidateRect(const IntRect & rect)465 void LocalFrameView::InvalidateRect(const IntRect& rect) {
466 auto* layout_object = GetLayoutEmbeddedContent();
467 if (!layout_object)
468 return;
469
470 IntRect paint_invalidation_rect = rect;
471 paint_invalidation_rect.Move(
472 (layout_object->BorderLeft() + layout_object->PaddingLeft()).ToInt(),
473 (layout_object->BorderTop() + layout_object->PaddingTop()).ToInt());
474 layout_object->InvalidatePaintRectangle(
475 PhysicalRect(paint_invalidation_rect));
476 }
477
FrameRectsChanged(const IntRect & old_rect)478 void LocalFrameView::FrameRectsChanged(const IntRect& old_rect) {
479 const bool width_changed = Size().Width() != old_rect.Width();
480 const bool height_changed = Size().Height() != old_rect.Height();
481
482 PropagateFrameRects();
483
484 if (FrameRect() != old_rect) {
485 if (auto* layout_view = GetLayoutView())
486 layout_view->SetShouldCheckForPaintInvalidation();
487 }
488
489 if (width_changed || height_changed) {
490 ViewportSizeChanged(width_changed, height_changed);
491 if (frame_->IsMainFrame())
492 frame_->GetPage()->GetVisualViewport().MainFrameDidChangeSize();
493 GetFrame().Loader().RestoreScrollPositionAndViewState();
494 }
495 }
496
GetPage() const497 Page* LocalFrameView::GetPage() const {
498 return GetFrame().GetPage();
499 }
500
GetLayoutView() const501 LayoutView* LocalFrameView::GetLayoutView() const {
502 return GetFrame().ContentLayoutObject();
503 }
504
GetScrollingCoordinator() const505 ScrollingCoordinator* LocalFrameView::GetScrollingCoordinator() const {
506 Page* p = GetPage();
507 return p ? p->GetScrollingCoordinator() : nullptr;
508 }
509
GetScrollingContext() const510 ScrollingCoordinatorContext* LocalFrameView::GetScrollingContext() const {
511 LocalFrame* root = &GetFrame().LocalFrameRoot();
512 if (GetFrame() != root)
513 return root->View()->GetScrollingContext();
514
515 if (!scrolling_context_)
516 scrolling_context_.reset(new ScrollingCoordinatorContext());
517 return scrolling_context_.get();
518 }
519
GetCompositorAnimationHost() const520 cc::AnimationHost* LocalFrameView::GetCompositorAnimationHost() const {
521 if (GetScrollingContext()->GetCompositorAnimationHost())
522 return GetScrollingContext()->GetCompositorAnimationHost();
523
524 if (!GetFrame().LocalFrameRoot().IsMainFrame())
525 return nullptr;
526
527 // TODO(kenrb): Compositor animation host and timeline for the main frame
528 // still live on ScrollingCoordinator. https://crbug.com/680606.
529 ScrollingCoordinator* c = GetScrollingCoordinator();
530 return c ? c->GetCompositorAnimationHost() : nullptr;
531 }
532
GetCompositorAnimationTimeline() const533 CompositorAnimationTimeline* LocalFrameView::GetCompositorAnimationTimeline()
534 const {
535 if (GetScrollingContext()->GetCompositorAnimationTimeline())
536 return GetScrollingContext()->GetCompositorAnimationTimeline();
537
538 if (!GetFrame().LocalFrameRoot().IsMainFrame())
539 return nullptr;
540
541 // TODO(kenrb): Compositor animation host and timeline for the main frame
542 // still live on ScrollingCoordinator. https://crbug.com/680606.
543 ScrollingCoordinator* c = GetScrollingCoordinator();
544 return c ? c->GetCompositorAnimationTimeline() : nullptr;
545 }
546
SetLayoutOverflowSize(const IntSize & size)547 void LocalFrameView::SetLayoutOverflowSize(const IntSize& size) {
548 if (size == layout_overflow_size_)
549 return;
550
551 layout_overflow_size_ = size;
552
553 Page* page = GetFrame().GetPage();
554 if (!page)
555 return;
556 page->GetChromeClient().ContentsSizeChanged(frame_.Get(), size);
557 }
558
AdjustViewSize()559 void LocalFrameView::AdjustViewSize() {
560 if (suppress_adjust_view_size_)
561 return;
562
563 LayoutView* layout_view = GetLayoutView();
564 if (!layout_view)
565 return;
566
567 DCHECK_EQ(frame_->View(), this);
568 SetLayoutOverflowSize(
569 PixelSnappedIntRect(layout_view->DocumentRect()).Size());
570 }
571
AdjustViewSizeAndLayout()572 void LocalFrameView::AdjustViewSizeAndLayout() {
573 AdjustViewSize();
574 if (NeedsLayout()) {
575 base::AutoReset<bool> suppress_adjust_view_size(&suppress_adjust_view_size_,
576 true);
577 UpdateLayout();
578 }
579 }
580
UpdateCountersAfterStyleChange()581 void LocalFrameView::UpdateCountersAfterStyleChange() {
582 auto* layout_view = GetLayoutView();
583 DCHECK(layout_view);
584 layout_view->UpdateCounters();
585 }
586
CountObjectsNeedingLayout(unsigned & needs_layout_objects,unsigned & total_objects,bool & is_subtree)587 void LocalFrameView::CountObjectsNeedingLayout(unsigned& needs_layout_objects,
588 unsigned& total_objects,
589 bool& is_subtree) {
590 needs_layout_objects = 0;
591 total_objects = 0;
592 is_subtree = IsSubtreeLayout();
593 if (is_subtree) {
594 layout_subtree_root_list_.CountObjectsNeedingLayout(needs_layout_objects,
595 total_objects);
596 } else {
597 LayoutSubtreeRootList::CountObjectsNeedingLayoutInRoot(
598 GetLayoutView(), needs_layout_objects, total_objects);
599 }
600 }
601
PerformPreLayoutTasks()602 void LocalFrameView::PerformPreLayoutTasks() {
603 TRACE_EVENT0("blink,benchmark", "LocalFrameView::performPreLayoutTasks");
604 Lifecycle().AdvanceTo(DocumentLifecycle::kInPreLayout);
605
606 // Don't schedule more layouts, we're in one.
607 base::AutoReset<bool> change_scheduling_enabled(&layout_scheduling_enabled_,
608 false);
609
610 bool was_resized = WasViewportResized();
611 Document* document = frame_->GetDocument();
612 if (was_resized)
613 document->SetResizedForViewportUnits();
614
615 // Viewport-dependent or device-dependent media queries may cause us to need
616 // completely different style information.
617 bool main_frame_rotation =
618 frame_->IsMainFrame() && frame_->GetSettings() &&
619 frame_->GetSettings()->GetMainFrameResizesAreOrientationChanges();
620 if ((was_resized &&
621 document->GetStyleEngine().MediaQueryAffectedByViewportChange()) ||
622 (was_resized && main_frame_rotation &&
623 document->GetStyleEngine().MediaQueryAffectedByDeviceChange())) {
624 document->MediaQueryAffectingValueChanged(MediaValueChange::kSize);
625 } else if (was_resized) {
626 document->EvaluateMediaQueryList();
627 }
628
629 document->UpdateStyleAndLayoutTree();
630
631 // Update style for all embedded SVG documents underneath this frame, so
632 // that intrinsic size computation for any embedded objects has up-to-date
633 // information before layout.
634 ForAllChildLocalFrameViews([](LocalFrameView& view) {
635 Document& document = *view.GetFrame().GetDocument();
636 if (document.IsSVGDocument())
637 document.UpdateStyleAndLayoutTree();
638 });
639
640 Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
641
642 if (was_resized)
643 document->ClearResizedForViewportUnits();
644 }
645
LayoutFromRootObject(LayoutObject & root)646 void LocalFrameView::LayoutFromRootObject(LayoutObject& root) {
647 LayoutState layout_state(root);
648 if (scrollable_areas_) {
649 for (auto& scrollable_area : *scrollable_areas_) {
650 if (scrollable_area->GetScrollAnchor() &&
651 scrollable_area->ShouldPerformScrollAnchoring())
652 scrollable_area->GetScrollAnchor()->NotifyBeforeLayout();
653 }
654 }
655
656 root.UpdateLayout();
657 }
658
PrepareLayoutAnalyzer()659 void LocalFrameView::PrepareLayoutAnalyzer() {
660 bool is_tracing = false;
661 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
662 TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &is_tracing);
663 if (!is_tracing) {
664 analyzer_.reset();
665 return;
666 }
667 if (!analyzer_)
668 analyzer_ = std::make_unique<LayoutAnalyzer>();
669 analyzer_->Reset();
670 }
671
AnalyzerCounters()672 std::unique_ptr<TracedValue> LocalFrameView::AnalyzerCounters() {
673 if (!analyzer_)
674 return std::make_unique<TracedValue>();
675 std::unique_ptr<TracedValue> value = analyzer_->ToTracedValue();
676 value->SetString("host", GetLayoutView()->GetDocument().location()->host());
677 value->SetString(
678 "frame",
679 String::Format("0x%" PRIxPTR, reinterpret_cast<uintptr_t>(frame_.Get())));
680 value->SetInteger(
681 "contentsHeightAfterLayout",
682 PixelSnappedIntRect(GetLayoutView()->DocumentRect()).Height());
683 value->SetInteger("visibleHeight", Height());
684 value->SetInteger("approximateBlankCharacterCount",
685 base::saturated_cast<int>(
686 FontFaceSetDocument::ApproximateBlankCharacterCount(
687 *frame_->GetDocument())));
688 return value;
689 }
690
691 #define PERFORM_LAYOUT_TRACE_CATEGORIES \
692 "blink,benchmark,rail," TRACE_DISABLED_BY_DEFAULT("blink.debug.layout")
693
PerformLayout(bool in_subtree_layout)694 void LocalFrameView::PerformLayout(bool in_subtree_layout) {
695 DCHECK(in_subtree_layout || layout_subtree_root_list_.IsEmpty());
696
697 double contents_height_before_layout =
698 GetLayoutView()->DocumentRect().Height();
699 TRACE_EVENT_BEGIN1(
700 PERFORM_LAYOUT_TRACE_CATEGORIES, "LocalFrameView::performLayout",
701 "contentsHeightBeforeLayout", contents_height_before_layout);
702 PrepareLayoutAnalyzer();
703
704 ScriptForbiddenScope forbid_script;
705
706 if (in_subtree_layout && HasOrthogonalWritingModeRoots()) {
707 // If we're going to lay out from each subtree root, rather than once from
708 // LayoutView, we need to merge the depth-ordered orthogonal writing mode
709 // root list into the depth-ordered list of subtrees scheduled for
710 // layout. Otherwise, during layout of one such subtree, we'd risk skipping
711 // over a subtree of objects needing layout.
712 DCHECK(!layout_subtree_root_list_.IsEmpty());
713 ScheduleOrthogonalWritingModeRootsForLayout();
714 }
715
716 DCHECK(!IsInPerformLayout());
717 Lifecycle().AdvanceTo(DocumentLifecycle::kInPerformLayout);
718
719 // performLayout is the actual guts of layout().
720 // FIXME: The 300 other lines in layout() probably belong in other helper
721 // functions so that a single human could understand what layout() is actually
722 // doing.
723
724 {
725 // TODO(szager): Remove this after diagnosing crash.
726 DocumentLifecycle::CheckNoTransitionScope check_no_transition(Lifecycle());
727 if (in_subtree_layout) {
728 if (analyzer_) {
729 analyzer_->Increment(LayoutAnalyzer::kPerformLayoutRootLayoutObjects,
730 layout_subtree_root_list_.size());
731 }
732 for (auto& root : layout_subtree_root_list_.Ordered()) {
733 if (!root->NeedsLayout())
734 continue;
735 LayoutFromRootObject(*root);
736
737 root->PaintingLayer()->UpdateLayerPositionsAfterLayout();
738
739 // We need to ensure that we mark up all layoutObjects up to the
740 // LayoutView for paint invalidation. This simplifies our code as we
741 // just always do a full tree walk.
742 if (LayoutObject* container = root->Container())
743 container->SetShouldCheckForPaintInvalidation();
744 }
745 layout_subtree_root_list_.Clear();
746 } else {
747 if (HasOrthogonalWritingModeRoots())
748 LayoutOrthogonalWritingModeRoots();
749 GetLayoutView()->UpdateLayout();
750 }
751 }
752
753 frame_->GetDocument()->Fetcher()->UpdateAllImageResourcePriorities();
754
755 Lifecycle().AdvanceTo(DocumentLifecycle::kAfterPerformLayout);
756
757 TRACE_EVENT_END1(PERFORM_LAYOUT_TRACE_CATEGORIES,
758 "LocalFrameView::performLayout", "counters",
759 AnalyzerCounters());
760 FirstMeaningfulPaintDetector::From(*frame_->GetDocument())
761 .MarkNextPaintAsMeaningfulIfNeeded(
762 layout_object_counter_, contents_height_before_layout,
763 GetLayoutView()->DocumentRect().Height(), Height());
764 }
765
UpdateLayout()766 void LocalFrameView::UpdateLayout() {
767 // We should never layout a Document which is not in a LocalFrame.
768 DCHECK(frame_);
769 DCHECK_EQ(frame_->View(), this);
770 DCHECK(frame_->GetPage());
771
772 ScriptForbiddenScope forbid_script;
773
774 if (IsInPerformLayout() || ShouldThrottleRendering() ||
775 !frame_->GetDocument()->IsActive() || frame_->IsProvisional())
776 return;
777
778 TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout");
779
780 RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(),
781 RuntimeCallStats::CounterId::kUpdateLayout);
782
783 // The actual call to UpdateGeometries is in PerformPostLayoutTasks.
784 SetNeedsUpdateGeometries();
785
786 if (auto_size_info_)
787 auto_size_info_->AutoSizeIfNeeded();
788
789 has_pending_layout_ = false;
790
791 Document* document = frame_->GetDocument();
792 TRACE_EVENT_BEGIN1("devtools.timeline", "Layout", "beginData",
793 inspector_layout_event::BeginData(this));
794 probe::UpdateLayout probe(document);
795
796 PerformPreLayoutTasks();
797
798 VisualViewport& visual_viewport = frame_->GetPage()->GetVisualViewport();
799 DoubleSize viewport_size(visual_viewport.VisibleWidthCSSPx(),
800 visual_viewport.VisibleHeightCSSPx());
801
802 // TODO(crbug.com/460956): The notion of a single root for layout is no
803 // longer applicable. Remove or update this code.
804 LayoutObject* root_for_this_layout = GetLayoutView();
805
806 FontCachePurgePreventer font_cache_purge_preventer;
807 StyleRetainScope style_retain_scope;
808 bool in_subtree_layout = false;
809 {
810 base::AutoReset<bool> change_scheduling_enabled(&layout_scheduling_enabled_,
811 false);
812 nested_layout_count_++;
813
814 // If the layout view was marked as needing layout after we added items in
815 // the subtree roots we need to clear the roots and do the layout from the
816 // layoutView.
817 if (GetLayoutView()->NeedsLayout())
818 ClearLayoutSubtreeRootsAndMarkContainingBlocks();
819 GetLayoutView()->ClearHitTestCache();
820
821 in_subtree_layout = IsSubtreeLayout();
822
823 // TODO(crbug.com/460956): The notion of a single root for layout is no
824 // longer applicable. Remove or update this code.
825 if (in_subtree_layout)
826 root_for_this_layout = layout_subtree_root_list_.RandomRoot();
827
828 if (!root_for_this_layout) {
829 // FIXME: Do we need to set m_size here?
830 NOTREACHED();
831 return;
832 }
833
834 if (!in_subtree_layout) {
835 ClearLayoutSubtreeRootsAndMarkContainingBlocks();
836 Node* body = document->body();
837 if (body && body->GetLayoutObject()) {
838 if (IsA<HTMLFrameSetElement>(*body)) {
839 body->GetLayoutObject()->SetChildNeedsLayout();
840 } else if (IsA<HTMLBodyElement>(*body)) {
841 if (!first_layout_ && size_.Height() != GetLayoutSize().Height() &&
842 body->GetLayoutObject()->EnclosingBox()->StretchesToViewport())
843 body->GetLayoutObject()->SetChildNeedsLayout();
844 }
845 }
846
847 if (first_layout_) {
848 first_layout_ = false;
849 last_viewport_size_ = GetLayoutSize();
850 last_zoom_factor_ = GetLayoutView()->StyleRef().Zoom();
851
852 mojom::blink::ScrollbarMode h_mode;
853 mojom::blink::ScrollbarMode v_mode;
854 GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
855 if (v_mode == mojom::blink::ScrollbarMode::kAuto) {
856 GetLayoutView()
857 ->GetScrollableArea()
858 ->ForceVerticalScrollbarForFirstLayout();
859 }
860 }
861
862 LayoutSize old_size = size_;
863
864 size_ = LayoutSize(GetLayoutSize());
865
866 if (old_size != size_ && !first_layout_) {
867 LayoutBox* root_layout_object =
868 document->documentElement()
869 ? document->documentElement()->GetLayoutBox()
870 : nullptr;
871 LayoutBox* body_layout_object = root_layout_object && document->body()
872 ? document->body()->GetLayoutBox()
873 : nullptr;
874 if (body_layout_object && body_layout_object->StretchesToViewport())
875 body_layout_object->SetChildNeedsLayout();
876 else if (root_layout_object &&
877 root_layout_object->StretchesToViewport())
878 root_layout_object->SetChildNeedsLayout();
879 }
880 }
881
882 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
883 TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree",
884 this, TracedLayoutObject::Create(*GetLayoutView(), false));
885
886 IntSize old_size(Size());
887
888 PerformLayout(in_subtree_layout);
889
890 IntSize new_size(Size());
891 if (old_size != new_size) {
892 MarkViewportConstrainedObjectsForLayout(
893 old_size.Width() != new_size.Width(),
894 old_size.Height() != new_size.Height());
895 }
896
897 if (frame_->IsMainFrame()) {
898 if (auto* text_autosizer = frame_->GetDocument()->GetTextAutosizer()) {
899 if (text_autosizer->HasLayoutInlineSizeChanged())
900 text_autosizer->UpdatePageInfoInAllFrames(frame_);
901 }
902 }
903
904 if (NeedsLayout()) {
905 base::AutoReset<bool> suppress(&suppress_adjust_view_size_, true);
906 UpdateLayout();
907 }
908
909 DCHECK(layout_subtree_root_list_.IsEmpty());
910 } // Reset m_layoutSchedulingEnabled to its previous value.
911 CheckDoesNotNeedLayout();
912
913 DocumentLifecycle::Scope lifecycle_scope(Lifecycle(),
914 DocumentLifecycle::kLayoutClean);
915
916 frame_timing_requests_dirty_ = true;
917
918 if (!in_subtree_layout)
919 GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
920
921 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
922 TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", this,
923 TracedLayoutObject::Create(*GetLayoutView(), true));
924
925 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
926 GetLayoutView()->Compositor()->DidLayout();
927 layout_count_for_testing_++;
928
929 if (AXObjectCache* cache = document->ExistingAXObjectCache()) {
930 const KURL& url = document->Url();
931 if (url.IsValid() && !url.IsAboutBlankURL()) {
932 // TODO(kschmi) move HandleLayoutComplete to the accessibility lifecycle
933 // stage. crbug.com/1062122
934 cache->HandleLayoutComplete(document);
935 }
936 }
937
938 UpdateDocumentAnnotatedRegions();
939 CheckDoesNotNeedLayout();
940
941 if (nested_layout_count_ == 1) {
942 PerformPostLayoutTasks();
943 CheckDoesNotNeedLayout();
944 }
945
946 // FIXME: The notion of a single root for layout is no longer applicable.
947 // Remove or update this code. crbug.com/460596
948 TRACE_EVENT_END1("devtools.timeline", "Layout", "endData",
949 inspector_layout_event::EndData(root_for_this_layout));
950 probe::DidChangeViewport(frame_.Get());
951
952 nested_layout_count_--;
953 if (nested_layout_count_)
954 return;
955
956 #if DCHECK_IS_ON()
957 // Post-layout assert that nobody was re-marked as needing layout during
958 // layout.
959 GetLayoutView()->AssertSubtreeIsLaidOut();
960 #endif
961
962 if (frame_->IsMainFrame()) {
963 // Scrollbars changing state can cause a visual viewport size change.
964 DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(),
965 visual_viewport.VisibleHeightCSSPx());
966 if (new_viewport_size != viewport_size)
967 frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
968 }
969
970 GetFrame().GetDocument()->LayoutUpdated();
971 CheckDoesNotNeedLayout();
972 }
973
WillStartForcedLayout()974 void LocalFrameView::WillStartForcedLayout() {
975 // UpdateLayout is re-entrant for auto-sizing and plugins. So keep
976 // track of stack depth to include all the time in the top-level call.
977 forced_layout_stack_depth_++;
978 if (forced_layout_stack_depth_ > 1)
979 return;
980 forced_layout_start_time_ = base::TimeTicks::Now();
981 }
982
DidFinishForcedLayout(DocumentUpdateReason reason)983 void LocalFrameView::DidFinishForcedLayout(DocumentUpdateReason reason) {
984 CHECK_GT(forced_layout_stack_depth_, (unsigned)0);
985 forced_layout_stack_depth_--;
986 if (!forced_layout_stack_depth_ && base::TimeTicks::IsHighResolution()) {
987 LocalFrameUkmAggregator& aggregator = EnsureUkmAggregator();
988 aggregator.RecordSample(
989 static_cast<size_t>(LocalFrameUkmAggregator::kForcedStyleAndLayout),
990 forced_layout_start_time_, base::TimeTicks::Now());
991 if (reason == DocumentUpdateReason::kHitTest) {
992 aggregator.RecordSample(
993 static_cast<size_t>(LocalFrameUkmAggregator::kHitTestDocumentUpdate),
994 forced_layout_start_time_, base::TimeTicks::Now());
995 }
996 }
997 }
998
SetNeedsPaintPropertyUpdate()999 void LocalFrameView::SetNeedsPaintPropertyUpdate() {
1000 if (auto* layout_view = GetLayoutView())
1001 layout_view->SetNeedsPaintPropertyUpdate();
1002 }
1003
ViewportSizeForViewportUnits() const1004 FloatSize LocalFrameView::ViewportSizeForViewportUnits() const {
1005 float zoom = 1;
1006 if (!frame_->GetDocument() || !frame_->GetDocument()->Printing())
1007 zoom = GetFrame().PageZoomFactor();
1008
1009 auto* layout_view = GetLayoutView();
1010 if (!layout_view)
1011 return FloatSize();
1012
1013 FloatSize layout_size;
1014 layout_size.SetWidth(layout_view->ViewWidth(kIncludeScrollbars) / zoom);
1015 layout_size.SetHeight(layout_view->ViewHeight(kIncludeScrollbars) / zoom);
1016
1017 BrowserControls& browser_controls = frame_->GetPage()->GetBrowserControls();
1018 if (browser_controls.PermittedState() != cc::BrowserControlsState::kHidden) {
1019 // We use the layoutSize rather than frameRect to calculate viewport units
1020 // so that we get correct results on mobile where the page is laid out into
1021 // a rect that may be larger than the viewport (e.g. the 980px fallback
1022 // width for desktop pages). Since the layout height is statically set to
1023 // be the viewport with browser controls showing, we add the browser
1024 // controls height, compensating for page scale as well, since we want to
1025 // use the viewport with browser controls hidden for vh (to match Safari).
1026 int viewport_width = frame_->GetPage()->GetVisualViewport().Size().Width();
1027 if (frame_->IsMainFrame() && layout_size.Width() && viewport_width) {
1028 // TODO(bokan/eirage): BrowserControl height may need to account for the
1029 // zoom factor when use-zoom-for-dsf is enabled on Android. Confirm this
1030 // works correctly when that's turned on. https://crbug.com/737777.
1031 float page_scale_at_layout_width = viewport_width / layout_size.Width();
1032 layout_size.Expand(0, (browser_controls.TotalHeight() -
1033 browser_controls.TotalMinHeight()) /
1034 page_scale_at_layout_width);
1035 }
1036 }
1037
1038 return layout_size;
1039 }
1040
ViewportSizeForMediaQueries() const1041 FloatSize LocalFrameView::ViewportSizeForMediaQueries() const {
1042 FloatSize viewport_size(layout_size_);
1043 if (!frame_->GetDocument()->Printing()) {
1044 float zoom = GetFrame().PageZoomFactor();
1045 viewport_size.SetWidth(
1046 AdjustForAbsoluteZoom::AdjustInt(layout_size_.Width(), zoom));
1047 viewport_size.SetHeight(
1048 AdjustForAbsoluteZoom::AdjustInt(layout_size_.Height(), zoom));
1049 }
1050 return viewport_size;
1051 }
1052
Lifecycle() const1053 DocumentLifecycle& LocalFrameView::Lifecycle() const {
1054 DCHECK(frame_);
1055 DCHECK(frame_->GetDocument());
1056 return frame_->GetDocument()->Lifecycle();
1057 }
1058
RunPostLifecycleSteps()1059 void LocalFrameView::RunPostLifecycleSteps() {
1060 RunIntersectionObserverSteps();
1061 }
1062
RunIntersectionObserverSteps()1063 void LocalFrameView::RunIntersectionObserverSteps() {
1064 #if DCHECK_IS_ON()
1065 bool was_dirty = NeedsLayout();
1066 #endif
1067 if (ShouldThrottleRendering() || Lifecycle().LifecyclePostponed() ||
1068 !frame_->GetDocument()->IsActive()) {
1069 return;
1070 }
1071
1072 if (frame_->IsMainFrame()) {
1073 EnsureOverlayInterstitialAdDetector().MaybeFireDetection(frame_.Get());
1074
1075 // Report the main frame's document intersection with itself.
1076 LayoutObject* layout_object = GetLayoutView();
1077 IntRect main_frame_dimensions =
1078 ToLayoutBox(layout_object)->PixelSnappedLayoutOverflowRect();
1079 GetFrame().Client()->OnMainFrameDocumentIntersectionChanged(WebRect(
1080 0, 0, main_frame_dimensions.Width(), main_frame_dimensions.Height()));
1081 }
1082
1083 TRACE_EVENT0("blink,benchmark",
1084 "LocalFrameView::UpdateViewportIntersectionsForSubtree");
1085 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
1086 LocalFrameUkmAggregator::kIntersectionObservation);
1087
1088 unsigned flags = 0;
1089 if (frame_->CanSkipStickyFrameTracking())
1090 flags |= IntersectionObservation::kCanSkipStickyFrameTracking;
1091
1092 bool needs_occlusion_tracking = UpdateViewportIntersectionsForSubtree(flags);
1093 if (FrameOwner* owner = frame_->Owner())
1094 owner->SetNeedsOcclusionTracking(needs_occlusion_tracking);
1095 #if DCHECK_IS_ON()
1096 DCHECK(was_dirty || !NeedsLayout());
1097 #endif
1098 DeliverSynchronousIntersectionObservations();
1099 }
1100
ForceUpdateViewportIntersections()1101 void LocalFrameView::ForceUpdateViewportIntersections() {
1102 // IntersectionObserver targets in this frame (and its frame tree) need to
1103 // update; but we can't wait for a lifecycle update to run them, because a
1104 // hidden frame won't run lifecycle updates. Force layout and run them now.
1105 DocumentLifecycle::DisallowThrottlingScope disallow_throttling(Lifecycle());
1106 UpdateLifecycleToCompositingCleanPlusScrolling(
1107 DocumentUpdateReason::kIntersectionObservation);
1108 UpdateViewportIntersectionsForSubtree(
1109 IntersectionObservation::kImplicitRootObserversNeedUpdate |
1110 IntersectionObservation::kIgnoreDelay);
1111 }
1112
EmbeddedReplacedContent() const1113 LayoutSVGRoot* LocalFrameView::EmbeddedReplacedContent() const {
1114 auto* layout_view = this->GetLayoutView();
1115 if (!layout_view)
1116 return nullptr;
1117
1118 LayoutObject* first_child = layout_view->FirstChild();
1119 if (!first_child || !first_child->IsBox())
1120 return nullptr;
1121
1122 // Currently only embedded SVG documents participate in the size-negotiation
1123 // logic.
1124 return ToLayoutSVGRootOrNull(first_child);
1125 }
1126
GetIntrinsicSizingInfo(IntrinsicSizingInfo & intrinsic_sizing_info) const1127 bool LocalFrameView::GetIntrinsicSizingInfo(
1128 IntrinsicSizingInfo& intrinsic_sizing_info) const {
1129 if (LayoutSVGRoot* content_layout_object = EmbeddedReplacedContent()) {
1130 content_layout_object->UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
1131 return true;
1132 }
1133 return false;
1134 }
1135
HasIntrinsicSizingInfo() const1136 bool LocalFrameView::HasIntrinsicSizingInfo() const {
1137 return EmbeddedReplacedContent();
1138 }
1139
UpdateGeometry()1140 void LocalFrameView::UpdateGeometry() {
1141 LayoutEmbeddedContent* layout = GetLayoutEmbeddedContent();
1142 if (!layout)
1143 return;
1144
1145 bool did_need_layout = NeedsLayout();
1146
1147 PhysicalRect new_frame = layout->ReplacedContentRect();
1148 #if DCHECK_IS_ON()
1149 if (new_frame.Width() != LayoutUnit::Max().RawValue() &&
1150 new_frame.Height() != LayoutUnit::Max().RawValue())
1151 DCHECK(!new_frame.size.HasFraction());
1152 #endif
1153 bool bounds_will_change = PhysicalSize(Size()) != new_frame.size;
1154
1155 // If frame bounds are changing mark the view for layout. Also check the
1156 // frame's page to make sure that the frame isn't in the process of being
1157 // destroyed. If iframe scrollbars needs reconstruction from native to custom
1158 // scrollbar, then also we need to layout the frameview.
1159 if (bounds_will_change)
1160 SetNeedsLayout();
1161
1162 layout->UpdateGeometry(*this);
1163 // If view needs layout, either because bounds have changed or possibly
1164 // indicating content size is wrong, we have to do a layout to set the right
1165 // LocalFrameView size.
1166 if (NeedsLayout())
1167 UpdateLayout();
1168
1169 if (!did_need_layout && !ShouldThrottleRendering())
1170 CheckDoesNotNeedLayout();
1171 }
1172
AddPartToUpdate(LayoutEmbeddedObject & object)1173 void LocalFrameView::AddPartToUpdate(LayoutEmbeddedObject& object) {
1174 DCHECK(IsInPerformLayout());
1175 // Tell the DOM element that it needs a Plugin update.
1176 Node* node = object.GetNode();
1177 DCHECK(node);
1178 if (IsA<HTMLObjectElement>(*node) || IsA<HTMLEmbedElement>(*node))
1179 To<HTMLPlugInElement>(node)->SetNeedsPluginUpdate(true);
1180
1181 part_update_set_.insert(&object);
1182 }
1183
SetDisplayMode(blink::mojom::DisplayMode mode)1184 void LocalFrameView::SetDisplayMode(blink::mojom::DisplayMode mode) {
1185 if (mode == display_mode_)
1186 return;
1187
1188 display_mode_ = mode;
1189
1190 if (frame_->GetDocument()) {
1191 frame_->GetDocument()->MediaQueryAffectingValueChanged(
1192 MediaValueChange::kOther);
1193 }
1194 }
1195
SetDisplayShape(DisplayShape display_shape)1196 void LocalFrameView::SetDisplayShape(DisplayShape display_shape) {
1197 if (display_shape == display_shape_)
1198 return;
1199
1200 display_shape_ = display_shape;
1201
1202 if (frame_->GetDocument()) {
1203 frame_->GetDocument()->MediaQueryAffectingValueChanged(
1204 MediaValueChange::kOther);
1205 }
1206 }
1207
SetMediaType(const AtomicString & media_type)1208 void LocalFrameView::SetMediaType(const AtomicString& media_type) {
1209 DCHECK(frame_->GetDocument());
1210 media_type_ = media_type;
1211 frame_->GetDocument()->MediaQueryAffectingValueChanged(
1212 MediaValueChange::kOther);
1213 }
1214
MediaType() const1215 AtomicString LocalFrameView::MediaType() const {
1216 // See if we have an override type.
1217 if (frame_->GetSettings() &&
1218 !frame_->GetSettings()->GetMediaTypeOverride().IsEmpty())
1219 return AtomicString(frame_->GetSettings()->GetMediaTypeOverride());
1220 return media_type_;
1221 }
1222
AdjustMediaTypeForPrinting(bool printing)1223 void LocalFrameView::AdjustMediaTypeForPrinting(bool printing) {
1224 if (printing) {
1225 if (media_type_when_not_printing_.IsNull())
1226 media_type_when_not_printing_ = MediaType();
1227 SetMediaType(media_type_names::kPrint);
1228 } else {
1229 if (!media_type_when_not_printing_.IsNull())
1230 SetMediaType(media_type_when_not_printing_);
1231 media_type_when_not_printing_ = g_null_atom;
1232 }
1233
1234 frame_->GetDocument()->GetStyleEngine().MarkViewportStyleDirty();
1235 frame_->GetDocument()->GetStyleEngine().MarkAllElementsForStyleRecalc(
1236 StyleChangeReasonForTracing::Create(
1237 style_change_reason::kStyleSheetChange));
1238 }
1239
AddBackgroundAttachmentFixedObject(LayoutObject * object)1240 void LocalFrameView::AddBackgroundAttachmentFixedObject(LayoutObject* object) {
1241 DCHECK(!background_attachment_fixed_objects_.Contains(object));
1242
1243 background_attachment_fixed_objects_.insert(object);
1244
1245 // Ensure main thread scrolling reasons are recomputed.
1246 SetNeedsPaintPropertyUpdate();
1247 // The object's scroll properties are not affected by its own background.
1248 object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
1249 }
1250
RemoveBackgroundAttachmentFixedObject(LayoutObject * object)1251 void LocalFrameView::RemoveBackgroundAttachmentFixedObject(
1252 LayoutObject* object) {
1253 DCHECK(background_attachment_fixed_objects_.Contains(object));
1254
1255 background_attachment_fixed_objects_.erase(object);
1256
1257 // Ensure main thread scrolling reasons are recomputed.
1258 SetNeedsPaintPropertyUpdate();
1259 // The object's scroll properties are not affected by its own background.
1260 object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
1261 }
1262
RequiresMainThreadScrollingForBackgroundAttachmentFixed() const1263 bool LocalFrameView::RequiresMainThreadScrollingForBackgroundAttachmentFixed()
1264 const {
1265 if (background_attachment_fixed_objects_.IsEmpty())
1266 return false;
1267 if (background_attachment_fixed_objects_.size() > 1)
1268 return true;
1269
1270 const auto* object =
1271 ToLayoutBoxModelObject(*background_attachment_fixed_objects_.begin());
1272 // We should not add such object in the set.
1273 DCHECK(!object->BackgroundTransfersToView());
1274 // If the background is viewport background and it paints onto the main
1275 // graphics layer only, then it doesn't need main thread scrolling.
1276 if (IsA<LayoutView>(object) &&
1277 object->GetBackgroundPaintLocation() == kBackgroundPaintInGraphicsLayer)
1278 return false;
1279 return true;
1280 }
1281
AddViewportConstrainedObject(LayoutObject & object)1282 void LocalFrameView::AddViewportConstrainedObject(LayoutObject& object) {
1283 if (!viewport_constrained_objects_)
1284 viewport_constrained_objects_ = std::make_unique<ObjectSet>();
1285
1286 viewport_constrained_objects_->insert(&object);
1287 }
1288
RemoveViewportConstrainedObject(LayoutObject & object)1289 void LocalFrameView::RemoveViewportConstrainedObject(LayoutObject& object) {
1290 if (viewport_constrained_objects_)
1291 viewport_constrained_objects_->erase(&object);
1292 }
1293
ViewportSizeChanged(bool width_changed,bool height_changed)1294 void LocalFrameView::ViewportSizeChanged(bool width_changed,
1295 bool height_changed) {
1296 DCHECK(width_changed || height_changed);
1297 DCHECK(frame_->GetPage());
1298 if (frame_->GetDocument() &&
1299 frame_->GetDocument()->Lifecycle().LifecyclePostponed())
1300 return;
1301
1302 if (frame_->IsMainFrame())
1303 layout_shift_tracker_->NotifyViewportSizeChanged();
1304
1305 auto* layout_view = GetLayoutView();
1306 if (layout_view) {
1307 // If this is the main frame, we might have got here by hiding/showing the
1308 // top controls. In that case, layout won't be triggered, so we need to
1309 // clamp the scroll offset here.
1310 if (GetFrame().IsMainFrame()) {
1311 layout_view->Layer()->UpdateSize();
1312 layout_view->GetScrollableArea()->ClampScrollOffsetAfterOverflowChange();
1313 }
1314
1315 // TODO(pdr): |UsesCompositing()| will be false with CompositeAfterPaint but
1316 // do we need to do these updates?
1317 if (layout_view->UsesCompositing()) {
1318 layout_view->Layer()->SetNeedsCompositingInputsUpdate();
1319 SetNeedsPaintPropertyUpdate();
1320 }
1321 }
1322
1323 if (GetFrame().GetDocument())
1324 GetFrame().GetDocument()->GetRootScrollerController().DidResizeFrameView();
1325
1326 // Change of viewport size after browser controls showing/hiding may affect
1327 // painting of the background.
1328 if (layout_view && frame_->IsMainFrame() &&
1329 frame_->GetPage()->GetBrowserControls().TotalHeight())
1330 layout_view->SetShouldCheckForPaintInvalidation();
1331
1332 if (GetFrame().GetDocument() && !IsInPerformLayout())
1333 MarkViewportConstrainedObjectsForLayout(width_changed, height_changed);
1334
1335 if (GetPaintTimingDetector().Visualizer())
1336 GetPaintTimingDetector().Visualizer()->OnViewportChanged();
1337 }
1338
MarkViewportConstrainedObjectsForLayout(bool width_changed,bool height_changed)1339 void LocalFrameView::MarkViewportConstrainedObjectsForLayout(
1340 bool width_changed,
1341 bool height_changed) {
1342 if (!HasViewportConstrainedObjects() || !(width_changed || height_changed))
1343 return;
1344
1345 for (auto* const viewport_constrained_object :
1346 *viewport_constrained_objects_) {
1347 LayoutObject* layout_object = viewport_constrained_object;
1348 const ComputedStyle& style = layout_object->StyleRef();
1349 if (width_changed) {
1350 if (style.Width().IsFixed() &&
1351 (style.Left().IsAuto() || style.Right().IsAuto())) {
1352 layout_object->SetNeedsPositionedMovementLayout();
1353 } else {
1354 layout_object->SetNeedsLayoutAndFullPaintInvalidation(
1355 layout_invalidation_reason::kSizeChanged);
1356 }
1357 }
1358 if (height_changed) {
1359 if (style.Height().IsFixed() &&
1360 (style.Top().IsAuto() || style.Bottom().IsAuto())) {
1361 layout_object->SetNeedsPositionedMovementLayout();
1362 } else {
1363 layout_object->SetNeedsLayoutAndFullPaintInvalidation(
1364 layout_invalidation_reason::kSizeChanged);
1365 }
1366 }
1367 }
1368 }
1369
ShouldSetCursor() const1370 bool LocalFrameView::ShouldSetCursor() const {
1371 Page* page = GetFrame().GetPage();
1372 return page && page->IsPageVisible() &&
1373 !frame_->GetEventHandler().IsMousePositionUnknown() &&
1374 page->GetFocusController().IsActive();
1375 }
1376
InvalidateBackgroundAttachmentFixedDescendantsOnScroll(const LayoutObject & scrolled_object)1377 void LocalFrameView::InvalidateBackgroundAttachmentFixedDescendantsOnScroll(
1378 const LayoutObject& scrolled_object) {
1379 for (auto* const layout_object : background_attachment_fixed_objects_) {
1380 if (scrolled_object != GetLayoutView() &&
1381 !layout_object->IsDescendantOf(&scrolled_object))
1382 continue;
1383 // An object needs to repaint the background on scroll when it has
1384 // background-attachment:fixed unless the object is the LayoutView and the
1385 // background is not painted on the scrolling contents.
1386 if (layout_object == GetLayoutView() &&
1387 !(GetLayoutView()->GetBackgroundPaintLocation() &
1388 kBackgroundPaintInScrollingContents))
1389 continue;
1390 layout_object->SetBackgroundNeedsFullPaintInvalidation();
1391 }
1392 }
1393
InvalidateViewportConstrainedObjects()1394 bool LocalFrameView::InvalidateViewportConstrainedObjects() {
1395 bool fast_path_allowed = true;
1396 for (auto* const viewport_constrained_object :
1397 *viewport_constrained_objects_) {
1398 LayoutObject* layout_object = viewport_constrained_object;
1399 DCHECK(layout_object->StyleRef().HasViewportConstrainedPosition() ||
1400 layout_object->StyleRef().HasStickyConstrainedPosition());
1401 DCHECK(layout_object->HasLayer());
1402 PaintLayer* layer = ToLayoutBoxModelObject(layout_object)->Layer();
1403
1404 if (layer->IsPaintInvalidationContainer())
1405 continue;
1406
1407 // If the layer has no visible content, then we shouldn't invalidate; but
1408 // if we're not compositing-inputs-clean, then we can't query
1409 // layer->SubtreeIsInvisible() here.
1410 layout_object->SetSubtreeShouldCheckForPaintInvalidation();
1411 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
1412 !layer->SelfOrDescendantNeedsRepaint()) {
1413 // Paint properties of the layer relative to its containing graphics
1414 // layer may change if the paint properties escape the graphics layer's
1415 // property state. Need to check raster invalidation for relative paint
1416 // property changes.
1417 if (auto* paint_invalidation_layer =
1418 layer->EnclosingLayerForPaintInvalidation()) {
1419 auto* mapping = paint_invalidation_layer->GetCompositedLayerMapping();
1420 if (!mapping)
1421 mapping = paint_invalidation_layer->GroupedMapping();
1422 if (mapping)
1423 mapping->SetNeedsCheckRasterInvalidation();
1424 }
1425 }
1426
1427 // If the fixed layer has a blur/drop-shadow filter applied on at least one
1428 // of its parents, we cannot scroll using the fast path, otherwise the
1429 // outsets of the filter will be moved around the page.
1430 if (layer->HasAncestorWithFilterThatMovesPixels())
1431 fast_path_allowed = false;
1432 }
1433 return fast_path_allowed;
1434 }
1435
ProcessUrlFragment(const KURL & url,bool same_document_navigation,bool should_scroll)1436 void LocalFrameView::ProcessUrlFragment(const KURL& url,
1437 bool same_document_navigation,
1438 bool should_scroll) {
1439 // We want to create the anchor even if we don't need to scroll. This ensures
1440 // all the side effects like setting CSS :target are correctly set.
1441 FragmentAnchor* anchor = FragmentAnchor::TryCreate(
1442 url, *frame_, same_document_navigation, should_scroll);
1443
1444 if (anchor) {
1445 fragment_anchor_ = anchor;
1446 fragment_anchor_->Installed();
1447 // Post-load, same-document navigations need to schedule a frame in which
1448 // the fragment anchor will be invoked. It will be done after layout as
1449 // part of the lifecycle.
1450 if (same_document_navigation)
1451 ScheduleAnimation();
1452 }
1453 }
1454
SetLayoutSize(const IntSize & size)1455 void LocalFrameView::SetLayoutSize(const IntSize& size) {
1456 DCHECK(!LayoutSizeFixedToFrameSize());
1457 if (frame_->GetDocument() &&
1458 frame_->GetDocument()->Lifecycle().LifecyclePostponed())
1459 return;
1460
1461 SetLayoutSizeInternal(size);
1462 }
1463
SetLayoutSizeFixedToFrameSize(bool is_fixed)1464 void LocalFrameView::SetLayoutSizeFixedToFrameSize(bool is_fixed) {
1465 if (layout_size_fixed_to_frame_size_ == is_fixed)
1466 return;
1467
1468 layout_size_fixed_to_frame_size_ = is_fixed;
1469 if (is_fixed)
1470 SetLayoutSizeInternal(Size());
1471 }
1472
ComputeLayerSelection(LocalFrame & frame)1473 static cc::LayerSelection ComputeLayerSelection(LocalFrame& frame) {
1474 if (!frame.View() || frame.View()->ShouldThrottleRendering())
1475 return {};
1476
1477 return ComputeLayerSelection(frame.Selection());
1478 }
1479
UpdateCompositedSelectionIfNeeded()1480 void LocalFrameView::UpdateCompositedSelectionIfNeeded() {
1481 if (!RuntimeEnabledFeatures::CompositedSelectionUpdateEnabled())
1482 return;
1483
1484 TRACE_EVENT0("blink", "LocalFrameView::updateCompositedSelectionIfNeeded");
1485
1486 Page* page = GetFrame().GetPage();
1487 DCHECK(page);
1488
1489 LocalFrame* focused_frame = page->GetFocusController().FocusedFrame();
1490 LocalFrame* local_frame =
1491 (focused_frame &&
1492 (focused_frame->LocalFrameRoot() == frame_->LocalFrameRoot()))
1493 ? focused_frame
1494 : nullptr;
1495
1496 if (local_frame) {
1497 const cc::LayerSelection& selection = ComputeLayerSelection(*local_frame);
1498 if (selection != cc::LayerSelection()) {
1499 page->GetChromeClient().UpdateLayerSelection(local_frame, selection);
1500 return;
1501 }
1502 }
1503
1504 if (!local_frame) {
1505 // Clearing the mainframe when there is no focused frame (and hence
1506 // no localFrame) is legacy behaviour, and implemented here to
1507 // satisfy WebFrameTest.CompositedSelectionBoundsCleared's
1508 // first check that the composited selection has been cleared even
1509 // though no frame has focus yet. If this is not desired, then the
1510 // expectation needs to be removed from the test.
1511 local_frame = &frame_->LocalFrameRoot();
1512 }
1513 DCHECK(local_frame);
1514 page->GetChromeClient().ClearLayerSelection(local_frame);
1515 }
1516
SetNeedsCompositingUpdate(CompositingUpdateType update_type)1517 void LocalFrameView::SetNeedsCompositingUpdate(
1518 CompositingUpdateType update_type) {
1519 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1520 return;
1521 if (auto* layout_view = GetLayoutView()) {
1522 if (frame_->GetDocument()->IsActive())
1523 layout_view->Compositor()->SetNeedsCompositingUpdate(update_type);
1524 }
1525 }
1526
GetChromeClient() const1527 ChromeClient* LocalFrameView::GetChromeClient() const {
1528 Page* page = GetFrame().GetPage();
1529 if (!page)
1530 return nullptr;
1531 return &page->GetChromeClient();
1532 }
1533
HandleLoadCompleted()1534 void LocalFrameView::HandleLoadCompleted() {
1535 // Once loading has completed, allow autoSize one last opportunity to
1536 // reduce the size of the frame.
1537 if (auto_size_info_)
1538 auto_size_info_->AutoSizeIfNeeded();
1539 }
1540
ClearLayoutSubtreeRoot(const LayoutObject & root)1541 void LocalFrameView::ClearLayoutSubtreeRoot(const LayoutObject& root) {
1542 layout_subtree_root_list_.Remove(const_cast<LayoutObject&>(root));
1543 }
1544
ClearLayoutSubtreeRootsAndMarkContainingBlocks()1545 void LocalFrameView::ClearLayoutSubtreeRootsAndMarkContainingBlocks() {
1546 layout_subtree_root_list_.ClearAndMarkContainingBlocksForLayout();
1547 }
1548
AddOrthogonalWritingModeRoot(LayoutBox & root)1549 void LocalFrameView::AddOrthogonalWritingModeRoot(LayoutBox& root) {
1550 DCHECK(!root.IsLayoutCustomScrollbarPart());
1551 orthogonal_writing_mode_root_list_.Add(root);
1552 }
1553
RemoveOrthogonalWritingModeRoot(LayoutBox & root)1554 void LocalFrameView::RemoveOrthogonalWritingModeRoot(LayoutBox& root) {
1555 orthogonal_writing_mode_root_list_.Remove(root);
1556 }
1557
HasOrthogonalWritingModeRoots() const1558 bool LocalFrameView::HasOrthogonalWritingModeRoots() const {
1559 return !orthogonal_writing_mode_root_list_.IsEmpty();
1560 }
1561
RemoveFloatingObjectsForSubtreeRoot(LayoutObject & root)1562 static inline void RemoveFloatingObjectsForSubtreeRoot(LayoutObject& root) {
1563 // TODO(kojii): Under certain conditions, moveChildTo() defers
1564 // removeFloatingObjects() until the containing block layouts. For
1565 // instance, when descendants of the moving child is floating,
1566 // removeChildNode() does not clear them. In such cases, at this
1567 // point, FloatingObjects may contain old or even deleted objects.
1568 // Dealing this in markAllDescendantsWithFloatsForLayout() could
1569 // solve, but since that is likely to suffer the performance and
1570 // since the containing block of orthogonal writing mode roots
1571 // having floats is very rare, prefer to re-create
1572 // FloatingObjects.
1573 if (LayoutBlock* cb = root.ContainingBlock()) {
1574 auto* child_block_flow = DynamicTo<LayoutBlockFlow>(cb);
1575 if ((cb->NormalChildNeedsLayout() || cb->SelfNeedsLayout()) &&
1576 child_block_flow) {
1577 child_block_flow->RemoveFloatingObjectsFromDescendants();
1578 }
1579 }
1580 }
1581
PrepareOrthogonalWritingModeRootForLayout(LayoutObject & root)1582 static bool PrepareOrthogonalWritingModeRootForLayout(LayoutObject& root) {
1583 DCHECK(root.IsBox() && ToLayoutBox(root).IsOrthogonalWritingModeRoot());
1584 if (!root.NeedsLayout() || root.IsOutOfFlowPositioned() ||
1585 root.IsColumnSpanAll() ||
1586 !root.StyleRef().LogicalHeight().IsIntrinsicOrAuto() ||
1587 ToLayoutBox(root).IsGridItem() || root.IsTablePart())
1588 return false;
1589
1590 if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
1591 // Do not pre-layout objects that are fully managed by LayoutNG; it is not
1592 // necessary and may lead to double layouts. We do need to pre-layout
1593 // objects whose containing block is a legacy object so that it can
1594 // properly compute its intrinsic size.
1595 if (IsManagedByLayoutNG(root))
1596 return false;
1597
1598 // If the root is legacy but has |CachedLayoutResult|, its parent is NG,
1599 // which called |RunLegacyLayout()|. This parent not only needs to run
1600 // pre-layout, but also clearing |NeedsLayout()| without updating
1601 // |CachedLayoutResult| is harmful.
1602 if (const auto* box = ToLayoutBoxOrNull(&root)) {
1603 if (box->GetCachedLayoutResult())
1604 return false;
1605 }
1606 }
1607
1608 RemoveFloatingObjectsForSubtreeRoot(root);
1609 return true;
1610 }
1611
LayoutOrthogonalWritingModeRoots()1612 void LocalFrameView::LayoutOrthogonalWritingModeRoots() {
1613 for (auto& root : orthogonal_writing_mode_root_list_.Ordered()) {
1614 if (PrepareOrthogonalWritingModeRootForLayout(*root))
1615 LayoutFromRootObject(*root);
1616 }
1617 }
1618
ScheduleOrthogonalWritingModeRootsForLayout()1619 void LocalFrameView::ScheduleOrthogonalWritingModeRootsForLayout() {
1620 for (auto& root : orthogonal_writing_mode_root_list_.Ordered()) {
1621 if (PrepareOrthogonalWritingModeRootForLayout(*root))
1622 layout_subtree_root_list_.Add(*root);
1623 }
1624 }
1625
CheckLayoutInvalidationIsAllowed() const1626 bool LocalFrameView::CheckLayoutInvalidationIsAllowed() const {
1627 #if DCHECK_IS_ON()
1628 if (allows_layout_invalidation_after_layout_clean_)
1629 return true;
1630
1631 // If we are updating all lifecycle phases beyond LayoutClean, we don't expect
1632 // dirty layout after LayoutClean.
1633 CHECK_FOR_DIRTY_LAYOUT(Lifecycle().GetState() <
1634 DocumentLifecycle::kLayoutClean);
1635
1636 #endif
1637 return true;
1638 }
1639
ScheduleRelayout()1640 void LocalFrameView::ScheduleRelayout() {
1641 DCHECK(frame_->View() == this);
1642
1643 if (!layout_scheduling_enabled_)
1644 return;
1645 // TODO(crbug.com/590856): It's still broken when we choose not to crash when
1646 // the check fails.
1647 if (!CheckLayoutInvalidationIsAllowed())
1648 return;
1649 if (!NeedsLayout())
1650 return;
1651 if (!frame_->GetDocument()->ShouldScheduleLayout())
1652 return;
1653 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
1654 "InvalidateLayout", TRACE_EVENT_SCOPE_THREAD, "data",
1655 inspector_invalidate_layout_event::Data(frame_.Get()));
1656
1657 ClearLayoutSubtreeRootsAndMarkContainingBlocks();
1658
1659 if (has_pending_layout_)
1660 return;
1661 has_pending_layout_ = true;
1662
1663 if (!ShouldThrottleRendering())
1664 GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
1665 }
1666
ScheduleRelayoutOfSubtree(LayoutObject * relayout_root)1667 void LocalFrameView::ScheduleRelayoutOfSubtree(LayoutObject* relayout_root) {
1668 DCHECK(frame_->View() == this);
1669
1670 // TODO(crbug.com/590856): It's still broken when we choose not to crash when
1671 // the check fails.
1672 if (!CheckLayoutInvalidationIsAllowed())
1673 return;
1674
1675 // FIXME: Should this call shouldScheduleLayout instead?
1676 if (!frame_->GetDocument()->IsActive())
1677 return;
1678
1679 LayoutView* layout_view = this->GetLayoutView();
1680 if (layout_view && layout_view->NeedsLayout()) {
1681 if (relayout_root)
1682 relayout_root->MarkContainerChainForLayout(false);
1683 return;
1684 }
1685
1686 if (relayout_root == layout_view)
1687 layout_subtree_root_list_.ClearAndMarkContainingBlocksForLayout();
1688 else
1689 layout_subtree_root_list_.Add(*relayout_root);
1690
1691 if (layout_scheduling_enabled_) {
1692 has_pending_layout_ = true;
1693
1694 if (!ShouldThrottleRendering())
1695 GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
1696
1697 Lifecycle().EnsureStateAtMost(DocumentLifecycle::kStyleClean);
1698 }
1699 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
1700 "InvalidateLayout", TRACE_EVENT_SCOPE_THREAD, "data",
1701 inspector_invalidate_layout_event::Data(frame_.Get()));
1702 }
1703
LayoutPending() const1704 bool LocalFrameView::LayoutPending() const {
1705 // FIXME: This should check Document::lifecycle instead.
1706 return has_pending_layout_;
1707 }
1708
IsInPerformLayout() const1709 bool LocalFrameView::IsInPerformLayout() const {
1710 return Lifecycle().GetState() == DocumentLifecycle::kInPerformLayout;
1711 }
1712
NeedsLayout() const1713 bool LocalFrameView::NeedsLayout() const {
1714 // This can return true in cases where the document does not have a body yet.
1715 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1716 // layout in that case.
1717
1718 auto* layout_view = GetLayoutView();
1719 return LayoutPending() || (layout_view && layout_view->NeedsLayout()) ||
1720 IsSubtreeLayout();
1721 }
1722
CheckDoesNotNeedLayout() const1723 NOINLINE bool LocalFrameView::CheckDoesNotNeedLayout() const {
1724 CHECK_FOR_DIRTY_LAYOUT(!LayoutPending());
1725 CHECK_FOR_DIRTY_LAYOUT(!GetLayoutView() || !GetLayoutView()->NeedsLayout());
1726 CHECK_FOR_DIRTY_LAYOUT(!IsSubtreeLayout());
1727 return true;
1728 }
1729
SetNeedsLayout()1730 void LocalFrameView::SetNeedsLayout() {
1731 auto* layout_view = GetLayoutView();
1732 if (!layout_view)
1733 return;
1734 // TODO(crbug.com/590856): It's still broken if we choose not to crash when
1735 // the check fails.
1736 if (!CheckLayoutInvalidationIsAllowed())
1737 return;
1738 layout_view->SetNeedsLayout(layout_invalidation_reason::kUnknown);
1739 }
1740
HasOpaqueBackground() const1741 bool LocalFrameView::HasOpaqueBackground() const {
1742 return !base_background_color_.HasAlpha();
1743 }
1744
BaseBackgroundColor() const1745 Color LocalFrameView::BaseBackgroundColor() const {
1746 if (use_dark_scheme_background_ &&
1747 base_background_color_ != Color::kTransparent) {
1748 return Color::kBlack;
1749 }
1750 return base_background_color_;
1751 }
1752
SetBaseBackgroundColor(const Color & background_color)1753 void LocalFrameView::SetBaseBackgroundColor(const Color& background_color) {
1754 if (base_background_color_ == background_color)
1755 return;
1756
1757 base_background_color_ = background_color;
1758 if (auto* layout_view = GetLayoutView()) {
1759 if (layout_view->Layer()->HasCompositedLayerMapping()) {
1760 CompositedLayerMapping* composited_layer_mapping =
1761 layout_view->Layer()->GetCompositedLayerMapping();
1762 composited_layer_mapping->UpdateContentsOpaque();
1763 if (composited_layer_mapping->MainGraphicsLayer())
1764 composited_layer_mapping->MainGraphicsLayer()->SetNeedsDisplay();
1765 if (composited_layer_mapping->ScrollingContentsLayer())
1766 composited_layer_mapping->ScrollingContentsLayer()->SetNeedsDisplay();
1767 }
1768 }
1769
1770 if (!ShouldThrottleRendering())
1771 GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
1772 }
1773
SetUseDarkSchemeBackground(bool dark_scheme)1774 void LocalFrameView::SetUseDarkSchemeBackground(bool dark_scheme) {
1775 if (use_dark_scheme_background_ == dark_scheme)
1776 return;
1777
1778 use_dark_scheme_background_ = dark_scheme;
1779 if (auto* layout_view = GetLayoutView())
1780 layout_view->SetBackgroundNeedsFullPaintInvalidation();
1781 }
1782
UpdateBaseBackgroundColorRecursively(const Color & base_background_color)1783 void LocalFrameView::UpdateBaseBackgroundColorRecursively(
1784 const Color& base_background_color) {
1785 ForAllNonThrottledLocalFrameViews(
1786 [base_background_color](LocalFrameView& frame_view) {
1787 frame_view.SetBaseBackgroundColor(base_background_color);
1788 });
1789 }
1790
InvokeFragmentAnchor()1791 void LocalFrameView::InvokeFragmentAnchor() {
1792 if (!fragment_anchor_)
1793 return;
1794
1795 if (!fragment_anchor_->Invoke())
1796 fragment_anchor_ = nullptr;
1797 }
1798
DismissFragmentAnchor()1799 void LocalFrameView::DismissFragmentAnchor() {
1800 if (!fragment_anchor_)
1801 return;
1802
1803 if (fragment_anchor_->Dismiss())
1804 fragment_anchor_ = nullptr;
1805 }
1806
UpdatePlugins()1807 bool LocalFrameView::UpdatePlugins() {
1808 // This is always called from UpdatePluginsTimerFired.
1809 // update_plugins_timer should only be scheduled if we have FrameViews to
1810 // update. Thus I believe we can stop checking isEmpty here, and just ASSERT
1811 // isEmpty:
1812 // FIXME: This assert has been temporarily removed due to
1813 // https://crbug.com/430344
1814 if (nested_layout_count_ > 1 || part_update_set_.IsEmpty())
1815 return true;
1816
1817 // Need to swap because script will run inside the below loop and invalidate
1818 // the iterator.
1819 EmbeddedObjectSet objects;
1820 objects.swap(part_update_set_);
1821
1822 for (const auto& embedded_object : objects) {
1823 LayoutEmbeddedObject& object = *embedded_object;
1824 auto* element = To<HTMLPlugInElement>(object.GetNode());
1825
1826 // The object may have already been destroyed (thus node cleared),
1827 // but LocalFrameView holds a manual ref, so it won't have been deleted.
1828 if (!element)
1829 continue;
1830
1831 // No need to update if it's already crashed or known to be missing.
1832 if (object.ShowsUnavailablePluginIndicator())
1833 continue;
1834
1835 if (element->NeedsPluginUpdate())
1836 element->UpdatePlugin();
1837 if (EmbeddedContentView* view = element->OwnedEmbeddedContentView())
1838 view->UpdateGeometry();
1839
1840 // Prevent plugins from causing infinite updates of themselves.
1841 // FIXME: Do we really need to prevent this?
1842 part_update_set_.erase(&object);
1843 }
1844
1845 return part_update_set_.IsEmpty();
1846 }
1847
UpdatePluginsTimerFired(TimerBase *)1848 void LocalFrameView::UpdatePluginsTimerFired(TimerBase*) {
1849 DCHECK(!IsInPerformLayout());
1850 for (unsigned i = 0; i < kMaxUpdatePluginsIterations; ++i) {
1851 if (UpdatePlugins())
1852 return;
1853 }
1854 }
1855
FlushAnyPendingPostLayoutTasks()1856 void LocalFrameView::FlushAnyPendingPostLayoutTasks() {
1857 DCHECK(!IsInPerformLayout());
1858 if (update_plugins_timer_.IsActive()) {
1859 update_plugins_timer_.Stop();
1860 UpdatePluginsTimerFired(nullptr);
1861 }
1862 }
1863
ScheduleUpdatePluginsIfNecessary()1864 void LocalFrameView::ScheduleUpdatePluginsIfNecessary() {
1865 DCHECK(!IsInPerformLayout());
1866 if (update_plugins_timer_.IsActive() || part_update_set_.IsEmpty())
1867 return;
1868 update_plugins_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
1869 }
1870
PerformPostLayoutTasks()1871 void LocalFrameView::PerformPostLayoutTasks() {
1872 // FIXME: We can reach here, even when the page is not active!
1873 // http/tests/inspector/elements/html-link-import.html and many other
1874 // tests hit that case.
1875 // We should DCHECK(isActive()); or at least return early if we can!
1876
1877 // Always called before or after performLayout(), part of the highest-level
1878 // layout() call.
1879 DCHECK(!IsInPerformLayout());
1880 TRACE_EVENT0("blink,benchmark", "LocalFrameView::performPostLayoutTasks");
1881
1882 frame_->Selection().DidLayout();
1883
1884 DCHECK(frame_->GetDocument());
1885
1886 FontFaceSetDocument::DidLayout(*frame_->GetDocument());
1887 // Fire a fake a mouse move event to update hover state and mouse cursor, and
1888 // send the right mouse out/over events.
1889 // TODO(lanwei): we should check whether the mouse is inside the frame before
1890 // dirtying the hover state.
1891 frame_->LocalFrameRoot().GetEventHandler().MarkHoverStateDirty();
1892
1893 UpdateGeometriesIfNeeded();
1894
1895 // Plugins could have torn down the page inside updateGeometries().
1896 if (!GetLayoutView())
1897 return;
1898
1899 ScheduleUpdatePluginsIfNecessary();
1900
1901 if (ScrollingCoordinator* scrolling_coordinator =
1902 this->GetScrollingCoordinator()) {
1903 scrolling_coordinator->NotifyGeometryChanged(this);
1904 }
1905
1906 SendResizeEventIfNeeded();
1907 }
1908
WasViewportResized()1909 bool LocalFrameView::WasViewportResized() {
1910 DCHECK(frame_);
1911 auto* layout_view = GetLayoutView();
1912 if (!layout_view)
1913 return false;
1914 return (GetLayoutSize() != last_viewport_size_ ||
1915 layout_view->StyleRef().Zoom() != last_zoom_factor_);
1916 }
1917
SendResizeEventIfNeeded()1918 void LocalFrameView::SendResizeEventIfNeeded() {
1919 DCHECK(frame_);
1920
1921 auto* layout_view = GetLayoutView();
1922 if (!layout_view || layout_view->GetDocument().Printing())
1923 return;
1924
1925 if (!WasViewportResized())
1926 return;
1927
1928 last_viewport_size_ = GetLayoutSize();
1929 last_zoom_factor_ = layout_view->StyleRef().Zoom();
1930
1931 frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
1932
1933 frame_->GetDocument()->EnqueueResizeEvent();
1934
1935 if (frame_->IsMainFrame())
1936 probe::DidResizeMainFrame(frame_.Get());
1937 }
1938
InputEventsScaleFactor() const1939 float LocalFrameView::InputEventsScaleFactor() const {
1940 float page_scale = frame_->GetPage()->GetVisualViewport().Scale();
1941 return page_scale *
1942 frame_->GetPage()->GetChromeClient().InputEventsScaleForEmulation();
1943 }
1944
NotifyPageThatContentAreaWillPaint() const1945 void LocalFrameView::NotifyPageThatContentAreaWillPaint() const {
1946 Page* page = frame_->GetPage();
1947 if (!page)
1948 return;
1949
1950 if (!scrollable_areas_)
1951 return;
1952
1953 for (const auto& scrollable_area : *scrollable_areas_) {
1954 if (!scrollable_area->ScrollbarsCanBeActive())
1955 continue;
1956
1957 scrollable_area->ContentAreaWillPaint();
1958 }
1959 }
1960
UpdateDocumentAnnotatedRegions() const1961 void LocalFrameView::UpdateDocumentAnnotatedRegions() const {
1962 Document* document = frame_->GetDocument();
1963 if (!document->HasAnnotatedRegions())
1964 return;
1965 Vector<AnnotatedRegionValue> new_regions;
1966 CollectAnnotatedRegions(*(document->GetLayoutBox()), new_regions);
1967 if (new_regions == document->AnnotatedRegions())
1968 return;
1969 document->SetAnnotatedRegions(new_regions);
1970
1971 DCHECK(frame_->Client());
1972 frame_->Client()->AnnotatedRegionsChanged();
1973 }
1974
DidAttachDocument()1975 void LocalFrameView::DidAttachDocument() {
1976 Page* page = frame_->GetPage();
1977 DCHECK(page);
1978
1979 DCHECK(frame_->GetDocument());
1980
1981 if (frame_->IsMainFrame()) {
1982 ScrollableArea& visual_viewport = frame_->GetPage()->GetVisualViewport();
1983 ScrollableArea* layout_viewport = LayoutViewport();
1984 DCHECK(layout_viewport);
1985
1986 auto* root_frame_viewport = MakeGarbageCollected<RootFrameViewport>(
1987 visual_viewport, *layout_viewport);
1988 viewport_scrollable_area_ = root_frame_viewport;
1989
1990 page->GlobalRootScrollerController().InitializeViewportScrollCallback(
1991 *root_frame_viewport, *frame_->GetDocument());
1992
1993 // Allow for commits to be deferred because this is a new document.
1994 have_deferred_commits_ = false;
1995 }
1996 }
1997
DocumentBackgroundColor() const1998 Color LocalFrameView::DocumentBackgroundColor() const {
1999 // The LayoutView's background color is set in
2000 // Document::inheritHtmlAndBodyElementStyles. Blend this with the base
2001 // background color of the LocalFrameView. This should match the color drawn
2002 // by ViewPainter::paintBoxDecorationBackground.
2003 Color result = BaseBackgroundColor();
2004
2005 // If we have a fullscreen element grab the fullscreen color from the
2006 // backdrop.
2007 if (Document* doc = frame_->GetDocument()) {
2008 if (Element* element = Fullscreen::FullscreenElementFrom(*doc)) {
2009 if (doc->IsXrOverlay()) {
2010 // Use the fullscreened element's background directly. Don't bother
2011 // blending with the backdrop since that's transparent.
2012 if (LayoutObject* layout_object = element->GetLayoutObject()) {
2013 return layout_object->ResolveColor(GetCSSPropertyBackgroundColor());
2014 }
2015 if (LayoutObject* layout_object =
2016 element->PseudoElementLayoutObject(kPseudoIdBackdrop)) {
2017 return layout_object->ResolveColor(GetCSSPropertyBackgroundColor());
2018 }
2019 }
2020 if (LayoutObject* layout_object =
2021 element->PseudoElementLayoutObject(kPseudoIdBackdrop)) {
2022 return result.Blend(
2023 layout_object->ResolveColor(GetCSSPropertyBackgroundColor()));
2024 }
2025 }
2026 }
2027 auto* layout_view = GetLayoutView();
2028 if (layout_view) {
2029 result = result.Blend(
2030 layout_view->ResolveColor(GetCSSPropertyBackgroundColor()));
2031 }
2032 return result;
2033 }
2034
WillBeRemovedFromFrame()2035 void LocalFrameView::WillBeRemovedFromFrame() {
2036 if (paint_artifact_compositor_)
2037 paint_artifact_compositor_->WillBeRemovedFromFrame();
2038
2039 if (Settings* settings = frame_->GetSettings()) {
2040 DCHECK(frame_->GetPage());
2041 if (settings->GetSpatialNavigationEnabled()) {
2042 frame_->GetPage()->GetSpatialNavigationController().DidDetachFrameView(
2043 *this);
2044 }
2045 }
2046 }
2047
ParentFrameView() const2048 LocalFrameView* LocalFrameView::ParentFrameView() const {
2049 if (!IsAttached())
2050 return nullptr;
2051
2052 Frame* parent_frame = frame_->Tree().Parent();
2053 if (auto* parent_local_frame = DynamicTo<LocalFrame>(parent_frame))
2054 return parent_local_frame->View();
2055
2056 return nullptr;
2057 }
2058
GetLayoutEmbeddedContent() const2059 LayoutEmbeddedContent* LocalFrameView::GetLayoutEmbeddedContent() const {
2060 return frame_->OwnerLayoutObject();
2061 }
2062
VisualViewportScrollbarsChanged()2063 void LocalFrameView::VisualViewportScrollbarsChanged() {
2064 SetVisualViewportNeedsRepaint();
2065 if (LayoutView* layout_view = GetLayoutView())
2066 layout_view->Layer()->ClearClipRects();
2067 }
2068
UpdateGeometriesIfNeeded()2069 void LocalFrameView::UpdateGeometriesIfNeeded() {
2070 if (!needs_update_geometries_)
2071 return;
2072 needs_update_geometries_ = false;
2073 HeapVector<Member<EmbeddedContentView>> views;
2074 ForAllChildViewsAndPlugins(
2075 [&](EmbeddedContentView& view) { views.push_back(view); });
2076
2077 for (const auto& view : views) {
2078 // Script or plugins could detach the frame so abort processing if that
2079 // happens.
2080 if (!GetLayoutView())
2081 break;
2082
2083 view->UpdateGeometry();
2084 }
2085 // Explicitly free the backing store to avoid memory regressions.
2086 // TODO(bikineev): Revisit after young generation is there.
2087 views.clear();
2088 }
2089
UpdateAllLifecyclePhases(DocumentUpdateReason reason)2090 bool LocalFrameView::UpdateAllLifecyclePhases(DocumentUpdateReason reason) {
2091 bool updated = GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
2092 DocumentLifecycle::kPaintClean, reason);
2093
2094 #if DCHECK_IS_ON()
2095 if (updated) {
2096 // This function should return true iff all non-throttled frames are in the
2097 // kPaintClean lifecycle state.
2098 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2099 DCHECK_EQ(frame_view.Lifecycle().GetState(),
2100 DocumentLifecycle::kPaintClean);
2101 });
2102
2103 // A required intersection observation should run throttled frames to
2104 // kLayoutClean.
2105 ForAllThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2106 DCHECK(frame_view.intersection_observation_state_ != kRequired ||
2107 frame_view.Lifecycle().GetState() >=
2108 DocumentLifecycle::kLayoutClean);
2109 });
2110 }
2111 #endif
2112
2113 return updated;
2114 }
2115
2116 // TODO(schenney): add a scrolling update lifecycle phase.
2117 // TODO(schenney): Pass a LifecycleUpdateReason in here
UpdateLifecycleToCompositingCleanPlusScrolling(DocumentUpdateReason reason)2118 bool LocalFrameView::UpdateLifecycleToCompositingCleanPlusScrolling(
2119 DocumentUpdateReason reason) {
2120 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
2121 return UpdateAllLifecyclePhasesExceptPaint(reason);
2122 return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
2123 DocumentLifecycle::kCompositingClean, reason);
2124 }
2125
2126 // TODO(schenney): Pass a LifecycleUpdateReason in here
UpdateLifecycleToCompositingInputsClean(DocumentUpdateReason reason)2127 bool LocalFrameView::UpdateLifecycleToCompositingInputsClean(
2128 DocumentUpdateReason reason) {
2129 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
2130 return UpdateAllLifecyclePhasesExceptPaint(reason);
2131 return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
2132 DocumentLifecycle::kCompositingInputsClean, reason);
2133 }
2134
2135 // TODO(schenney): Pass a LifecycleUpdateReason in here
UpdateAllLifecyclePhasesExceptPaint(DocumentUpdateReason reason)2136 bool LocalFrameView::UpdateAllLifecyclePhasesExceptPaint(
2137 DocumentUpdateReason reason) {
2138 return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
2139 DocumentLifecycle::kPrePaintClean, reason);
2140 }
2141
UpdateLifecyclePhasesForPrinting()2142 void LocalFrameView::UpdateLifecyclePhasesForPrinting() {
2143 auto* local_frame_view_root = GetFrame().LocalFrameRoot().View();
2144 local_frame_view_root->UpdateLifecyclePhases(
2145 DocumentLifecycle::kPrePaintClean, DocumentUpdateReason::kPrinting);
2146
2147 auto* detached_frame_view = this;
2148 while (detached_frame_view->IsAttached() &&
2149 detached_frame_view != local_frame_view_root) {
2150 detached_frame_view = detached_frame_view->ParentFrameView();
2151 CHECK(detached_frame_view);
2152 }
2153
2154 if (detached_frame_view == local_frame_view_root)
2155 return;
2156 DCHECK(!detached_frame_view->IsAttached());
2157
2158 // We are printing a detached frame or a descendant of a detached frame which
2159 // was not reached in some phases during during |local_frame_view_root->
2160 // UpdateLifecyclePhasesnormal()|. We need the subtree to be ready for
2161 // painting.
2162 detached_frame_view->UpdateLifecyclePhases(DocumentLifecycle::kPrePaintClean,
2163 DocumentUpdateReason::kPrinting);
2164 }
2165
2166 // TODO(schenney): Pass a LifecycleUpdateReason in here
UpdateLifecycleToLayoutClean(DocumentUpdateReason reason)2167 bool LocalFrameView::UpdateLifecycleToLayoutClean(DocumentUpdateReason reason) {
2168 return GetFrame().LocalFrameRoot().View()->UpdateLifecyclePhases(
2169 DocumentLifecycle::kLayoutClean, reason);
2170 }
2171
ScheduleVisualUpdateForPaintInvalidationIfNeeded()2172 void LocalFrameView::ScheduleVisualUpdateForPaintInvalidationIfNeeded() {
2173 LocalFrame& local_frame_root = GetFrame().LocalFrameRoot();
2174 if (local_frame_root.View()->current_update_lifecycle_phases_target_state_ <
2175 DocumentLifecycle::kPrePaintClean ||
2176 Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean) {
2177 // Schedule visual update to process the paint invalidation in the next
2178 // cycle.
2179 local_frame_root.ScheduleVisualUpdateUnlessThrottled();
2180 }
2181 // Otherwise the paint invalidation will be handled in the pre-paint
2182 // phase of this cycle.
2183 }
2184
NotifyResizeObservers(DocumentLifecycle::LifecycleState target_state)2185 bool LocalFrameView::NotifyResizeObservers(
2186 DocumentLifecycle::LifecycleState target_state) {
2187 // Return true if lifecycles need to be re-run
2188 TRACE_EVENT0("blink,benchmark", "LocalFrameView::NotifyResizeObservers");
2189
2190 if (target_state < DocumentLifecycle::kPaintClean)
2191 return false;
2192
2193 // Controller exists only if ResizeObserver was created.
2194 if (!GetFrame().GetDocument()->GetResizeObserverController())
2195 return false;
2196
2197 ResizeObserverController& resize_controller =
2198 frame_->GetDocument()->EnsureResizeObserverController();
2199
2200 DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
2201
2202 size_t min_depth = resize_controller.GatherObservations();
2203
2204 if (min_depth != ResizeObserverController::kDepthBottom) {
2205 resize_controller.DeliverObservations();
2206 } else {
2207 // Observation depth limit reached
2208 if (resize_controller.SkippedObservations()) {
2209 resize_controller.ClearObservations();
2210 ErrorEvent* error = ErrorEvent::Create(
2211 "ResizeObserver loop limit exceeded",
2212 SourceLocation::Capture(frame_->GetDocument()->ToExecutionContext()),
2213 nullptr);
2214 // We're using |SanitizeScriptErrors::kDoNotSanitize| as the error is made
2215 // by blink itself.
2216 // TODO(yhirano): Reconsider this.
2217 frame_->GetDocument()->ToExecutionContext()->DispatchErrorEvent(
2218 error, SanitizeScriptErrors::kDoNotSanitize);
2219 // Ensure notifications will get delivered in next cycle.
2220 ScheduleAnimation();
2221 DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
2222 }
2223 if (Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean)
2224 return false;
2225 }
2226
2227 // Lifecycle needs to be run again because Resize Observer affected layout
2228 return true;
2229 }
2230
2231 // TODO(leviw): We don't assert lifecycle information from documents in child
2232 // WebPluginContainerImpls.
UpdateLifecyclePhases(DocumentLifecycle::LifecycleState target_state,DocumentUpdateReason reason)2233 bool LocalFrameView::UpdateLifecyclePhases(
2234 DocumentLifecycle::LifecycleState target_state,
2235 DocumentUpdateReason reason) {
2236 // If the lifecycle is postponed, which can happen if the inspector requests
2237 // it, then we shouldn't update any lifecycle phases.
2238 if (UNLIKELY(frame_->GetDocument() &&
2239 frame_->GetDocument()->Lifecycle().LifecyclePostponed())) {
2240 return false;
2241 }
2242
2243 // Prevent reentrance.
2244 // TODO(vmpstr): Should we just have a DCHECK instead here?
2245 if (UNLIKELY(current_update_lifecycle_phases_target_state_ !=
2246 DocumentLifecycle::kUninitialized)) {
2247 NOTREACHED()
2248 << "LocalFrameView::updateLifecyclePhasesInternal() reentrance";
2249 return false;
2250 }
2251
2252 // This must be called from the root frame, or a detached frame for printing,
2253 // since it recurses down, not up. Otherwise the lifecycles of the frames
2254 // might be out of sync.
2255 DCHECK(frame_->IsLocalRoot() || !IsAttached());
2256
2257 // Only the following target states are supported.
2258 DCHECK(target_state == DocumentLifecycle::kLayoutClean ||
2259 target_state == DocumentLifecycle::kAccessibilityClean ||
2260 target_state == DocumentLifecycle::kCompositingInputsClean ||
2261 target_state == DocumentLifecycle::kCompositingClean ||
2262 target_state == DocumentLifecycle::kPrePaintClean ||
2263 target_state == DocumentLifecycle::kPaintClean);
2264 lifecycle_update_count_for_testing_++;
2265
2266 // If the document is not active then it is either not yet initialized, or it
2267 // is stopping. In either case, we can't reach one of the supported target
2268 // states.
2269 if (!frame_->GetDocument()->IsActive())
2270 return false;
2271
2272 if (frame_->IsLocalRoot())
2273 UpdateLayerDebugInfoEnabled();
2274
2275 // This is used to guard against reentrance. It is also used in conjunction
2276 // with the current lifecycle state to determine which phases are yet to run
2277 // in this cycle.
2278 base::AutoReset<DocumentLifecycle::LifecycleState> target_state_scope(
2279 ¤t_update_lifecycle_phases_target_state_, target_state);
2280 // This is used to check if we're within a lifecycle update but have passed
2281 // the layout update phase. Note there is a bit of a subtlety here: it's not
2282 // sufficient for us to check the current lifecycle state, since it can be
2283 // past kLayoutClean but the function to run style and layout phase has not
2284 // actually been run yet. Since this bool affects throttling, and throttling,
2285 // in turn, determines whether style and layout function will run, we need a
2286 // separate bool.
2287 base::AutoReset<bool> past_layout_lifecycle_resetter(
2288 &past_layout_lifecycle_update_, false);
2289 base::AutoReset<bool> in_lifecycle_scope(&in_lifecycle_update_, true);
2290
2291 // If we're throttling, then we don't need to update lifecycle phases. The
2292 // throttling status will get updated in RunPostLifecycleSteps().
2293 if (ShouldThrottleRendering()) {
2294 return Lifecycle().GetState() == target_state;
2295 }
2296
2297 lifecycle_data_.start_time = base::TimeTicks::Now();
2298 ++lifecycle_data_.count;
2299
2300 {
2301 TRACE_EVENT0("blink", "LocalFrameView::WillStartLifecycleUpdate");
2302
2303 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2304 auto lifecycle_observers = frame_view.lifecycle_observers_;
2305 for (auto& observer : lifecycle_observers)
2306 observer->WillStartLifecycleUpdate(frame_view);
2307 });
2308 }
2309
2310 {
2311 TRACE_EVENT0(
2312 "blink",
2313 "LocalFrameView::UpdateLifecyclePhases - start of lifecycle tasks");
2314 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2315 WTF::Vector<base::OnceClosure> tasks;
2316 frame_view.start_of_lifecycle_tasks_.swap(tasks);
2317 for (auto& task : tasks)
2318 std::move(task).Run();
2319 });
2320 }
2321
2322 // Run the lifecycle updates.
2323 UpdateLifecyclePhasesInternal(target_state);
2324
2325 {
2326 TRACE_EVENT0("blink", "LocalFrameView::DidFinishLifecycleUpdate");
2327
2328 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2329 auto lifecycle_observers = frame_view.lifecycle_observers_;
2330 for (auto& observer : lifecycle_observers)
2331 observer->DidFinishLifecycleUpdate(frame_view);
2332 });
2333 }
2334
2335 // Hit testing metrics include the entire time processing a document update
2336 // in preparation for a hit test.
2337 if (reason == DocumentUpdateReason::kHitTest) {
2338 LocalFrameUkmAggregator& aggregator = EnsureUkmAggregator();
2339 aggregator.RecordSample(
2340 static_cast<size_t>(LocalFrameUkmAggregator::kHitTestDocumentUpdate),
2341 lifecycle_data_.start_time, base::TimeTicks::Now());
2342 }
2343
2344 return Lifecycle().GetState() == target_state;
2345 }
2346
UpdateLifecyclePhasesInternal(DocumentLifecycle::LifecycleState target_state)2347 void LocalFrameView::UpdateLifecyclePhasesInternal(
2348 DocumentLifecycle::LifecycleState target_state) {
2349 // Run style, layout, compositing and prepaint lifecycle phases and deliver
2350 // resize observations if required. Resize observer callbacks/delegates have
2351 // the potential to dirty layout (until loop limit is reached) and therefore
2352 // the above lifecycle phases need to be re-run until the limit is reached
2353 // or no layout is pending.
2354 while (true) {
2355 bool run_more_lifecycle_phases =
2356 RunStyleAndLayoutLifecyclePhases(target_state);
2357 if (!run_more_lifecycle_phases)
2358 return;
2359 DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
2360
2361 if (!GetLayoutView())
2362 return;
2363
2364 {
2365 // We need scoping braces here because this
2366 // DisallowLayoutInvalidationScope is meant to be in effect during
2367 // pre-paint, but not during ResizeObserver.
2368 #if DCHECK_IS_ON()
2369 DisallowLayoutInvalidationScope disallow_layout_invalidation(this);
2370 #endif
2371
2372 DCHECK_GE(target_state, DocumentLifecycle::kAccessibilityClean);
2373 run_more_lifecycle_phases = RunAccessibilityLifecyclePhase(target_state);
2374 DCHECK(ShouldThrottleRendering() || !ExistingAXObjectCache() ||
2375 Lifecycle().GetState() == DocumentLifecycle::kAccessibilityClean);
2376 if (!run_more_lifecycle_phases)
2377 return;
2378
2379 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
2380 "SetLayerTreeId", TRACE_EVENT_SCOPE_THREAD, "data",
2381 inspector_set_layer_tree_id::Data(frame_.Get()));
2382 TRACE_EVENT1("devtools.timeline", "UpdateLayerTree", "data",
2383 inspector_update_layer_tree_event::Data(frame_.Get()));
2384
2385 run_more_lifecycle_phases = RunCompositingLifecyclePhase(target_state);
2386 if (!run_more_lifecycle_phases)
2387 return;
2388
2389 // TODO(pdr): PrePaint should be under the "Paint" devtools timeline step
2390 // when CompositeAfterPaint is enabled.
2391 run_more_lifecycle_phases = RunPrePaintLifecyclePhase(target_state);
2392 DCHECK(ShouldThrottleRendering() ||
2393 Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
2394 if (!run_more_lifecycle_phases)
2395 return;
2396 }
2397
2398 run_more_lifecycle_phases = RunResizeObserverSteps(target_state);
2399 if (!run_more_lifecycle_phases)
2400 break;
2401 }
2402 // Layout invalidation scope was disabled for resize observer
2403 // re-enable it for subsequent steps
2404 #if DCHECK_IS_ON()
2405 DisallowLayoutInvalidationScope disallow_layout_invalidation(this);
2406 #endif
2407 // Now that we have run the lifecycle up to paint, we can reset
2408 // |need_paint_phase_after_throttling_| so that the paint phase will
2409 // properly see us as being throttled (if that was the only reason we remained
2410 // unthrottled), and clear the painted output.
2411 need_paint_phase_after_throttling_ = false;
2412
2413 DCHECK_EQ(target_state, DocumentLifecycle::kPaintClean);
2414 RunPaintLifecyclePhase();
2415 DCHECK(ShouldThrottleRendering() ||
2416 frame_->GetDocument()->IsCapturingLayout() ||
2417 Lifecycle().GetState() == DocumentLifecycle::kPaintClean);
2418
2419 ForAllRemoteFrameViews(
2420 [](RemoteFrameView& frame_view) { frame_view.UpdateCompositingRect(); });
2421 }
2422
RunResizeObserverSteps(DocumentLifecycle::LifecycleState target_state)2423 bool LocalFrameView::RunResizeObserverSteps(
2424 DocumentLifecycle::LifecycleState target_state) {
2425 bool re_run_lifecycles = false;
2426 if (target_state == DocumentLifecycle::kPaintClean) {
2427 ForAllNonThrottledLocalFrameViews(
2428 [&re_run_lifecycles](LocalFrameView& frame_view) {
2429 bool result =
2430 frame_view.NotifyResizeObservers(DocumentLifecycle::kPaintClean);
2431 re_run_lifecycles = re_run_lifecycles || result;
2432 });
2433 }
2434 if (!re_run_lifecycles) {
2435 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2436 ResizeObserverController& resize_controller =
2437 frame_view.frame_->GetDocument()->EnsureResizeObserverController();
2438 resize_controller.ClearMinDepth();
2439 });
2440 }
2441 return re_run_lifecycles;
2442 }
2443
RunStyleAndLayoutLifecyclePhases(DocumentLifecycle::LifecycleState target_state)2444 bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
2445 DocumentLifecycle::LifecycleState target_state) {
2446 TRACE_EVENT0("blink,benchmark",
2447 "LocalFrameView::RunStyleAndLayoutLifecyclePhases");
2448 UpdateStyleAndLayoutIfNeededRecursive();
2449 DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
2450
2451 frame_->GetDocument()
2452 ->GetRootScrollerController()
2453 .PerformRootScrollerSelection();
2454
2455 // PerformRootScrollerSelection can dirty layout if an effective root
2456 // scroller is changed so make sure we get back to LayoutClean.
2457 if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() ||
2458 RuntimeEnabledFeatures::SetRootScrollerEnabled()) {
2459 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2460 if (frame_view.NeedsLayout())
2461 frame_view.UpdateLayout();
2462
2463 DCHECK(frame_view.Lifecycle().GetState() >=
2464 DocumentLifecycle::kLayoutClean);
2465 });
2466 }
2467
2468 if (target_state == DocumentLifecycle::kLayoutClean)
2469 return false;
2470
2471 // This will be reset by AutoReset in the calling function
2472 // (UpdateLifecyclePhases()).
2473 past_layout_lifecycle_update_ = true;
2474
2475 // After layout and the |past_layout_lifecycle_update_| update, the value of
2476 // ShouldThrottleRendering() can change. OOPIF local frame roots that are
2477 // throttled can return now that layout is clean. This situation happens if
2478 // the throttling was disabled due to required intersection observation, which
2479 // can now be run.
2480 if (ShouldThrottleRendering())
2481 return false;
2482
2483 // Now we can run post layout steps in preparation for further phases.
2484 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2485 frame_view.PerformScrollAnchoringAdjustments();
2486 });
2487
2488 frame_->GetDocument()->PerformScrollSnappingTasks();
2489
2490 EnqueueScrollEvents();
2491
2492 frame_->GetPage()->GetValidationMessageClient().LayoutOverlay();
2493
2494 if (target_state == DocumentLifecycle::kPaintClean) {
2495 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2496 frame_view.NotifyFrameRectsChangedIfNeeded();
2497 });
2498 }
2499
2500 return Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean;
2501 }
2502
RunCompositingLifecyclePhase(DocumentLifecycle::LifecycleState target_state)2503 bool LocalFrameView::RunCompositingLifecyclePhase(
2504 DocumentLifecycle::LifecycleState target_state) {
2505 TRACE_EVENT0("blink,benchmark",
2506 "LocalFrameView::RunCompositingLifecyclePhase");
2507 auto* layout_view = GetLayoutView();
2508 DCHECK(layout_view);
2509
2510 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2511 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
2512 LocalFrameUkmAggregator::kCompositing);
2513 layout_view->Compositor()->UpdateIfNeededRecursive(target_state);
2514 }
2515
2516 return target_state > DocumentLifecycle::kCompositingClean;
2517 }
2518
RunPrePaintLifecyclePhase(DocumentLifecycle::LifecycleState target_state)2519 bool LocalFrameView::RunPrePaintLifecyclePhase(
2520 DocumentLifecycle::LifecycleState target_state) {
2521 TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunPrePaintLifecyclePhase");
2522
2523 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2524 // TODO(pdr): This descendant dependent treewalk should be integrated into
2525 // the prepaint tree walk.
2526 #if DCHECK_IS_ON()
2527 SetIsUpdatingDescendantDependentFlags(true);
2528 #endif
2529 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2530 frame_view.GetLayoutView()->Layer()->UpdateDescendantDependentFlags();
2531 frame_view.GetLayoutView()->CommitPendingSelection();
2532 });
2533 #if DCHECK_IS_ON()
2534 SetIsUpdatingDescendantDependentFlags(false);
2535 #endif
2536 }
2537
2538 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2539 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
2540 if (frame_view.CanThrottleRendering()) {
2541 // This frame can be throttled but not throttled, meaning we are not in an
2542 // AllowThrottlingScope. Now this frame may contain dirty paint flags, and
2543 // we need to propagate the flags into the ancestor chain so that
2544 // PrePaintTreeWalk can reach this frame.
2545 frame_view.SetNeedsPaintPropertyUpdate();
2546 // We may record more foreign layers under the frame.
2547 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
2548 frame_view.SetForeignLayerListNeedsUpdate();
2549 if (auto* owner = frame_view.GetLayoutEmbeddedContent())
2550 owner->SetShouldCheckForPaintInvalidation();
2551 }
2552 });
2553
2554 {
2555 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
2556 LocalFrameUkmAggregator::kPrePaint);
2557
2558 GetPage()->GetLinkHighlight().UpdateBeforePrePaint();
2559 PrePaintTreeWalk().WalkTree(*this);
2560 GetPage()->GetLinkHighlight().UpdateAfterPrePaint();
2561 }
2562
2563 UpdateCompositedSelectionIfNeeded();
2564
2565 frame_->GetPage()->GetValidationMessageClient().UpdatePrePaint();
2566 ForAllNonThrottledLocalFrameViews([](LocalFrameView& view) {
2567 view.frame_->UpdateFrameColorOverlayPrePaint();
2568 });
2569 if (auto* web_local_frame_impl = WebLocalFrameImpl::FromFrame(frame_))
2570 web_local_frame_impl->UpdateDevToolsOverlaysPrePaint();
2571
2572 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2573 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPrePaintClean);
2574 });
2575
2576 return target_state > DocumentLifecycle::kPrePaintClean;
2577 }
2578
2579 template <typename Function>
ForAllGraphicsLayers(GraphicsLayer & layer,const Function & function)2580 static void ForAllGraphicsLayers(GraphicsLayer& layer,
2581 const Function& function) {
2582 function(layer);
2583 for (auto* child : layer.Children())
2584 ForAllGraphicsLayers(*child, function);
2585 }
2586
RunPaintLifecyclePhase()2587 void LocalFrameView::RunPaintLifecyclePhase() {
2588 TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunPaintLifecyclePhase");
2589 // While printing or capturing a paint preview of a document, the paint walk
2590 // is done into a special canvas. There is no point doing a normal paint step
2591 // (or animations update) when in this mode.
2592 bool is_capturing_layout = frame_->GetDocument()->IsCapturingLayout();
2593 if (!is_capturing_layout)
2594 PaintTree();
2595
2596 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2597 if (GetLayoutView()->Compositor()->InCompositingMode()) {
2598 GetScrollingCoordinator()->UpdateAfterPaint(this);
2599 }
2600 }
2601
2602 if (!is_capturing_layout) {
2603 bool needed_update = !paint_artifact_compositor_ ||
2604 paint_artifact_compositor_->NeedsUpdate();
2605 PushPaintArtifactToCompositor();
2606 ForAllNonThrottledLocalFrameViews([this](LocalFrameView& frame_view) {
2607 frame_view.GetScrollableArea()->UpdateCompositorScrollAnimations();
2608 if (const auto* animating_scrollable_areas =
2609 frame_view.AnimatingScrollableAreas()) {
2610 for (PaintLayerScrollableArea* area : *animating_scrollable_areas)
2611 area->UpdateCompositorScrollAnimations();
2612 }
2613 frame_view.GetLayoutView()
2614 ->GetDocument()
2615 .GetDocumentAnimations()
2616 .UpdateAnimations(DocumentLifecycle::kPaintClean,
2617 paint_artifact_compositor_.get());
2618 });
2619
2620 // Initialize animation properties in the newly created paint property
2621 // nodes according to the current animation state. This is mainly for
2622 // the running composited animations which didn't change state during
2623 // above UpdateAnimations() but associated with new paint property nodes.
2624 if (needed_update) {
2625 auto* root_layer = RootCcLayer();
2626 if (root_layer && root_layer->layer_tree_host()) {
2627 root_layer->layer_tree_host()
2628 ->mutator_host()
2629 ->InitClientAnimationState();
2630 }
2631 }
2632
2633 // Notify the controller that the artifact has been pushed and some
2634 // lifecycle state can be freed (such as raster invalidations).
2635 if (paint_controller_)
2636 paint_controller_->FinishCycle();
2637
2638 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2639 // Property tree changed state is typically cleared through
2640 // |PaintController::FinishCycle| but that will be a no-op because
2641 // the paint controller is transient, so force the changed state to be
2642 // cleared here.
2643 if (paint_controller_) {
2644 paint_controller_->ClearPropertyTreeChangedStateTo(
2645 PropertyTreeState::Root());
2646 }
2647 auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
2648 if (root) {
2649 ForAllGraphicsLayers(*root, [](GraphicsLayer& layer) {
2650 if (layer.PaintsContentOrHitTest() && layer.HasLayerState()) {
2651 layer.GetPaintController().ClearPropertyTreeChangedStateTo(
2652 layer.GetPropertyTreeState());
2653 }
2654 });
2655 }
2656 }
2657 }
2658 }
2659
RunAccessibilityLifecyclePhase(DocumentLifecycle::LifecycleState target_state)2660 bool LocalFrameView::RunAccessibilityLifecyclePhase(
2661 DocumentLifecycle::LifecycleState target_state) {
2662 TRACE_EVENT0("blink,benchmark",
2663 "LocalFrameView::RunAccessibilityLifecyclePhase");
2664 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2665 if (AXObjectCache* cache = frame_view.ExistingAXObjectCache()) {
2666 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInAccessibility);
2667 cache->ProcessDeferredAccessibilityEvents(
2668 *frame_view.GetFrame().GetDocument());
2669 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kAccessibilityClean);
2670 }
2671 });
2672
2673 return target_state > DocumentLifecycle::kAccessibilityClean;
2674 }
2675
EnqueueScrollAnchoringAdjustment(ScrollableArea * scrollable_area)2676 void LocalFrameView::EnqueueScrollAnchoringAdjustment(
2677 ScrollableArea* scrollable_area) {
2678 anchoring_adjustment_queue_.insert(scrollable_area);
2679 }
2680
DequeueScrollAnchoringAdjustment(ScrollableArea * scrollable_area)2681 void LocalFrameView::DequeueScrollAnchoringAdjustment(
2682 ScrollableArea* scrollable_area) {
2683 anchoring_adjustment_queue_.erase(scrollable_area);
2684 }
2685
SetNeedsEnqueueScrollEvent(PaintLayerScrollableArea * scrollable_area)2686 void LocalFrameView::SetNeedsEnqueueScrollEvent(
2687 PaintLayerScrollableArea* scrollable_area) {
2688 scroll_event_queue_.insert(scrollable_area);
2689 GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
2690 }
2691
PerformScrollAnchoringAdjustments()2692 void LocalFrameView::PerformScrollAnchoringAdjustments() {
2693 // Adjust() will cause a scroll which could end up causing a layout and
2694 // reentering this method. Copy and clear the queue so we don't modify it
2695 // during iteration.
2696 AnchoringAdjustmentQueue queue_copy = anchoring_adjustment_queue_;
2697 anchoring_adjustment_queue_.clear();
2698
2699 for (const WeakMember<ScrollableArea>& scroller : queue_copy) {
2700 if (scroller) {
2701 DCHECK(scroller->GetScrollAnchor());
2702 scroller->GetScrollAnchor()->Adjust();
2703 }
2704 }
2705 }
2706
EnqueueScrollEvents()2707 void LocalFrameView::EnqueueScrollEvents() {
2708 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2709 for (const WeakMember<PaintLayerScrollableArea>& scroller :
2710 frame_view.scroll_event_queue_) {
2711 if (scroller)
2712 scroller->EnqueueScrollEventIfNeeded();
2713 }
2714 frame_view.scroll_event_queue_.clear();
2715 });
2716 }
2717
2718 template <typename MainLayerFunction, typename ContentsLayerFunction>
ForAllDrawableGraphicsLayers(const GraphicsLayer * layer,const MainLayerFunction & main_layer_function,const ContentsLayerFunction & contents_layer_function)2719 static void ForAllDrawableGraphicsLayers(
2720 const GraphicsLayer* layer,
2721 const MainLayerFunction& main_layer_function,
2722 const ContentsLayerFunction& contents_layer_function) {
2723 if (!layer || layer->Client().ShouldThrottleRendering() ||
2724 layer->Client().IsUnderSVGHiddenContainer()) {
2725 return;
2726 }
2727
2728 if (layer->Client().PaintBlockedByDisplayLockIncludingAncestors(
2729 DisplayLockContextLifecycleTarget::kSelf)) {
2730 // If we skip the layer, then we need to ensure to notify the
2731 // display-lock, since we need to force recollect the layers when we commit.
2732 layer->Client().NotifyDisplayLockNeedsGraphicsLayerCollection();
2733 return;
2734 }
2735
2736 // We need to collect all layers that draw content, as well as some layers
2737 // that don't for the purposes of hit testing. For example, an empty div
2738 // will not draw content but needs to create a layer to ensure scroll events
2739 // do not pass through it.
2740 if (layer->PaintsContentOrHitTest() || layer->GetHitTestable())
2741 main_layer_function(layer);
2742
2743 if (auto* contents_layer = layer->ContentsLayer())
2744 contents_layer_function(layer, contents_layer);
2745
2746 for (const auto* child : layer->Children()) {
2747 ForAllDrawableGraphicsLayers(child, main_layer_function,
2748 contents_layer_function);
2749 }
2750 ForAllDrawableGraphicsLayers(layer->MaskLayer(), main_layer_function,
2751 contents_layer_function);
2752 }
2753
CollectDrawableLayersForLayerListRecursively(GraphicsContext & context,const GraphicsLayer * root)2754 static void CollectDrawableLayersForLayerListRecursively(
2755 GraphicsContext& context,
2756 const GraphicsLayer* root) {
2757 ForAllDrawableGraphicsLayers(
2758 root,
2759 [&](const GraphicsLayer* layer) { RecordGraphicsLayer(context, *layer); },
2760 [&](const GraphicsLayer* layer, cc::Layer* contents_layer) {
2761 RecordForeignLayer(
2762 context, *layer, DisplayItem::kForeignLayerContentsWrapper,
2763 contents_layer,
2764 FloatPoint(layer->GetContentsOffsetFromTransformNode()),
2765 &layer->GetContentsPropertyTreeState());
2766 });
2767 }
2768
UpdateLayerDebugInfoRecursively(const GraphicsLayer * root)2769 static void UpdateLayerDebugInfoRecursively(const GraphicsLayer* root) {
2770 ForAllDrawableGraphicsLayers(
2771 root,
2772 [](const GraphicsLayer* layer) {
2773 PaintArtifactCompositor::UpdateLayerDebugInfo(
2774 layer->CcLayer(),
2775 PaintChunk::Id(*layer, DisplayItem::kGraphicsLayerWrapper),
2776 layer->GetCompositingReasons(),
2777 layer->GetRasterInvalidationTracking());
2778 },
2779 [](const GraphicsLayer* layer, cc::Layer* contents_layer) {
2780 PaintArtifactCompositor::UpdateLayerDebugInfo(
2781 contents_layer,
2782 PaintChunk::Id(*layer, DisplayItem::kForeignLayerContentsWrapper),
2783 layer->GetCompositingReasons(), nullptr);
2784 });
2785 }
2786
PaintGraphicsLayerRecursively(GraphicsLayer * layer)2787 static bool PaintGraphicsLayerRecursively(GraphicsLayer* layer) {
2788 bool painted = layer->PaintRecursively();
2789 #if DCHECK_IS_ON()
2790 VerboseLogGraphicsLayerTree(layer);
2791 #endif
2792 return painted;
2793 }
2794
PaintTree()2795 void LocalFrameView::PaintTree() {
2796 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
2797 LocalFrameUkmAggregator::kPaint);
2798
2799 DCHECK(GetFrame().IsLocalRoot());
2800
2801 auto* layout_view = GetLayoutView();
2802 DCHECK(layout_view);
2803 paint_frame_count_++;
2804 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2805 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
2806 });
2807
2808 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2809 if (!paint_controller_)
2810 paint_controller_ = std::make_unique<PaintController>();
2811
2812 // TODO(crbug.com/917911): Painting of overlays should not force repainting
2813 // of the frame contents.
2814 auto* web_local_frame_impl = WebLocalFrameImpl::FromFrame(frame_);
2815 bool has_dev_tools_overlays =
2816 web_local_frame_impl && web_local_frame_impl->HasDevToolsOverlays();
2817 if (!GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint() &&
2818 !visual_viewport_needs_repaint_ && !has_dev_tools_overlays) {
2819 paint_controller_->UpdateUMACountsOnFullyCached();
2820 } else {
2821 GraphicsContext graphics_context(*paint_controller_);
2822 if (Settings* settings = frame_->GetSettings()) {
2823 graphics_context.SetDarkMode(
2824 BuildDarkModeSettings(*settings, *GetLayoutView()));
2825 }
2826
2827 PaintInternal(graphics_context, kGlobalPaintNormalPhase,
2828 CullRect::Infinite());
2829
2830 GetPage()->GetLinkHighlight().Paint(graphics_context);
2831
2832 GetPage()->GetValidationMessageClient().PaintOverlay(graphics_context);
2833 ForAllNonThrottledLocalFrameViews(
2834 [&graphics_context](LocalFrameView& view) {
2835 view.frame_->PaintFrameColorOverlay(graphics_context);
2836 });
2837
2838 // Devtools overlays query the inspected page's paint data so this update
2839 // needs to be after other paintings.
2840 if (has_dev_tools_overlays)
2841 web_local_frame_impl->PaintDevToolsOverlays(graphics_context);
2842
2843 if (frame_->IsMainFrame()) {
2844 frame_->GetPage()->GetVisualViewport().Paint(graphics_context);
2845 visual_viewport_needs_repaint_ = false;
2846 } else {
2847 DCHECK(!visual_viewport_needs_repaint_);
2848 }
2849
2850 paint_controller_->CommitNewDisplayItems();
2851 }
2852 } else {
2853 // A null graphics layer can occur for painting of SVG images that are not
2854 // parented into the main frame tree, or when the LocalFrameView is the main
2855 // frame view of a page overlay. The page overlay is in the layer tree of
2856 // the host page and will be painted during painting of the host page.
2857 if (GraphicsLayer* root_graphics_layer =
2858 layout_view->Compositor()->PaintRootGraphicsLayer()) {
2859 bool painted = PaintGraphicsLayerRecursively(root_graphics_layer);
2860 if (painted) {
2861 // If the painted result changed, the recorded hit test data may have
2862 // changed which will affect the mapped hit test geometry.
2863 if (GetScrollingCoordinator())
2864 GetScrollingCoordinator()->NotifyGeometryChanged(this);
2865 }
2866 }
2867 }
2868
2869 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
2870 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
2871 if (auto* layout_view = frame_view.GetLayoutView())
2872 layout_view->Layer()->ClearNeedsRepaintRecursively();
2873 frame_view.GetPaintTimingDetector().NotifyPaintFinished();
2874 });
2875
2876 PaintController::ReportUMACounts();
2877 }
2878
RootCcLayer() const2879 const cc::Layer* LocalFrameView::RootCcLayer() const {
2880 return paint_artifact_compositor_ ? paint_artifact_compositor_->RootLayer()
2881 : nullptr;
2882 }
2883
PushPaintArtifactToCompositor()2884 void LocalFrameView::PushPaintArtifactToCompositor() {
2885 TRACE_EVENT0("blink", "LocalFrameView::pushPaintArtifactToCompositor");
2886 if (!frame_->GetSettings()->GetAcceleratedCompositingEnabled())
2887 return;
2888
2889 Page* page = GetFrame().GetPage();
2890 if (!page)
2891 return;
2892
2893 if (!paint_artifact_compositor_) {
2894 paint_artifact_compositor_ = std::make_unique<PaintArtifactCompositor>(
2895 page->GetScrollingCoordinator()->GetWeakPtr());
2896 page->GetChromeClient().AttachRootLayer(
2897 paint_artifact_compositor_->RootLayer(), &GetFrame());
2898 }
2899
2900 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
2901 LocalFrameUkmAggregator::kCompositingCommit);
2902
2903 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
2904 layer_debug_info_enabled_) {
2905 UpdateLayerDebugInfoRecursively(
2906 GetLayoutView()->Compositor()->PaintRootGraphicsLayer());
2907 }
2908
2909 // Skip updating property trees, pushing cc::Layers, and issuing raster
2910 // invalidations if possible.
2911 if (!paint_artifact_compositor_->NeedsUpdate()) {
2912 DCHECK(paint_controller_);
2913 return;
2914 }
2915
2916 paint_artifact_compositor_->SetLayerDebugInfoEnabled(
2917 layer_debug_info_enabled_);
2918
2919 PaintArtifactCompositor::ViewportProperties viewport_properties;
2920 if (GetFrame().IsMainFrame()) {
2921 const auto& viewport = page->GetVisualViewport();
2922 viewport_properties.overscroll_elasticity_transform =
2923 viewport.GetOverscrollElasticityTransformNode();
2924 viewport_properties.page_scale = viewport.GetPageScaleNode();
2925
2926 if (const auto* root_scroller =
2927 GetPage()->GlobalRootScrollerController().GlobalRootScroller()) {
2928 if (const auto* layout_object = root_scroller->GetLayoutObject()) {
2929 if (const auto* paint_properties =
2930 layout_object->FirstFragment().PaintProperties()) {
2931 if (paint_properties->Scroll()) {
2932 viewport_properties.outer_clip = paint_properties->OverflowClip();
2933 viewport_properties.outer_scroll_translation =
2934 paint_properties->ScrollTranslation();
2935 viewport_properties.inner_scroll_translation =
2936 viewport.GetScrollTranslationNode();
2937 }
2938 }
2939 }
2940 }
2941 }
2942
2943 PaintArtifactCompositor::Settings settings;
2944 settings.prefer_compositing_to_lcd_text =
2945 page->GetSettings().GetPreferCompositingToLCDTextEnabled();
2946
2947 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
2948 (!paint_controller_ || visual_viewport_needs_repaint_)) {
2949 // Before CompositeAfterPaint, we need a transient PaintController to
2950 // collect the foreign layers, and this doesn't need caching. This shouldn't
2951 // affect caching status of DisplayItemClients because FinishCycle() is
2952 // not synchronized with other PaintControllers. This may live across frame
2953 // updates until SetForeignLayerListNeedsUpdate() is called.
2954 paint_controller_ =
2955 std::make_unique<PaintController>(PaintController::kTransient);
2956
2957 GraphicsContext context(*paint_controller_);
2958 auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
2959 CollectDrawableLayersForLayerListRecursively(context, root);
2960
2961 if (frame_->IsMainFrame()) {
2962 if (root == GetLayoutView()->Compositor()->RootGraphicsLayer())
2963 frame_->GetPage()->GetVisualViewport().Paint(context);
2964 visual_viewport_needs_repaint_ = false;
2965 } else {
2966 DCHECK(!visual_viewport_needs_repaint_);
2967 }
2968
2969 // Link highlights paint after all other layers.
2970 page->GetLinkHighlight().Paint(context);
2971
2972 paint_controller_->CommitNewDisplayItems();
2973 }
2974
2975 paint_artifact_compositor_->Update(
2976 paint_controller_->GetPaintArtifactShared(), viewport_properties,
2977 settings);
2978
2979 probe::LayerTreePainted(&GetFrame());
2980 }
2981
CompositedLayersAsJSON(LayerTreeFlags flags)2982 std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON(
2983 LayerTreeFlags flags) {
2984 auto* root_frame_view = GetFrame().LocalFrameRoot().View();
2985 if (root_frame_view->GetPaintController()) {
2986 return root_frame_view->paint_artifact_compositor_->GetLayersAsJSON(
2987 flags, &root_frame_view->GetPaintController()->GetPaintArtifact());
2988 } else {
2989 return std::make_unique<JSONObject>();
2990 }
2991 }
2992
UpdateStyleAndLayoutIfNeededRecursive()2993 void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
2994 if (ShouldThrottleRendering() || !frame_->GetDocument()->IsActive())
2995 return;
2996
2997 ScopedFrameBlamer frame_blamer(frame_);
2998 TRACE_EVENT0("blink,benchmark",
2999 "LocalFrameView::updateStyleAndLayoutIfNeededRecursive");
3000
3001 // We have to crawl our entire subtree looking for any FrameViews that need
3002 // layout and make sure they are up to date.
3003 // Mac actually tests for intersection with the dirty region and tries not to
3004 // update layout for frames that are outside the dirty region. Not only does
3005 // this seem pointless (since those frames will have set a zero timer to
3006 // layout anyway), but it is also incorrect, since if two frames overlap, the
3007 // first could be excluded from the dirty region but then become included
3008 // later by the second frame adding rects to the dirty region when it lays
3009 // out.
3010
3011 {
3012 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
3013 LocalFrameUkmAggregator::kStyle);
3014 frame_->GetDocument()->UpdateStyleAndLayoutTree();
3015
3016 // Update style for all embedded SVG documents underneath this frame, so
3017 // that intrinsic size computation for any embedded objects has up-to-date
3018 // information before layout.
3019 ForAllChildLocalFrameViews([](LocalFrameView& view) {
3020 Document& document = *view.GetFrame().GetDocument();
3021 if (document.IsSVGDocument())
3022 document.UpdateStyleAndLayoutTree();
3023 });
3024 }
3025
3026 CHECK(!ShouldThrottleRendering());
3027 CHECK(frame_->GetDocument()->IsActive());
3028 CHECK(!nested_layout_count_);
3029
3030 if (NeedsLayout()) {
3031 SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
3032 LocalFrameUkmAggregator::kLayout);
3033 UpdateLayout();
3034 } else {
3035 UpdateGeometriesIfNeeded();
3036 }
3037
3038 CheckDoesNotNeedLayout();
3039
3040 // WebView plugins need to update regardless of whether the
3041 // LayoutEmbeddedObject that owns them needed layout.
3042 // TODO(schenney): This currently runs the entire lifecycle on plugin
3043 // WebViews. We should have a way to only run these other Documents to the
3044 // same lifecycle stage as this frame.
3045 for (const auto& plugin : plugins_) {
3046 plugin->UpdateAllLifecyclePhases();
3047 }
3048 CheckDoesNotNeedLayout();
3049
3050 // FIXME: Calling layout() shouldn't trigger script execution or have any
3051 // observable effects on the frame tree but we're not quite there yet.
3052 HeapVector<Member<LocalFrameView>> frame_views;
3053 for (Frame* child = frame_->Tree().FirstChild(); child;
3054 child = child->Tree().NextSibling()) {
3055 auto* child_local_frame = DynamicTo<LocalFrame>(child);
3056 if (!child_local_frame)
3057 continue;
3058 if (LocalFrameView* view = child_local_frame->View())
3059 frame_views.push_back(view);
3060 }
3061
3062 for (const auto& frame_view : frame_views)
3063 frame_view->UpdateStyleAndLayoutIfNeededRecursive();
3064
3065 // These asserts ensure that parent frames are clean, when child frames
3066 // finished updating layout and style.
3067 // TODO(szager): this is the last call to CheckDoesNotNeedLayout during the
3068 // lifecycle code, but it can happen that NeedsLayout() becomes true after
3069 // this point, even while the document lifecycle proceeds to kLayoutClean
3070 // and beyond. Figure out how this happens, and do something sensible.
3071 CheckDoesNotNeedLayout();
3072 #if DCHECK_IS_ON()
3073 frame_->GetDocument()->GetLayoutView()->AssertLaidOut();
3074 #endif
3075
3076 if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
3077 Lifecycle().AdvanceTo(DocumentLifecycle::kLayoutClean);
3078
3079 // If we're restoring a scroll position from history, that takes precedence
3080 // over scrolling to the anchor in the URL.
3081 frame_->GetDocument()->ApplyScrollRestorationLogic();
3082
3083 // Ensure that we become visually non-empty eventually.
3084 // TODO(esprehn): This should check isRenderingReady() instead.
3085 if (GetFrame().GetDocument()->HasFinishedParsing() &&
3086 GetFrame().Loader().StateMachine()->CommittedFirstRealDocumentLoad())
3087 is_visually_non_empty_ = true;
3088
3089 GetFrame().Selection().UpdateStyleAndLayoutIfNeeded();
3090 GetFrame().GetPage()->GetDragCaret().UpdateStyleAndLayoutIfNeeded();
3091 }
3092
EnableAutoSizeMode(const IntSize & min_size,const IntSize & max_size)3093 void LocalFrameView::EnableAutoSizeMode(const IntSize& min_size,
3094 const IntSize& max_size) {
3095 if (!auto_size_info_)
3096 auto_size_info_ = MakeGarbageCollected<FrameViewAutoSizeInfo>(this);
3097
3098 auto_size_info_->ConfigureAutoSizeMode(min_size, max_size);
3099 SetLayoutSizeFixedToFrameSize(true);
3100 SetNeedsLayout();
3101 ScheduleRelayout();
3102 }
3103
DisableAutoSizeMode()3104 void LocalFrameView::DisableAutoSizeMode() {
3105 if (!auto_size_info_)
3106 return;
3107
3108 SetLayoutSizeFixedToFrameSize(false);
3109 SetNeedsLayout();
3110 ScheduleRelayout();
3111
3112 // Since autosize mode forces the scrollbar mode, change them to being auto.
3113 GetLayoutView()->SetAutosizeScrollbarModes(
3114 mojom::blink::ScrollbarMode::kAuto, mojom::blink::ScrollbarMode::kAuto);
3115 auto_size_info_.Clear();
3116 }
3117
ForceLayoutForPagination(const FloatSize & page_size,const FloatSize & original_page_size,float maximum_shrink_factor)3118 void LocalFrameView::ForceLayoutForPagination(
3119 const FloatSize& page_size,
3120 const FloatSize& original_page_size,
3121 float maximum_shrink_factor) {
3122 // Dumping externalRepresentation(m_frame->layoutObject()).ascii() is a good
3123 // trick to see the state of things before and after the layout
3124 if (LayoutView* layout_view = this->GetLayoutView()) {
3125 float page_logical_width = layout_view->StyleRef().IsHorizontalWritingMode()
3126 ? page_size.Width()
3127 : page_size.Height();
3128 float page_logical_height =
3129 layout_view->StyleRef().IsHorizontalWritingMode() ? page_size.Height()
3130 : page_size.Width();
3131
3132 LayoutUnit floored_page_logical_width =
3133 static_cast<LayoutUnit>(page_logical_width);
3134 LayoutUnit floored_page_logical_height =
3135 static_cast<LayoutUnit>(page_logical_height);
3136 layout_view->SetLogicalWidth(floored_page_logical_width);
3137 layout_view->SetPageLogicalHeight(floored_page_logical_height);
3138 layout_view->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
3139 layout_invalidation_reason::kPrintingChanged);
3140 UpdateLayout();
3141
3142 // If we don't fit in the given page width, we'll lay out again. If we don't
3143 // fit in the page width when shrunk, we will lay out at maximum shrink and
3144 // clip extra content.
3145 // FIXME: We are assuming a shrink-to-fit printing implementation. A
3146 // cropping implementation should not do this!
3147 bool horizontal_writing_mode =
3148 layout_view->StyleRef().IsHorizontalWritingMode();
3149 PhysicalRect document_rect(layout_view->DocumentRect());
3150 LayoutUnit doc_logical_width = horizontal_writing_mode
3151 ? document_rect.Width()
3152 : document_rect.Height();
3153 if (doc_logical_width > page_logical_width) {
3154 // ResizePageRectsKeepingRatio would truncate the expected page size,
3155 // while we want it rounded -- so make sure it's rounded here.
3156 FloatSize expected_page_size(
3157 std::min<float>(document_rect.Width().Round(),
3158 page_size.Width() * maximum_shrink_factor),
3159 std::min<float>(document_rect.Height().Round(),
3160 page_size.Height() * maximum_shrink_factor));
3161 FloatSize max_page_size = frame_->ResizePageRectsKeepingRatio(
3162 FloatSize(original_page_size.Width(), original_page_size.Height()),
3163 expected_page_size);
3164 page_logical_width = horizontal_writing_mode ? max_page_size.Width()
3165 : max_page_size.Height();
3166 page_logical_height = horizontal_writing_mode ? max_page_size.Height()
3167 : max_page_size.Width();
3168
3169 floored_page_logical_width = static_cast<LayoutUnit>(page_logical_width);
3170 floored_page_logical_height =
3171 static_cast<LayoutUnit>(page_logical_height);
3172 layout_view->SetLogicalWidth(floored_page_logical_width);
3173 layout_view->SetPageLogicalHeight(floored_page_logical_height);
3174 layout_view
3175 ->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
3176 layout_invalidation_reason::kPrintingChanged);
3177 UpdateLayout();
3178
3179 PhysicalRect updated_document_rect(layout_view->DocumentRect());
3180 LayoutUnit doc_logical_height = horizontal_writing_mode
3181 ? updated_document_rect.Height()
3182 : updated_document_rect.Width();
3183 LayoutUnit doc_logical_top = horizontal_writing_mode
3184 ? updated_document_rect.Y()
3185 : updated_document_rect.X();
3186 LayoutUnit doc_logical_right = horizontal_writing_mode
3187 ? updated_document_rect.Right()
3188 : updated_document_rect.Bottom();
3189 LayoutUnit clipped_logical_left;
3190 if (!layout_view->StyleRef().IsLeftToRightDirection()) {
3191 clipped_logical_left =
3192 LayoutUnit(doc_logical_right - page_logical_width);
3193 }
3194 LayoutRect overflow(clipped_logical_left, doc_logical_top,
3195 LayoutUnit(page_logical_width), doc_logical_height);
3196
3197 if (!horizontal_writing_mode)
3198 overflow = overflow.TransposedRect();
3199 AdjustViewSizeAndLayout();
3200 // This is how we clip in case we overflow again.
3201 layout_view->ClearLayoutOverflow();
3202 layout_view->AddLayoutOverflow(overflow);
3203 return;
3204 }
3205 }
3206
3207 if (TextAutosizer* text_autosizer = frame_->GetDocument()->GetTextAutosizer())
3208 text_autosizer->UpdatePageInfo();
3209 AdjustViewSizeAndLayout();
3210 }
3211
ConvertFromLayoutObject(const LayoutObject & layout_object,const IntRect & layout_object_rect) const3212 IntRect LocalFrameView::ConvertFromLayoutObject(
3213 const LayoutObject& layout_object,
3214 const IntRect& layout_object_rect) const {
3215 // Convert from page ("absolute") to LocalFrameView coordinates.
3216 return PixelSnappedIntRect(
3217 layout_object.LocalToAbsoluteRect(PhysicalRect(layout_object_rect)));
3218 }
3219
ConvertToLayoutObject(const LayoutObject & layout_object,const IntRect & frame_rect) const3220 IntRect LocalFrameView::ConvertToLayoutObject(const LayoutObject& layout_object,
3221 const IntRect& frame_rect) const {
3222 return PixelSnappedIntRect(
3223 layout_object.AbsoluteToLocalRect(PhysicalRect(frame_rect)));
3224 }
3225
ConvertFromLayoutObject(const LayoutObject & layout_object,const IntPoint & layout_object_point) const3226 IntPoint LocalFrameView::ConvertFromLayoutObject(
3227 const LayoutObject& layout_object,
3228 const IntPoint& layout_object_point) const {
3229 return RoundedIntPoint(ConvertFromLayoutObject(
3230 layout_object, PhysicalOffset(layout_object_point)));
3231 }
3232
ConvertToLayoutObject(const LayoutObject & layout_object,const IntPoint & frame_point) const3233 IntPoint LocalFrameView::ConvertToLayoutObject(
3234 const LayoutObject& layout_object,
3235 const IntPoint& frame_point) const {
3236 return RoundedIntPoint(
3237 ConvertToLayoutObject(layout_object, PhysicalOffset(frame_point)));
3238 }
3239
ConvertFromLayoutObject(const LayoutObject & layout_object,const PhysicalOffset & layout_object_offset) const3240 PhysicalOffset LocalFrameView::ConvertFromLayoutObject(
3241 const LayoutObject& layout_object,
3242 const PhysicalOffset& layout_object_offset) const {
3243 return layout_object.LocalToAbsolutePoint(layout_object_offset);
3244 }
3245
ConvertToLayoutObject(const LayoutObject & layout_object,const PhysicalOffset & frame_offset) const3246 PhysicalOffset LocalFrameView::ConvertToLayoutObject(
3247 const LayoutObject& layout_object,
3248 const PhysicalOffset& frame_offset) const {
3249 return PhysicalOffset::FromFloatPointRound(
3250 ConvertToLayoutObject(layout_object, FloatPoint(frame_offset)));
3251 }
3252
ConvertToLayoutObject(const LayoutObject & layout_object,const FloatPoint & frame_point) const3253 FloatPoint LocalFrameView::ConvertToLayoutObject(
3254 const LayoutObject& layout_object,
3255 const FloatPoint& frame_point) const {
3256 return layout_object.AbsoluteToLocalFloatPoint(frame_point);
3257 }
3258
ConvertSelfToChild(const EmbeddedContentView & child,const IntPoint & point) const3259 IntPoint LocalFrameView::ConvertSelfToChild(const EmbeddedContentView& child,
3260 const IntPoint& point) const {
3261 IntPoint new_point(point);
3262 new_point.MoveBy(-child.Location());
3263 return new_point;
3264 }
3265
RootFrameToDocument(const IntRect & rect_in_root_frame)3266 IntRect LocalFrameView::RootFrameToDocument(const IntRect& rect_in_root_frame) {
3267 IntPoint offset = RootFrameToDocument(rect_in_root_frame.Location());
3268 IntRect local_rect = rect_in_root_frame;
3269 local_rect.SetLocation(offset);
3270 return local_rect;
3271 }
3272
RootFrameToDocument(const IntPoint & point_in_root_frame)3273 IntPoint LocalFrameView::RootFrameToDocument(
3274 const IntPoint& point_in_root_frame) {
3275 return FlooredIntPoint(RootFrameToDocument(FloatPoint(point_in_root_frame)));
3276 }
3277
RootFrameToDocument(const FloatPoint & point_in_root_frame)3278 FloatPoint LocalFrameView::RootFrameToDocument(
3279 const FloatPoint& point_in_root_frame) {
3280 ScrollableArea* layout_viewport = LayoutViewport();
3281 if (!layout_viewport)
3282 return point_in_root_frame;
3283
3284 FloatPoint local_frame = ConvertFromRootFrame(point_in_root_frame);
3285 return local_frame + layout_viewport->GetScrollOffset();
3286 }
3287
DocumentToFrame(const IntRect & rect_in_document) const3288 IntRect LocalFrameView::DocumentToFrame(const IntRect& rect_in_document) const {
3289 IntRect rect_in_frame = rect_in_document;
3290 rect_in_frame.SetLocation(DocumentToFrame(rect_in_document.Location()));
3291 return rect_in_frame;
3292 }
3293
DocumentToFrame(const DoublePoint & point_in_document) const3294 DoublePoint LocalFrameView::DocumentToFrame(
3295 const DoublePoint& point_in_document) const {
3296 ScrollableArea* layout_viewport = LayoutViewport();
3297 if (!layout_viewport)
3298 return point_in_document;
3299
3300 return point_in_document - layout_viewport->GetScrollOffset();
3301 }
3302
DocumentToFrame(const IntPoint & point_in_document) const3303 IntPoint LocalFrameView::DocumentToFrame(
3304 const IntPoint& point_in_document) const {
3305 return FlooredIntPoint(DocumentToFrame(DoublePoint(point_in_document)));
3306 }
3307
DocumentToFrame(const FloatPoint & point_in_document) const3308 FloatPoint LocalFrameView::DocumentToFrame(
3309 const FloatPoint& point_in_document) const {
3310 return FloatPoint(DocumentToFrame(DoublePoint(point_in_document)));
3311 }
3312
DocumentToFrame(const PhysicalOffset & offset_in_document) const3313 PhysicalOffset LocalFrameView::DocumentToFrame(
3314 const PhysicalOffset& offset_in_document) const {
3315 ScrollableArea* layout_viewport = LayoutViewport();
3316 if (!layout_viewport)
3317 return offset_in_document;
3318
3319 return offset_in_document -
3320 PhysicalOffset::FromFloatSizeRound(layout_viewport->GetScrollOffset());
3321 }
3322
DocumentToFrame(const PhysicalRect & rect_in_document) const3323 PhysicalRect LocalFrameView::DocumentToFrame(
3324 const PhysicalRect& rect_in_document) const {
3325 return PhysicalRect(DocumentToFrame(rect_in_document.offset),
3326 rect_in_document.size);
3327 }
3328
FrameToDocument(const IntPoint & point_in_frame) const3329 IntPoint LocalFrameView::FrameToDocument(const IntPoint& point_in_frame) const {
3330 return FlooredIntPoint(FrameToDocument(PhysicalOffset(point_in_frame)));
3331 }
3332
FrameToDocument(const PhysicalOffset & offset_in_frame) const3333 PhysicalOffset LocalFrameView::FrameToDocument(
3334 const PhysicalOffset& offset_in_frame) const {
3335 ScrollableArea* layout_viewport = LayoutViewport();
3336 if (!layout_viewport)
3337 return offset_in_frame;
3338
3339 return offset_in_frame +
3340 PhysicalOffset::FromFloatSizeRound(layout_viewport->GetScrollOffset());
3341 }
3342
FrameToDocument(const IntRect & rect_in_frame) const3343 IntRect LocalFrameView::FrameToDocument(const IntRect& rect_in_frame) const {
3344 return IntRect(FrameToDocument(rect_in_frame.Location()),
3345 rect_in_frame.Size());
3346 }
3347
FrameToDocument(const PhysicalRect & rect_in_frame) const3348 PhysicalRect LocalFrameView::FrameToDocument(
3349 const PhysicalRect& rect_in_frame) const {
3350 return PhysicalRect(FrameToDocument(rect_in_frame.offset),
3351 rect_in_frame.size);
3352 }
3353
ConvertToContainingEmbeddedContentView(const IntRect & local_rect) const3354 IntRect LocalFrameView::ConvertToContainingEmbeddedContentView(
3355 const IntRect& local_rect) const {
3356 if (LocalFrameView* parent = ParentFrameView()) {
3357 auto* layout_object = GetLayoutEmbeddedContent();
3358 if (!layout_object)
3359 return local_rect;
3360
3361 IntRect rect(local_rect);
3362 // Add borders and padding
3363 rect.Move(
3364 (layout_object->BorderLeft() + layout_object->PaddingLeft()).ToInt(),
3365 (layout_object->BorderTop() + layout_object->PaddingTop()).ToInt());
3366 return parent->ConvertFromLayoutObject(*layout_object, rect);
3367 }
3368
3369 return local_rect;
3370 }
3371
ConvertFromContainingEmbeddedContentView(const IntRect & parent_rect) const3372 IntRect LocalFrameView::ConvertFromContainingEmbeddedContentView(
3373 const IntRect& parent_rect) const {
3374 if (LocalFrameView* parent = ParentFrameView()) {
3375 IntRect local_rect = parent_rect;
3376 local_rect.SetLocation(
3377 parent->ConvertSelfToChild(*this, local_rect.Location()));
3378 return local_rect;
3379 }
3380
3381 return parent_rect;
3382 }
3383
ConvertToContainingEmbeddedContentView(const PhysicalOffset & local_offset) const3384 PhysicalOffset LocalFrameView::ConvertToContainingEmbeddedContentView(
3385 const PhysicalOffset& local_offset) const {
3386 if (LocalFrameView* parent = ParentFrameView()) {
3387 auto* layout_object = GetLayoutEmbeddedContent();
3388 if (!layout_object)
3389 return local_offset;
3390
3391 PhysicalOffset point(local_offset);
3392
3393 // Add borders and padding
3394 point += PhysicalOffset(
3395 layout_object->BorderLeft() + layout_object->PaddingLeft(),
3396 layout_object->BorderTop() + layout_object->PaddingTop());
3397 return parent->ConvertFromLayoutObject(*layout_object, point);
3398 }
3399
3400 return local_offset;
3401 }
3402
ConvertToContainingEmbeddedContentView(const FloatPoint & local_point) const3403 FloatPoint LocalFrameView::ConvertToContainingEmbeddedContentView(
3404 const FloatPoint& local_point) const {
3405 if (ParentFrameView()) {
3406 auto* layout_object = GetLayoutEmbeddedContent();
3407 if (!layout_object)
3408 return local_point;
3409
3410 PhysicalOffset point = PhysicalOffset::FromFloatPointRound(local_point);
3411
3412 // Add borders and padding
3413 point.left += layout_object->BorderLeft() + layout_object->PaddingLeft();
3414 point.top += layout_object->BorderTop() + layout_object->PaddingTop();
3415 return FloatPoint(layout_object->LocalToAbsolutePoint(point));
3416 }
3417
3418 return local_point;
3419 }
3420
ConvertFromContainingEmbeddedContentView(const PhysicalOffset & parent_offset) const3421 PhysicalOffset LocalFrameView::ConvertFromContainingEmbeddedContentView(
3422 const PhysicalOffset& parent_offset) const {
3423 return PhysicalOffset::FromFloatPointRound(
3424 ConvertFromContainingEmbeddedContentView(FloatPoint(parent_offset)));
3425 }
3426
ConvertFromContainingEmbeddedContentView(const FloatPoint & parent_point) const3427 FloatPoint LocalFrameView::ConvertFromContainingEmbeddedContentView(
3428 const FloatPoint& parent_point) const {
3429 return FloatPoint(
3430 ConvertFromContainingEmbeddedContentView(DoublePoint(parent_point)));
3431 }
3432
ConvertFromContainingEmbeddedContentView(const DoublePoint & parent_point) const3433 DoublePoint LocalFrameView::ConvertFromContainingEmbeddedContentView(
3434 const DoublePoint& parent_point) const {
3435 if (LocalFrameView* parent = ParentFrameView()) {
3436 // Get our layoutObject in the parent view
3437 auto* layout_object = GetLayoutEmbeddedContent();
3438 if (!layout_object)
3439 return parent_point;
3440
3441 DoublePoint point = DoublePoint(parent->ConvertToLayoutObject(
3442 *layout_object, FloatPoint(parent_point)));
3443 // Subtract borders and padding
3444 point.Move(
3445 (-layout_object->BorderLeft() - layout_object->PaddingLeft())
3446 .ToDouble(),
3447 (-layout_object->BorderTop() - layout_object->PaddingTop()).ToDouble());
3448 return point;
3449 }
3450
3451 return parent_point;
3452 }
3453
ConvertToContainingEmbeddedContentView(const IntPoint & local_point) const3454 IntPoint LocalFrameView::ConvertToContainingEmbeddedContentView(
3455 const IntPoint& local_point) const {
3456 return RoundedIntPoint(
3457 ConvertToContainingEmbeddedContentView(PhysicalOffset(local_point)));
3458 }
3459
SetTracksRasterInvalidations(bool track_raster_invalidations)3460 void LocalFrameView::SetTracksRasterInvalidations(
3461 bool track_raster_invalidations) {
3462 if (track_raster_invalidations == is_tracking_raster_invalidations_)
3463 return;
3464
3465 // Ensure the document is up-to-date before tracking invalidations.
3466 UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
3467
3468 for (Frame* frame = &frame_->Tree().Top(); frame;
3469 frame = frame->Tree().TraverseNext()) {
3470 auto* local_frame = DynamicTo<LocalFrame>(frame);
3471 if (!local_frame)
3472 continue;
3473 if (auto* layout_view = local_frame->ContentLayoutObject()) {
3474 is_tracking_raster_invalidations_ = track_raster_invalidations;
3475 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
3476 if (paint_artifact_compositor_) {
3477 paint_artifact_compositor_->SetTracksRasterInvalidations(
3478 track_raster_invalidations);
3479 }
3480 } else {
3481 layout_view->Compositor()->UpdateTrackingRasterInvalidations();
3482 }
3483 }
3484 }
3485
3486 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
3487 "LocalFrameView::setTracksPaintInvalidations",
3488 TRACE_EVENT_SCOPE_GLOBAL, "enabled",
3489 track_raster_invalidations);
3490 }
3491
ScheduleAnimation(base::TimeDelta delay)3492 void LocalFrameView::ScheduleAnimation(base::TimeDelta delay) {
3493 if (auto* client = GetChromeClient())
3494 client->ScheduleAnimation(this, delay);
3495 }
3496
ScrollableAreasDidChange()3497 void LocalFrameView::ScrollableAreasDidChange() {
3498 // Layout may update scrollable area bounding boxes. It also sets the same
3499 // dirty flag making this one redundant (See
3500 // |ScrollingCoordinator::notifyGeometryChanged|).
3501 // So if layout is expected, ignore this call allowing scrolling coordinator
3502 // to be notified post-layout to recompute gesture regions.
3503 // TODO(wjmaclean): It would be nice to move the !NeedsLayout() check from
3504 // here to SetScrollGestureRegionIsDirty(), but at present doing so breaks
3505 // web tests. This suggests that there is something that wants to set the
3506 // dirty bit when layout is needed, and won't re-try setting the bit after
3507 // layout has completed - it would be nice to find that and fix it.
3508 if (!NeedsLayout())
3509 GetScrollingContext()->SetScrollGestureRegionIsDirty(true);
3510 }
3511
AddScrollableArea(PaintLayerScrollableArea * scrollable_area)3512 void LocalFrameView::AddScrollableArea(
3513 PaintLayerScrollableArea* scrollable_area) {
3514 DCHECK(scrollable_area);
3515 if (!scrollable_areas_)
3516 scrollable_areas_ = MakeGarbageCollected<ScrollableAreaSet>();
3517 scrollable_areas_->insert(scrollable_area);
3518
3519 if (GetScrollingCoordinator())
3520 ScrollableAreasDidChange();
3521 }
3522
RemoveScrollableArea(PaintLayerScrollableArea * scrollable_area)3523 void LocalFrameView::RemoveScrollableArea(
3524 PaintLayerScrollableArea* scrollable_area) {
3525 if (!scrollable_areas_)
3526 return;
3527 scrollable_areas_->erase(scrollable_area);
3528
3529 if (GetScrollingCoordinator())
3530 ScrollableAreasDidChange();
3531 }
3532
AddAnimatingScrollableArea(PaintLayerScrollableArea * scrollable_area)3533 void LocalFrameView::AddAnimatingScrollableArea(
3534 PaintLayerScrollableArea* scrollable_area) {
3535 DCHECK(scrollable_area);
3536 if (!animating_scrollable_areas_)
3537 animating_scrollable_areas_ = MakeGarbageCollected<ScrollableAreaSet>();
3538 animating_scrollable_areas_->insert(scrollable_area);
3539 }
3540
RemoveAnimatingScrollableArea(PaintLayerScrollableArea * scrollable_area)3541 void LocalFrameView::RemoveAnimatingScrollableArea(
3542 PaintLayerScrollableArea* scrollable_area) {
3543 if (!animating_scrollable_areas_)
3544 return;
3545 animating_scrollable_areas_->erase(scrollable_area);
3546 }
3547
AttachToLayout()3548 void LocalFrameView::AttachToLayout() {
3549 CHECK(!IsAttached());
3550 if (frame_->GetDocument())
3551 CHECK_NE(Lifecycle().GetState(), DocumentLifecycle::kStopping);
3552 SetAttached(true);
3553 LocalFrameView* parent_view = ParentFrameView();
3554 CHECK(parent_view);
3555 if (parent_view->IsVisible())
3556 SetParentVisible(true);
3557 UpdateRenderThrottlingStatus(IsHiddenForThrottling(),
3558 parent_view->CanThrottleRendering());
3559
3560 // We may have updated paint properties in detached frame subtree for
3561 // printing (see UpdateLifecyclePhasesForPrinting()). The paint properties
3562 // may change after the frame is attached.
3563 if (auto* layout_view = GetLayoutView()) {
3564 layout_view->AddSubtreePaintPropertyUpdateReason(
3565 SubtreePaintPropertyUpdateReason::kPrinting);
3566 }
3567 }
3568
DetachFromLayout()3569 void LocalFrameView::DetachFromLayout() {
3570 CHECK(IsAttached());
3571 SetParentVisible(false);
3572 SetAttached(false);
3573
3574 // We may need update paint properties in detached frame subtree for printing.
3575 // See UpdateLifecyclePhasesForPrinting().
3576 if (auto* layout_view = GetLayoutView()) {
3577 layout_view->AddSubtreePaintPropertyUpdateReason(
3578 SubtreePaintPropertyUpdateReason::kPrinting);
3579 }
3580 }
3581
AddPlugin(WebPluginContainerImpl * plugin)3582 void LocalFrameView::AddPlugin(WebPluginContainerImpl* plugin) {
3583 DCHECK(!plugins_.Contains(plugin));
3584 plugins_.insert(plugin);
3585 }
3586
RemovePlugin(WebPluginContainerImpl * plugin)3587 void LocalFrameView::RemovePlugin(WebPluginContainerImpl* plugin) {
3588 DCHECK(plugins_.Contains(plugin));
3589 plugins_.erase(plugin);
3590 }
3591
RemoveScrollbar(Scrollbar * scrollbar)3592 void LocalFrameView::RemoveScrollbar(Scrollbar* scrollbar) {
3593 DCHECK(scrollbars_.Contains(scrollbar));
3594 scrollbars_.erase(scrollbar);
3595 }
3596
AddScrollbar(Scrollbar * scrollbar)3597 void LocalFrameView::AddScrollbar(Scrollbar* scrollbar) {
3598 DCHECK(!scrollbars_.Contains(scrollbar));
3599 scrollbars_.insert(scrollbar);
3600 }
3601
VisualViewportSuppliesScrollbars()3602 bool LocalFrameView::VisualViewportSuppliesScrollbars() {
3603 // On desktop, we always use the layout viewport's scrollbars.
3604 if (!frame_->GetSettings() || !frame_->GetSettings()->GetViewportEnabled() ||
3605 !frame_->GetDocument() || !frame_->GetPage())
3606 return false;
3607
3608 if (!LayoutViewport())
3609 return false;
3610
3611 const TopDocumentRootScrollerController& controller =
3612 frame_->GetPage()->GlobalRootScrollerController();
3613 return controller.RootScrollerArea() == LayoutViewport();
3614 }
3615
ExistingAXObjectCache() const3616 AXObjectCache* LocalFrameView::ExistingAXObjectCache() const {
3617 if (GetFrame().GetDocument())
3618 return GetFrame().GetDocument()->ExistingAXObjectCache();
3619 return nullptr;
3620 }
3621
SetCursor(const ui::Cursor & cursor)3622 void LocalFrameView::SetCursor(const ui::Cursor& cursor) {
3623 Page* page = GetFrame().GetPage();
3624 if (!page || frame_->GetEventHandler().IsMousePositionUnknown())
3625 return;
3626 LogCursorSizeCounter(&GetFrame(), cursor);
3627 page->GetChromeClient().SetCursor(cursor, frame_);
3628 }
3629
PropagateFrameRects()3630 void LocalFrameView::PropagateFrameRects() {
3631 TRACE_EVENT0("blink", "LocalFrameView::PropagateFrameRects");
3632 if (LayoutSizeFixedToFrameSize())
3633 SetLayoutSizeInternal(Size());
3634
3635 ForAllChildViewsAndPlugins([](EmbeddedContentView& view) {
3636 auto* local_frame_view = DynamicTo<LocalFrameView>(view);
3637 if (!local_frame_view || !local_frame_view->ShouldThrottleRendering()) {
3638 view.PropagateFrameRects();
3639 }
3640 });
3641
3642 GetFrame().Client()->FrameRectsChanged(FrameRect());
3643
3644 // It's possible for changing the frame rect to not generate a layout
3645 // or any other event tracked by accessibility, we've seen this with
3646 // Android WebView. Ensure that the root of the accessibility tree is
3647 // invalidated so that it gets the right bounding rect.
3648 if (AXObjectCache* cache = ExistingAXObjectCache())
3649 cache->HandleFrameRectsChanged(*GetFrame().GetDocument());
3650 }
3651
SetLayoutSizeInternal(const IntSize & size)3652 void LocalFrameView::SetLayoutSizeInternal(const IntSize& size) {
3653 if (layout_size_ == size)
3654 return;
3655 layout_size_ = size;
3656
3657 if (frame_->IsMainFrame() && frame_->GetDocument())
3658 TextAutosizer::UpdatePageInfoInAllFrames(frame_);
3659
3660 SetNeedsLayout();
3661 }
3662
ClipPaintRect(FloatRect * paint_rect) const3663 void LocalFrameView::ClipPaintRect(FloatRect* paint_rect) const {
3664 // TODO(wangxianzhu): Support ChromeClient::VisibleContentRectForPainting()
3665 // with CompositeAfterPaint.
3666 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
3667
3668 // Paint the whole rect if ClipsContent is false, meaning that the whole
3669 // document should be recorded. This occurs if:
3670 // - A paint preview is being captured.
3671 // - WebPreferences::record_whole_document is true.
3672 if (!frame_->ClipsContent())
3673 return;
3674
3675 // By default we consider the bounds of the FrameView to be what is considered
3676 // visible for the Frame.
3677 IntRect visible_rect = IntRect(IntPoint(), Size());
3678 // Non-main frames always clip to their FrameView bounds. Main frames can
3679 // have this behaviour modified by devtools.
3680 if (frame_->IsMainFrame()) {
3681 // If devtools is overriding the viewport, then the FrameView's bounds are
3682 // not what we should paint, instead we should paint inside the bounds
3683 // specified by devtools.
3684 GetPage()->GetChromeClient().OverrideVisibleRectForMainFrame(*frame_,
3685 &visible_rect);
3686 }
3687 paint_rect->Intersect(visible_rect);
3688 }
3689
DidChangeScrollOffset()3690 void LocalFrameView::DidChangeScrollOffset() {
3691 GetFrame().Client()->DidChangeScrollOffset();
3692 if (GetFrame().IsMainFrame()) {
3693 GetFrame().GetPage()->GetChromeClient().MainFrameScrollOffsetChanged(
3694 GetFrame());
3695 }
3696 }
3697
ScrollableAreaWithElementId(const CompositorElementId & id)3698 ScrollableArea* LocalFrameView::ScrollableAreaWithElementId(
3699 const CompositorElementId& id) {
3700 // Check for the layout viewport, which may not be in scrollable_areas_ if it
3701 // is styled overflow: hidden. (Other overflow: hidden elements won't have
3702 // composited scrolling layers per crbug.com/784053, so we don't have to worry
3703 // about them.)
3704 ScrollableArea* viewport = LayoutViewport();
3705 if (id == viewport->GetScrollElementId())
3706 return viewport;
3707
3708 if (scrollable_areas_) {
3709 // This requires iterating over all scrollable areas. We may want to store a
3710 // map of ElementId to ScrollableArea if this is an issue for performance.
3711 for (ScrollableArea* scrollable_area : *scrollable_areas_) {
3712 if (id == scrollable_area->GetScrollElementId())
3713 return scrollable_area;
3714 }
3715 }
3716 return nullptr;
3717 }
3718
ScrollRectToVisibleInRemoteParent(const PhysicalRect & rect_to_scroll,mojom::blink::ScrollIntoViewParamsPtr params)3719 void LocalFrameView::ScrollRectToVisibleInRemoteParent(
3720 const PhysicalRect& rect_to_scroll,
3721 mojom::blink::ScrollIntoViewParamsPtr params) {
3722 DCHECK(GetFrame().IsLocalRoot() && !GetFrame().IsMainFrame() &&
3723 safe_to_propagate_scroll_to_parent_);
3724 PhysicalRect new_rect = ConvertToRootFrame(rect_to_scroll);
3725 frame_->GetLocalFrameHostRemote().ScrollRectToVisibleInParentFrame(
3726 gfx::Rect(new_rect.X().ToInt(), new_rect.Y().ToInt(),
3727 new_rect.Width().ToInt(), new_rect.Height().ToInt()),
3728 std::move(params));
3729 }
3730
NotifyFrameRectsChangedIfNeeded()3731 void LocalFrameView::NotifyFrameRectsChangedIfNeeded() {
3732 if (root_layer_did_scroll_) {
3733 root_layer_did_scroll_ = false;
3734 PropagateFrameRects();
3735 }
3736 }
3737
ViewportToFrame(const PhysicalOffset & point_in_viewport) const3738 PhysicalOffset LocalFrameView::ViewportToFrame(
3739 const PhysicalOffset& point_in_viewport) const {
3740 PhysicalOffset point_in_root_frame = PhysicalOffset::FromFloatPointRound(
3741 frame_->GetPage()->GetVisualViewport().ViewportToRootFrame(
3742 FloatPoint(point_in_viewport)));
3743 return ConvertFromRootFrame(point_in_root_frame);
3744 }
3745
ViewportToFrame(const FloatPoint & point_in_viewport) const3746 FloatPoint LocalFrameView::ViewportToFrame(
3747 const FloatPoint& point_in_viewport) const {
3748 FloatPoint point_in_root_frame(
3749 frame_->GetPage()->GetVisualViewport().ViewportToRootFrame(
3750 point_in_viewport));
3751 return ConvertFromRootFrame(point_in_root_frame);
3752 }
3753
ViewportToFrame(const IntRect & rect_in_viewport) const3754 IntRect LocalFrameView::ViewportToFrame(const IntRect& rect_in_viewport) const {
3755 IntRect rect_in_root_frame =
3756 frame_->GetPage()->GetVisualViewport().ViewportToRootFrame(
3757 rect_in_viewport);
3758 return ConvertFromRootFrame(rect_in_root_frame);
3759 }
3760
ViewportToFrame(const IntPoint & point_in_viewport) const3761 IntPoint LocalFrameView::ViewportToFrame(
3762 const IntPoint& point_in_viewport) const {
3763 return RoundedIntPoint(ViewportToFrame(PhysicalOffset(point_in_viewport)));
3764 }
3765
FrameToViewport(const IntRect & rect_in_frame) const3766 IntRect LocalFrameView::FrameToViewport(const IntRect& rect_in_frame) const {
3767 IntRect rect_in_root_frame = ConvertToRootFrame(rect_in_frame);
3768 return frame_->GetPage()->GetVisualViewport().RootFrameToViewport(
3769 rect_in_root_frame);
3770 }
3771
FrameToViewport(const IntPoint & point_in_frame) const3772 IntPoint LocalFrameView::FrameToViewport(const IntPoint& point_in_frame) const {
3773 IntPoint point_in_root_frame = ConvertToRootFrame(point_in_frame);
3774 return frame_->GetPage()->GetVisualViewport().RootFrameToViewport(
3775 point_in_root_frame);
3776 }
3777
FrameToScreen(const IntRect & rect) const3778 IntRect LocalFrameView::FrameToScreen(const IntRect& rect) const {
3779 if (auto* client = GetChromeClient())
3780 return client->ViewportToScreen(FrameToViewport(rect), this);
3781 return IntRect();
3782 }
3783
SoonToBeRemovedUnscaledViewportToContents(const IntPoint & point_in_viewport) const3784 IntPoint LocalFrameView::SoonToBeRemovedUnscaledViewportToContents(
3785 const IntPoint& point_in_viewport) const {
3786 IntPoint point_in_root_frame = FlooredIntPoint(
3787 frame_->GetPage()->GetVisualViewport().ViewportCSSPixelsToRootFrame(
3788 FloatPoint(point_in_viewport)));
3789 return ConvertFromRootFrame(point_in_root_frame);
3790 }
3791
Paint(GraphicsContext & context,const GlobalPaintFlags global_paint_flags,const CullRect & cull_rect,const IntSize & paint_offset) const3792 void LocalFrameView::Paint(GraphicsContext& context,
3793 const GlobalPaintFlags global_paint_flags,
3794 const CullRect& cull_rect,
3795 const IntSize& paint_offset) const {
3796 // |paint_offset| is not used because paint properties of the contents will
3797 // ensure the correct location.
3798 PaintInternal(context, global_paint_flags, cull_rect);
3799 }
3800
PaintInternal(GraphicsContext & context,const GlobalPaintFlags global_paint_flags,const CullRect & cull_rect) const3801 void LocalFrameView::PaintInternal(GraphicsContext& context,
3802 const GlobalPaintFlags global_paint_flags,
3803 const CullRect& cull_rect) const {
3804 FramePainter(*this).Paint(context, global_paint_flags, cull_rect);
3805 }
3806
PaintOutsideOfLifecycleIsAllowed(GraphicsContext & context,const LocalFrameView & frame_view)3807 static bool PaintOutsideOfLifecycleIsAllowed(GraphicsContext& context,
3808 const LocalFrameView& frame_view) {
3809 // A paint outside of lifecycle should not conflict about paint controller
3810 // caching with the default painting executed during lifecycle update,
3811 // otherwise the caller should either use a transient paint controller or
3812 // explicitly skip cache.
3813 if (context.GetPaintController().IsSkippingCache())
3814 return true;
3815 // For CompositeAfterPaint, they always conflict because we always paint into
3816 // paint_controller_ during lifecycle update.
3817 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
3818 return false;
3819 // For pre-CompositeAfterPaint, they conflict if the local frame root has a
3820 // a root graphics layer.
3821 return !frame_view.GetFrame()
3822 .LocalFrameRoot()
3823 .View()
3824 ->GetLayoutView()
3825 ->Compositor()
3826 ->PaintRootGraphicsLayer();
3827 }
3828
PaintOutsideOfLifecycle(GraphicsContext & context,const GlobalPaintFlags global_paint_flags,const CullRect & cull_rect)3829 void LocalFrameView::PaintOutsideOfLifecycle(
3830 GraphicsContext& context,
3831 const GlobalPaintFlags global_paint_flags,
3832 const CullRect& cull_rect) {
3833 DCHECK(PaintOutsideOfLifecycleIsAllowed(context, *this));
3834
3835 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
3836 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
3837 });
3838
3839 PaintInternal(context, global_paint_flags, cull_rect);
3840
3841 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
3842 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
3843 });
3844 }
3845
PaintContentsOutsideOfLifecycle(GraphicsContext & context,const GlobalPaintFlags global_paint_flags,const CullRect & cull_rect)3846 void LocalFrameView::PaintContentsOutsideOfLifecycle(
3847 GraphicsContext& context,
3848 const GlobalPaintFlags global_paint_flags,
3849 const CullRect& cull_rect) {
3850 DCHECK(PaintOutsideOfLifecycleIsAllowed(context, *this));
3851
3852 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
3853 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
3854 });
3855
3856 FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
3857
3858 ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
3859 frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
3860 });
3861 }
3862
GetPaintRecord() const3863 sk_sp<PaintRecord> LocalFrameView::GetPaintRecord() const {
3864 DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
3865 DCHECK_EQ(DocumentLifecycle::kPaintClean, Lifecycle().GetState());
3866 DCHECK(frame_->IsLocalRoot());
3867 DCHECK(paint_controller_);
3868 return paint_controller_->GetPaintArtifact().GetPaintRecord(
3869 PropertyTreeState::Root());
3870 }
3871
ConvertToRootFrame(const IntRect & local_rect) const3872 IntRect LocalFrameView::ConvertToRootFrame(const IntRect& local_rect) const {
3873 if (LocalFrameView* parent = ParentFrameView()) {
3874 IntRect parent_rect = ConvertToContainingEmbeddedContentView(local_rect);
3875 return parent->ConvertToRootFrame(parent_rect);
3876 }
3877 return local_rect;
3878 }
3879
ConvertToRootFrame(const IntPoint & local_point) const3880 IntPoint LocalFrameView::ConvertToRootFrame(const IntPoint& local_point) const {
3881 return RoundedIntPoint(ConvertToRootFrame(PhysicalOffset(local_point)));
3882 }
3883
ConvertToRootFrame(const PhysicalOffset & local_offset) const3884 PhysicalOffset LocalFrameView::ConvertToRootFrame(
3885 const PhysicalOffset& local_offset) const {
3886 if (LocalFrameView* parent = ParentFrameView()) {
3887 PhysicalOffset parent_offset =
3888 ConvertToContainingEmbeddedContentView(local_offset);
3889 return parent->ConvertToRootFrame(parent_offset);
3890 }
3891 return local_offset;
3892 }
3893
ConvertToRootFrame(const FloatPoint & local_point) const3894 FloatPoint LocalFrameView::ConvertToRootFrame(
3895 const FloatPoint& local_point) const {
3896 if (LocalFrameView* parent = ParentFrameView()) {
3897 FloatPoint parent_point =
3898 ConvertToContainingEmbeddedContentView(local_point);
3899 return parent->ConvertToRootFrame(parent_point);
3900 }
3901 return local_point;
3902 }
3903
ConvertToRootFrame(const PhysicalRect & local_rect) const3904 PhysicalRect LocalFrameView::ConvertToRootFrame(
3905 const PhysicalRect& local_rect) const {
3906 if (LocalFrameView* parent = ParentFrameView()) {
3907 PhysicalOffset parent_offset =
3908 ConvertToContainingEmbeddedContentView(local_rect.offset);
3909 PhysicalRect parent_rect(parent_offset, local_rect.size);
3910 return parent->ConvertToRootFrame(parent_rect);
3911 }
3912 return local_rect;
3913 }
3914
ConvertFromRootFrame(const IntRect & rect_in_root_frame) const3915 IntRect LocalFrameView::ConvertFromRootFrame(
3916 const IntRect& rect_in_root_frame) const {
3917 if (LocalFrameView* parent = ParentFrameView()) {
3918 IntRect parent_rect = parent->ConvertFromRootFrame(rect_in_root_frame);
3919 return ConvertFromContainingEmbeddedContentView(parent_rect);
3920 }
3921 return rect_in_root_frame;
3922 }
3923
ConvertFromRootFrame(const IntPoint & point_in_root_frame) const3924 IntPoint LocalFrameView::ConvertFromRootFrame(
3925 const IntPoint& point_in_root_frame) const {
3926 return RoundedIntPoint(
3927 ConvertFromRootFrame(PhysicalOffset(point_in_root_frame)));
3928 }
3929
ConvertFromRootFrame(const PhysicalOffset & offset_in_root_frame) const3930 PhysicalOffset LocalFrameView::ConvertFromRootFrame(
3931 const PhysicalOffset& offset_in_root_frame) const {
3932 if (LocalFrameView* parent = ParentFrameView()) {
3933 PhysicalOffset parent_point =
3934 parent->ConvertFromRootFrame(offset_in_root_frame);
3935 return ConvertFromContainingEmbeddedContentView(parent_point);
3936 }
3937 return offset_in_root_frame;
3938 }
3939
ConvertFromRootFrame(const FloatPoint & point_in_root_frame) const3940 FloatPoint LocalFrameView::ConvertFromRootFrame(
3941 const FloatPoint& point_in_root_frame) const {
3942 if (LocalFrameView* parent = ParentFrameView()) {
3943 FloatPoint parent_point = parent->ConvertFromRootFrame(point_in_root_frame);
3944 return ConvertFromContainingEmbeddedContentView(parent_point);
3945 }
3946 return point_in_root_frame;
3947 }
3948
ParentVisibleChanged()3949 void LocalFrameView::ParentVisibleChanged() {
3950 // As parent visibility changes, we may need to recomposite this frame view
3951 // and potentially child frame views.
3952 SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
3953
3954 if (!IsSelfVisible())
3955 return;
3956
3957 bool visible = IsParentVisible();
3958 ForAllChildViewsAndPlugins(
3959 [visible](EmbeddedContentView& embedded_content_view) {
3960 embedded_content_view.SetParentVisible(visible);
3961 });
3962 }
3963
SelfVisibleChanged()3964 void LocalFrameView::SelfVisibleChanged() {
3965 // FrameView visibility affects PLC::CanBeComposited, which in turn affects
3966 // compositing inputs.
3967 if (LayoutView* view = GetLayoutView())
3968 view->Layer()->SetNeedsCompositingInputsUpdate();
3969 }
3970
Show()3971 void LocalFrameView::Show() {
3972 if (!IsSelfVisible()) {
3973 SetSelfVisible(true);
3974 if (GetScrollingCoordinator())
3975 GetScrollingContext()->SetScrollGestureRegionIsDirty(true);
3976 SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
3977 if (IsParentVisible()) {
3978 ForAllChildViewsAndPlugins(
3979 [](EmbeddedContentView& embedded_content_view) {
3980 embedded_content_view.SetParentVisible(true);
3981 });
3982 }
3983 }
3984 }
3985
Hide()3986 void LocalFrameView::Hide() {
3987 if (IsSelfVisible()) {
3988 if (IsParentVisible()) {
3989 ForAllChildViewsAndPlugins(
3990 [](EmbeddedContentView& embedded_content_view) {
3991 embedded_content_view.SetParentVisible(false);
3992 });
3993 }
3994 SetSelfVisible(false);
3995 if (GetScrollingCoordinator())
3996 GetScrollingContext()->SetScrollGestureRegionIsDirty(true);
3997 SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
3998 }
3999 }
4000
ViewportWidth() const4001 int LocalFrameView::ViewportWidth() const {
4002 int viewport_width = GetLayoutSize().Width();
4003 return AdjustForAbsoluteZoom::AdjustInt(viewport_width, GetLayoutView());
4004 }
4005
GetScrollableArea()4006 ScrollableArea* LocalFrameView::GetScrollableArea() {
4007 if (viewport_scrollable_area_)
4008 return viewport_scrollable_area_.Get();
4009
4010 return LayoutViewport();
4011 }
4012
LayoutViewport() const4013 PaintLayerScrollableArea* LocalFrameView::LayoutViewport() const {
4014 auto* layout_view = GetLayoutView();
4015 return layout_view ? layout_view->GetScrollableArea() : nullptr;
4016 }
4017
GetRootFrameViewport()4018 RootFrameViewport* LocalFrameView::GetRootFrameViewport() {
4019 return viewport_scrollable_area_.Get();
4020 }
4021
CollectAnnotatedRegions(LayoutObject & layout_object,Vector<AnnotatedRegionValue> & regions) const4022 void LocalFrameView::CollectAnnotatedRegions(
4023 LayoutObject& layout_object,
4024 Vector<AnnotatedRegionValue>& regions) const {
4025 // LayoutTexts don't have their own style, they just use their parent's style,
4026 // so we don't want to include them.
4027 if (layout_object.IsText())
4028 return;
4029
4030 layout_object.AddAnnotatedRegions(regions);
4031 for (LayoutObject* curr = layout_object.SlowFirstChild(); curr;
4032 curr = curr->NextSibling())
4033 CollectAnnotatedRegions(*curr, regions);
4034 }
4035
UpdateViewportIntersectionsForSubtree(unsigned parent_flags)4036 bool LocalFrameView::UpdateViewportIntersectionsForSubtree(
4037 unsigned parent_flags) {
4038 // TODO(dcheng): Since LocalFrameView tree updates are deferred, FrameViews
4039 // might still be in the LocalFrameView hierarchy even though the associated
4040 // Document is already detached. Investigate if this check and a similar check
4041 // in lifecycle updates are still needed when there are no more deferred
4042 // LocalFrameView updates: https://crbug.com/561683
4043 if (!GetFrame().GetDocument()->IsActive())
4044 return false;
4045
4046 unsigned flags = GetIntersectionObservationFlags(parent_flags);
4047 bool needs_occlusion_tracking = false;
4048
4049 if (!NeedsLayout()) {
4050 // Notify javascript IntersectionObservers
4051 if (IntersectionObserverController* controller =
4052 GetFrame().GetDocument()->GetIntersectionObserverController()) {
4053 needs_occlusion_tracking |= controller->ComputeIntersections(flags);
4054 }
4055 intersection_observation_state_ = kNotNeeded;
4056 }
4057
4058 if (UpdateViewportIntersection(flags, needs_occlusion_tracking))
4059 flags |= IntersectionObservation::kCanSkipStickyFrameTracking;
4060
4061 for (Frame* child = frame_->Tree().FirstChild(); child;
4062 child = child->Tree().NextSibling()) {
4063 needs_occlusion_tracking |=
4064 child->View()->UpdateViewportIntersectionsForSubtree(flags);
4065 }
4066
4067 for (PortalContents* portal :
4068 DocumentPortals::From(*frame_->GetDocument()).GetPortals()) {
4069 if (Frame* frame = portal->GetFrame()) {
4070 needs_occlusion_tracking |=
4071 frame->View()->UpdateViewportIntersectionsForSubtree(flags);
4072 }
4073 }
4074
4075 return needs_occlusion_tracking;
4076 }
4077
DeliverSynchronousIntersectionObservations()4078 void LocalFrameView::DeliverSynchronousIntersectionObservations() {
4079 if (IntersectionObserverController* controller =
4080 GetFrame().GetDocument()->GetIntersectionObserverController()) {
4081 controller->DeliverNotifications(
4082 IntersectionObserver::kDeliverDuringPostLifecycleSteps);
4083 }
4084 ForAllChildLocalFrameViews([](LocalFrameView& frame_view) {
4085 frame_view.DeliverSynchronousIntersectionObservations();
4086 });
4087 }
4088
CrossOriginToMainFrameChanged()4089 void LocalFrameView::CrossOriginToMainFrameChanged() {
4090 // If any of these conditions hold, then a change in cross-origin status does
4091 // not affect throttling.
4092 if (lifecycle_updates_throttled_ || IsSubtreeThrottled() ||
4093 !IsHiddenForThrottling()) {
4094 return;
4095 }
4096 RenderThrottlingStatusChanged();
4097 // We need to invalidate unconditionally, so if it didn't happen during
4098 // RenderThrottlingStatusChanged, do it now.
4099 if (CanThrottleRendering())
4100 InvalidateForThrottlingChange();
4101 // Immediately propagate changes to children.
4102 UpdateRenderThrottlingStatus(IsHiddenForThrottling(), IsSubtreeThrottled(),
4103 true);
4104 }
4105
CrossOriginToParentFrameChanged()4106 void LocalFrameView::CrossOriginToParentFrameChanged() {
4107 if (auto* owner = frame_->DeprecatedLocalOwner())
4108 owner->FrameCrossOriginToParentFrameChanged();
4109 }
4110
VisibilityForThrottlingChanged()4111 void LocalFrameView::VisibilityForThrottlingChanged() {
4112 if (FrameScheduler* frame_scheduler = frame_->GetFrameScheduler()) {
4113 // TODO(szager): Per crbug.com/994443, maybe this should be:
4114 // SetFrameVisible(IsHiddenForThrottling() || IsSubtreeThrottled());
4115 frame_scheduler->SetFrameVisible(!IsHiddenForThrottling());
4116 }
4117 }
4118
VisibilityChanged(blink::mojom::FrameVisibility visibility)4119 void LocalFrameView::VisibilityChanged(
4120 blink::mojom::FrameVisibility visibility) {
4121 frame_->GetLocalFrameHostRemote().VisibilityChanged(visibility);
4122 }
4123
RenderThrottlingStatusChanged()4124 void LocalFrameView::RenderThrottlingStatusChanged() {
4125 TRACE_EVENT0("blink", "LocalFrameView::RenderThrottlingStatusChanged");
4126 DCHECK(!IsInPerformLayout());
4127 DCHECK(!frame_->GetDocument() || !frame_->GetDocument()->InStyleRecalc());
4128
4129 // We may record more/less foreign layers under the frame.
4130 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
4131 SetForeignLayerListNeedsUpdate();
4132
4133 if (!CanThrottleRendering())
4134 InvalidateForThrottlingChange();
4135
4136 // If we have become unthrottled, this is essentially a no-op since we're
4137 // going to paint anyway. If we have become throttled, then this will force
4138 // one lifecycle update to clear the painted output.
4139 if (GetFrame().IsLocalRoot())
4140 need_paint_phase_after_throttling_ = true;
4141
4142 #if DCHECK_IS_ON()
4143 // Make sure we never have an unthrottled frame inside a throttled one.
4144 LocalFrameView* parent = ParentFrameView();
4145 while (parent) {
4146 DCHECK(CanThrottleRendering() || !parent->CanThrottleRendering());
4147 parent = parent->ParentFrameView();
4148 }
4149 #endif
4150 }
4151
InvalidateForThrottlingChange()4152 void LocalFrameView::InvalidateForThrottlingChange() {
4153 // ScrollingCoordinator needs to update according to the new throttling
4154 // status.
4155 if (ScrollingCoordinator* coordinator = this->GetScrollingCoordinator())
4156 coordinator->NotifyGeometryChanged(this);
4157 // Start ticking animation frames again if necessary.
4158 if (GetPage())
4159 GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
4160 // Force a full repaint of this frame to ensure we are not left with a
4161 // partially painted version of this frame's contents if we skipped
4162 // painting them while the frame was throttled.
4163 LayoutView* layout_view = GetLayoutView();
4164 if (layout_view) {
4165 layout_view->InvalidatePaintForViewAndCompositedLayers();
4166 // Also need to update all paint properties that might be skipped while
4167 // the frame was throttled.
4168 layout_view->AddSubtreePaintPropertyUpdateReason(
4169 SubtreePaintPropertyUpdateReason::kPreviouslySkipped);
4170 }
4171 }
4172
SetNeedsForcedCompositingUpdate()4173 void LocalFrameView::SetNeedsForcedCompositingUpdate() {
4174 needs_forced_compositing_update_ = true;
4175 if (LocalFrameView* parent = ParentFrameView())
4176 parent->SetNeedsForcedCompositingUpdate();
4177 }
4178
SetIntersectionObservationState(IntersectionObservationState state)4179 void LocalFrameView::SetIntersectionObservationState(
4180 IntersectionObservationState state) {
4181 if (intersection_observation_state_ >= state)
4182 return;
4183 intersection_observation_state_ = state;
4184 }
4185
SetPaintArtifactCompositorNeedsUpdate()4186 void LocalFrameView::SetPaintArtifactCompositorNeedsUpdate() {
4187 LocalFrameView* root = GetFrame().LocalFrameRoot().View();
4188 if (root && root->paint_artifact_compositor_)
4189 root->paint_artifact_compositor_->SetNeedsUpdate();
4190 }
4191
SetForeignLayerListNeedsUpdate()4192 void LocalFrameView::SetForeignLayerListNeedsUpdate() {
4193 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
4194 DCHECK_NE(Lifecycle().GetState(), DocumentLifecycle::kInPaint);
4195
4196 if (LocalFrameView* root = GetFrame().LocalFrameRoot().View()) {
4197 // We will re-collect foreign layers in PushPaintArtifactsToCompositor().
4198 root->paint_controller_ = nullptr;
4199 if (root->paint_artifact_compositor_)
4200 root->paint_artifact_compositor_->SetNeedsUpdate();
4201 }
4202 }
4203
GetPaintArtifactCompositor() const4204 PaintArtifactCompositor* LocalFrameView::GetPaintArtifactCompositor() const {
4205 LocalFrameView* root = GetFrame().LocalFrameRoot().View();
4206 return root ? root->paint_artifact_compositor_.get() : nullptr;
4207 }
4208
GetIntersectionObservationFlags(unsigned parent_flags) const4209 unsigned LocalFrameView::GetIntersectionObservationFlags(
4210 unsigned parent_flags) const {
4211 unsigned flags = 0;
4212
4213 const LocalFrame& target_frame = GetFrame();
4214 const Frame& root_frame = target_frame.Tree().Top();
4215 if (&root_frame == &target_frame ||
4216 target_frame.GetSecurityContext()->GetSecurityOrigin()->CanAccess(
4217 root_frame.GetSecurityContext()->GetSecurityOrigin())) {
4218 flags |= IntersectionObservation::kReportImplicitRootBounds;
4219 }
4220
4221 // Observers with explicit roots only need to be checked on the same frame,
4222 // since in this case target and root must be in the same document.
4223 if (intersection_observation_state_ != kNotNeeded) {
4224 flags |= (IntersectionObservation::kExplicitRootObserversNeedUpdate |
4225 IntersectionObservation::kImplicitRootObserversNeedUpdate);
4226 }
4227
4228 // For observers with implicit roots, we need to check state on the whole
4229 // local frame tree, as passed down from the parent.
4230 flags |= (parent_flags &
4231 IntersectionObservation::kImplicitRootObserversNeedUpdate);
4232
4233 // The kIgnoreDelay parameter is used to force computation in an OOPIF which
4234 // is hidden in the parent document, thus not running lifecycle updates. It
4235 // applies to the entire frame tree.
4236 flags |= (parent_flags & IntersectionObservation::kIgnoreDelay);
4237
4238 flags |=
4239 (parent_flags & IntersectionObservation::kCanSkipStickyFrameTracking);
4240
4241 return flags;
4242 }
4243
ShouldThrottleRendering() const4244 bool LocalFrameView::ShouldThrottleRendering() const {
4245 bool throttled_for_global_reasons = CanThrottleRendering() &&
4246 frame_->GetDocument() &&
4247 Lifecycle().ThrottlingAllowed();
4248 if (!throttled_for_global_reasons || needs_forced_compositing_update_ ||
4249 need_paint_phase_after_throttling_) {
4250 return false;
4251 }
4252
4253 if (intersection_observation_state_ == kRequired) {
4254 auto* local_frame_root_view = GetFrame().LocalFrameRoot().View();
4255 // When doing a lifecycle update required by intersection observer, we can
4256 // throttle lifecycle states after layout. Outside of lifecycle updates,
4257 // the frame should be considered throttled because it is not fully updating
4258 // the lifecycle.
4259 return !local_frame_root_view->in_lifecycle_update_ ||
4260 local_frame_root_view->past_layout_lifecycle_update_;
4261 }
4262
4263 return true;
4264 }
4265
CanThrottleRendering() const4266 bool LocalFrameView::CanThrottleRendering() const {
4267 if (lifecycle_updates_throttled_)
4268 return true;
4269 if (IsSubtreeThrottled())
4270 return true;
4271 // We only throttle hidden cross-origin frames. This is to avoid a situation
4272 // where an ancestor frame directly depends on the pipeline timing of a
4273 // descendant and breaks as a result of throttling. The rationale is that
4274 // cross-origin frames must already communicate with asynchronous messages,
4275 // so they should be able to tolerate some delay in receiving replies from a
4276 // throttled peer.
4277 return IsHiddenForThrottling() && frame_->IsCrossOriginToMainFrame();
4278 }
4279
UpdateRenderThrottlingStatus(bool hidden_for_throttling,bool subtree_throttled,bool recurse)4280 void LocalFrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
4281 bool subtree_throttled,
4282 bool recurse) {
4283 bool was_throttled = CanThrottleRendering();
4284 FrameView::UpdateRenderThrottlingStatus(hidden_for_throttling,
4285 subtree_throttled, recurse);
4286 if (was_throttled != CanThrottleRendering())
4287 RenderThrottlingStatusChanged();
4288 }
4289
BeginLifecycleUpdates()4290 void LocalFrameView::BeginLifecycleUpdates() {
4291 // Avoid pumping frames for the initially empty document.
4292 // TODO(schenney): This seems pointless because main frame updates do occur
4293 // for pages like about:blank, at least according to log messages.
4294 if (!GetFrame().Loader().StateMachine()->CommittedFirstRealDocumentLoad())
4295 return;
4296 lifecycle_updates_throttled_ = false;
4297 if (auto* owner = GetLayoutEmbeddedContent())
4298 owner->SetShouldCheckForPaintInvalidation();
4299
4300 LayoutView* layout_view = GetLayoutView();
4301 bool layout_view_is_empty = layout_view && !layout_view->FirstChild();
4302 if (layout_view_is_empty && !DidFirstLayout() && !NeedsLayout()) {
4303 // Make sure a display:none iframe gets an initial layout pass.
4304 layout_view->SetNeedsLayout(layout_invalidation_reason::kAddedToLayout,
4305 kMarkOnlyThis);
4306 }
4307
4308 ScheduleAnimation();
4309 SetIntersectionObservationState(kRequired);
4310
4311 // Non-main-frame lifecycle and commit deferral are controlled by their
4312 // main frame.
4313 if (!GetFrame().IsMainFrame())
4314 return;
4315
4316 Document* document = GetFrame().GetDocument();
4317 ChromeClient& chrome_client = GetFrame().GetPage()->GetChromeClient();
4318
4319 // Determine if we want to defer commits to the compositor once lifecycle
4320 // updates start. Doing so allows us to update the page lifecycle but not
4321 // present the results to screen until we see first contentful paint is
4322 // available or until a timer expires.
4323 // This is enabled only if kAvoidFlashBetweenNavigation is enabled, and
4324 // the document loading is regular HTML served over HTTP/HTTPs.
4325 // And only defer commits once. This method gets called multiple times,
4326 // and we do not want to defer a second time if we have already done
4327 // so once and resumed commits already.
4328 if (document &&
4329 base::FeatureList::IsEnabled(blink::features::kPaintHolding) &&
4330 document->DeferredCompositorCommitIsAllowed() &&
4331 !have_deferred_commits_) {
4332 chrome_client.StartDeferringCommits(GetFrame(),
4333 GetCommitDelayForPaintHolding());
4334 have_deferred_commits_ = true;
4335 }
4336
4337 chrome_client.BeginLifecycleUpdates(GetFrame());
4338 }
4339
SetInitialViewportSize(const IntSize & viewport_size)4340 void LocalFrameView::SetInitialViewportSize(const IntSize& viewport_size) {
4341 if (viewport_size == initial_viewport_size_)
4342 return;
4343
4344 initial_viewport_size_ = viewport_size;
4345 if (Document* document = frame_->GetDocument())
4346 document->GetStyleEngine().InitialViewportChanged();
4347 }
4348
InitialViewportWidth() const4349 int LocalFrameView::InitialViewportWidth() const {
4350 DCHECK(frame_->IsMainFrame());
4351 return initial_viewport_size_.Width();
4352 }
4353
InitialViewportHeight() const4354 int LocalFrameView::InitialViewportHeight() const {
4355 DCHECK(frame_->IsMainFrame());
4356 return initial_viewport_size_.Height();
4357 }
4358
HasVisibleSlowRepaintViewportConstrainedObjects() const4359 bool LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects() const {
4360 if (!ViewportConstrainedObjects())
4361 return false;
4362 for (const LayoutObject* layout_object : *ViewportConstrainedObjects()) {
4363 DCHECK(layout_object->IsBoxModelObject() && layout_object->HasLayer());
4364 DCHECK(layout_object->StyleRef().GetPosition() == EPosition::kFixed ||
4365 layout_object->StyleRef().GetPosition() == EPosition::kSticky);
4366 if (ToLayoutBoxModelObject(layout_object)->IsSlowRepaintConstrainedObject())
4367 return true;
4368 }
4369 return false;
4370 }
4371
MainThreadScrollingReasonsPerFrame() const4372 MainThreadScrollingReasons LocalFrameView::MainThreadScrollingReasonsPerFrame()
4373 const {
4374 MainThreadScrollingReasons reasons =
4375 static_cast<MainThreadScrollingReasons>(0);
4376
4377 if (ShouldThrottleRendering())
4378 return reasons;
4379
4380 if (RequiresMainThreadScrollingForBackgroundAttachmentFixed()) {
4381 reasons |=
4382 cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
4383 }
4384
4385 // Force main-thread scrolling if the frame has uncomposited position: fixed
4386 // elements. Note: we care about this not only for input-scrollable frames
4387 // but also for overflow: hidden frames, because script can run composited
4388 // smooth-scroll animations. For this reason, we use HasOverflow instead of
4389 // ScrollsOverflow (which is false for overflow: hidden).
4390 if (LayoutViewport()->HasOverflow() &&
4391 GetLayoutView()->StyleRef().VisibleToHitTesting() &&
4392 HasVisibleSlowRepaintViewportConstrainedObjects()) {
4393 reasons |=
4394 cc::MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
4395 }
4396 return reasons;
4397 }
4398
GetMainThreadScrollingReasons() const4399 MainThreadScrollingReasons LocalFrameView::GetMainThreadScrollingReasons()
4400 const {
4401 MainThreadScrollingReasons reasons =
4402 static_cast<MainThreadScrollingReasons>(0);
4403
4404 if (!GetPage()->GetSettings().GetThreadedScrollingEnabled())
4405 reasons |= cc::MainThreadScrollingReason::kThreadedScrollingDisabled;
4406
4407 if (!GetPage()->MainFrame()->IsLocalFrame())
4408 return reasons;
4409
4410 // TODO(alexmos,kenrb): For OOPIF, local roots that are different from
4411 // the main frame can't be used in the calculation, since they use
4412 // different compositors with unrelated state, which breaks some of the
4413 // calculations below.
4414 if (&frame_->LocalFrameRoot() != GetPage()->MainFrame())
4415 return reasons;
4416
4417 // Walk the tree to the root. Use the gathered reasons to determine
4418 // whether the target frame should be scrolled on main thread regardless
4419 // other subframes on the same page.
4420 for (Frame* frame = frame_; frame; frame = frame->Tree().Parent()) {
4421 auto* local_frame = DynamicTo<LocalFrame>(frame);
4422 if (!local_frame)
4423 continue;
4424 reasons |= local_frame->View()->MainThreadScrollingReasonsPerFrame();
4425 }
4426
4427 DCHECK(
4428 !cc::MainThreadScrollingReason::HasNonCompositedScrollReasons(reasons));
4429 return reasons;
4430 }
4431
MainThreadScrollingReasonsAsText()4432 String LocalFrameView::MainThreadScrollingReasonsAsText() {
4433 MainThreadScrollingReasons reasons = 0;
4434 DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
4435 const auto* properties = GetLayoutView()->FirstFragment().PaintProperties();
4436 if (properties && properties->Scroll())
4437 reasons = properties->Scroll()->GetMainThreadScrollingReasons();
4438 return String(cc::MainThreadScrollingReason::AsText(reasons).c_str());
4439 }
4440
MapToVisualRectInRemoteRootFrame(PhysicalRect & rect,bool apply_overflow_clip)4441 bool LocalFrameView::MapToVisualRectInRemoteRootFrame(
4442 PhysicalRect& rect,
4443 bool apply_overflow_clip) {
4444 DCHECK(frame_->IsLocalRoot());
4445 // This is the top-level frame, so no mapping necessary.
4446 if (frame_->IsMainFrame())
4447 return true;
4448 bool result = rect.InclusiveIntersect(PhysicalRect(
4449 apply_overflow_clip ? frame_->RemoteViewportIntersection()
4450 : frame_->RemoteMainFrameDocumentIntersection()));
4451 if (result)
4452 rect.Move(PhysicalOffset(GetFrame().RemoteViewportOffset()));
4453 return result;
4454 }
4455
MapLocalToRemoteRootFrame(TransformState & transform_state)4456 void LocalFrameView::MapLocalToRemoteRootFrame(
4457 TransformState& transform_state) {
4458 DCHECK(frame_->IsLocalRoot());
4459 // This is the top-level frame, so no mapping necessary.
4460 if (frame_->IsMainFrame())
4461 return;
4462 transform_state.Move(PhysicalOffset(frame_->RemoteViewportOffset()));
4463 }
4464
CaretWidth() const4465 LayoutUnit LocalFrameView::CaretWidth() const {
4466 return LayoutUnit(std::max<float>(
4467 1.0f, GetChromeClient()->WindowToViewportScalar(&GetFrame(), 1.0f)));
4468 }
4469
EnsureUkmAggregator()4470 LocalFrameUkmAggregator& LocalFrameView::EnsureUkmAggregator() {
4471 if (!ukm_aggregator_) {
4472 ukm_aggregator_ = base::MakeRefCounted<LocalFrameUkmAggregator>(
4473 frame_->GetDocument()->UkmSourceID(),
4474 frame_->GetDocument()->UkmRecorder());
4475 }
4476 return *ukm_aggregator_;
4477 }
4478
OnFirstContentfulPaint()4479 void LocalFrameView::OnFirstContentfulPaint() {
4480 GetPage()->GetChromeClient().StopDeferringCommits(
4481 *frame_, cc::PaintHoldingCommitTrigger::kFirstContentfulPaint);
4482 EnsureUkmAggregator().DidReachFirstContentfulPaint(frame_->IsMainFrame());
4483 }
4484
RegisterForLifecycleNotifications(LifecycleNotificationObserver * observer)4485 void LocalFrameView::RegisterForLifecycleNotifications(
4486 LifecycleNotificationObserver* observer) {
4487 lifecycle_observers_.insert(observer);
4488 }
4489
UnregisterFromLifecycleNotifications(LifecycleNotificationObserver * observer)4490 void LocalFrameView::UnregisterFromLifecycleNotifications(
4491 LifecycleNotificationObserver* observer) {
4492 lifecycle_observers_.erase(observer);
4493 }
4494
EnqueueStartOfLifecycleTask(base::OnceClosure closure)4495 void LocalFrameView::EnqueueStartOfLifecycleTask(base::OnceClosure closure) {
4496 start_of_lifecycle_tasks_.push_back(std::move(closure));
4497 }
4498
4499 #if DCHECK_IS_ON()
4500 LocalFrameView::DisallowLayoutInvalidationScope::
DisallowLayoutInvalidationScope(LocalFrameView * view)4501 DisallowLayoutInvalidationScope(LocalFrameView* view)
4502 : local_frame_view_(view) {
4503 local_frame_view_->allows_layout_invalidation_after_layout_clean_ = false;
4504 local_frame_view_->ForAllChildLocalFrameViews([](LocalFrameView& frame_view) {
4505 if (!frame_view.ShouldThrottleRendering())
4506 frame_view.CheckDoesNotNeedLayout();
4507 frame_view.allows_layout_invalidation_after_layout_clean_ = false;
4508 });
4509 }
4510
4511 LocalFrameView::DisallowLayoutInvalidationScope::
~DisallowLayoutInvalidationScope()4512 ~DisallowLayoutInvalidationScope() {
4513 local_frame_view_->allows_layout_invalidation_after_layout_clean_ = true;
4514 local_frame_view_->ForAllChildLocalFrameViews([](LocalFrameView& frame_view) {
4515 if (!frame_view.ShouldThrottleRendering())
4516 frame_view.CheckDoesNotNeedLayout();
4517 frame_view.allows_layout_invalidation_after_layout_clean_ = true;
4518 });
4519 }
4520
4521 #endif
4522
UpdateLayerDebugInfoEnabled()4523 void LocalFrameView::UpdateLayerDebugInfoEnabled() {
4524 DCHECK(frame_->IsLocalRoot());
4525 #if DCHECK_IS_ON()
4526 DCHECK(layer_debug_info_enabled_);
4527 #else
4528 bool should_enable =
4529 cc::frame_viewer_instrumentation::IsTracingLayerTreeSnapshots() ||
4530 WebTestSupport::IsRunningWebTest() ||
4531 CoreProbeSink::HasAgentsGlobal(CoreProbeSink::kInspectorLayerTreeAgent);
4532 if (should_enable != layer_debug_info_enabled_) {
4533 layer_debug_info_enabled_ = should_enable;
4534 SetPaintArtifactCompositorNeedsUpdate();
4535 }
4536 #endif
4537 }
4538
4539 OverlayInterstitialAdDetector&
EnsureOverlayInterstitialAdDetector()4540 LocalFrameView::EnsureOverlayInterstitialAdDetector() {
4541 if (!overlay_interstitial_ad_detector_) {
4542 overlay_interstitial_ad_detector_ =
4543 std::make_unique<OverlayInterstitialAdDetector>();
4544 }
4545 return *overlay_interstitial_ad_detector_.get();
4546 }
4547
4548 } // namespace blink
4549