summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/frame/local_frame_view.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/frame/local_frame_view.cc664
1 files changed, 371 insertions, 293 deletions
diff --git a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
index cd23c7cd570..0bae92b6617 100644
--- a/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/chromium/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -46,13 +46,13 @@
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/animation/document_animations.h"
#include "third_party/blink/renderer/core/css/font_face_set_document.h"
#include "third_party/blink/renderer/core/css/style_change_reason.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/editing/compute_layer_selection.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
@@ -124,6 +124,7 @@
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
+#include "third_party/blink/renderer/core/paint/cull_rect_updater.h"
#include "third_party/blink/renderer/core/paint/frame_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
@@ -256,14 +257,11 @@ LocalFrameView::LocalFrameView(LocalFrame& frame, IntRect frame_rect)
// updates. We can't throttle it here or it seems the root compositor
// doesn't get setup properly.
lifecycle_updates_throttled_(!GetFrame().IsMainFrame()),
- current_update_lifecycle_phases_target_state_(
- DocumentLifecycle::kUninitialized),
- past_layout_lifecycle_update_(false),
+ target_state_(DocumentLifecycle::kUninitialized),
suppress_adjust_view_size_(false),
intersection_observation_state_(kNotNeeded),
needs_forced_compositing_update_(false),
needs_focus_on_fragment_(false),
- in_lifecycle_update_(false),
main_thread_scrolling_reasons_(0),
forced_layout_stack_depth_(0),
forced_layout_start_time_(base::TimeTicks()),
@@ -292,6 +290,7 @@ LocalFrameView::~LocalFrameView() {
void LocalFrameView::Trace(Visitor* visitor) const {
visitor->Trace(frame_);
+ visitor->Trace(update_plugins_timer_);
visitor->Trace(fragment_anchor_);
visitor->Trace(scrollable_areas_);
visitor->Trace(animating_scrollable_areas_);
@@ -416,6 +415,24 @@ void LocalFrameView::Dispose() {
if (viewport_scrollable_area_)
viewport_scrollable_area_->ClearScrollableArea();
+ // If we have scheduled plugins to be updated, cancel it. They will still be
+ // notified before they are destroyed.
+ if (update_plugins_timer_.IsActive())
+ update_plugins_timer_.Stop();
+ part_update_set_.clear();
+
+ // These are LayoutObjects whose layout has been deferred to a subsequent
+ // lifecycle update. Not gonna happen.
+ layout_subtree_root_list_.Clear();
+
+ // TODO(szager): LayoutObjects are supposed to remove themselves from these
+ // tracking groups when they update style or are destroyed, but sometimes they
+ // are missed. It would be good to understand how/why that happens, but in the
+ // mean time, it's not safe to keep pointers around to defunct LayoutObjects.
+ orthogonal_writing_mode_root_list_.Clear();
+ viewport_constrained_objects_.reset();
+ background_attachment_fixed_objects_.clear();
+
// Destroy |m_autoSizeInfo| as early as possible, to avoid dereferencing
// partially destroyed |this| via |m_autoSizeInfo->m_frameView|.
auto_size_info_.Clear();
@@ -581,12 +598,6 @@ void LocalFrameView::AdjustViewSizeAndLayout() {
}
}
-void LocalFrameView::UpdateCountersAfterStyleChange() {
- auto* layout_view = GetLayoutView();
- DCHECK(layout_view);
- layout_view->UpdateCounters();
-}
-
void LocalFrameView::CountObjectsNeedingLayout(unsigned& needs_layout_objects,
unsigned& total_objects,
bool& is_subtree) {
@@ -629,7 +640,7 @@ void LocalFrameView::PerformPreLayoutTasks() {
document->EvaluateMediaQueryList();
}
- document->UpdateStyleAndLayoutTree();
+ document->UpdateStyleAndLayoutTreeForThisDocument();
// Update style for all embedded SVG documents underneath this frame, so
// that intrinsic size computation for any embedded objects has up-to-date
@@ -637,7 +648,7 @@ void LocalFrameView::PerformPreLayoutTasks() {
ForAllChildLocalFrameViews([](LocalFrameView& view) {
Document& document = *view.GetFrame().GetDocument();
if (document.IsSVGDocument())
- document.UpdateStyleAndLayoutTree();
+ document.UpdateStyleAndLayoutTreeForThisDocument();
});
Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
@@ -763,8 +774,6 @@ void LocalFrameView::PerformLayout(bool in_subtree_layout) {
if (!LayoutFromRootObject(*root))
continue;
- root->PaintingLayer()->UpdateLayerPositionsAfterLayout();
-
// We need to ensure that we mark up all layoutObjects up to the
// LayoutView for paint invalidation. This simplifies our code as we
// just always do a full tree walk.
@@ -943,9 +952,6 @@ void LocalFrameView::UpdateLayout() {
frame_timing_requests_dirty_ = true;
- if (!in_subtree_layout)
- GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
-
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("blink.debug.layout.trees"), "LayoutTree", this,
TracedLayoutObject::Create(*GetLayoutView(), true));
@@ -1011,14 +1017,8 @@ void LocalFrameView::DidFinishForcedLayout(DocumentUpdateReason reason) {
forced_layout_stack_depth_--;
if (!forced_layout_stack_depth_ && base::TimeTicks::IsHighResolution()) {
LocalFrameUkmAggregator& aggregator = EnsureUkmAggregator();
- aggregator.RecordSample(
- static_cast<size_t>(LocalFrameUkmAggregator::kForcedStyleAndLayout),
- forced_layout_start_time_, base::TimeTicks::Now());
- if (reason == DocumentUpdateReason::kHitTest) {
- aggregator.RecordSample(
- static_cast<size_t>(LocalFrameUkmAggregator::kHitTestDocumentUpdate),
- forced_layout_start_time_, base::TimeTicks::Now());
- }
+ aggregator.RecordForcedLayoutSample(reason, forced_layout_start_time_,
+ base::TimeTicks::Now());
}
}
@@ -1094,6 +1094,9 @@ DocumentLifecycle& LocalFrameView::Lifecycle() const {
void LocalFrameView::RunPostLifecycleSteps() {
AllowThrottlingScope allow_throttling(*this);
RunIntersectionObserverSteps();
+ ForAllRemoteFrameViews([](RemoteFrameView& frame_view) {
+ frame_view.UpdateCompositingScaleFactor();
+ });
}
void LocalFrameView::RunIntersectionObserverSteps() {
@@ -1114,7 +1117,7 @@ void LocalFrameView::RunIntersectionObserverSteps() {
LayoutObject* layout_object = GetLayoutView();
IntRect main_frame_dimensions =
To<LayoutBox>(layout_object)->PixelSnappedLayoutOverflowRect();
- GetFrame().Client()->OnMainFrameIntersectionChanged(WebRect(
+ GetFrame().Client()->OnMainFrameIntersectionChanged(IntRect(
0, 0, main_frame_dimensions.Width(), main_frame_dimensions.Height()));
}
@@ -1137,7 +1140,7 @@ void LocalFrameView::ForceUpdateViewportIntersections() {
// update; but we can't wait for a lifecycle update to run them, because a
// hidden frame won't run lifecycle updates. Force layout and run them now.
DisallowThrottlingScope disallow_throttling(*this);
- UpdateLifecycleToCompositingCleanPlusScrolling(
+ UpdateLifecycleToPrePaintClean(
DocumentUpdateReason::kIntersectionObservation);
UpdateViewportIntersectionsForSubtree(
IntersectionObservation::kImplicitRootObserversNeedUpdate |
@@ -1251,25 +1254,20 @@ void LocalFrameView::AdjustMediaTypeForPrinting(bool printing) {
void LocalFrameView::AddBackgroundAttachmentFixedObject(LayoutObject* object) {
DCHECK(!background_attachment_fixed_objects_.Contains(object));
-
background_attachment_fixed_objects_.insert(object);
- // Ensure main thread scrolling reasons are recomputed.
- SetNeedsPaintPropertyUpdate();
- // The object's scroll properties are not affected by its own background.
- object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
+ // Ensure main thread scrolling reasons of the ancestor scroll nodes are
+ // recomputed. The object's own scroll properties are not affected.
+ object->ForceAllAncestorsNeedPaintPropertyUpdate();
}
void LocalFrameView::RemoveBackgroundAttachmentFixedObject(
LayoutObject* object) {
- DCHECK(background_attachment_fixed_objects_.Contains(object));
-
background_attachment_fixed_objects_.erase(object);
- // Ensure main thread scrolling reasons are recomputed.
- SetNeedsPaintPropertyUpdate();
- // The object's scroll properties are not affected by its own background.
- object->SetAncestorsNeedPaintPropertyUpdateForMainThreadScrolling();
+ // Ensure main thread scrolling reasons of the ancestor scroll nodes are
+ // recomputed. The object's own scroll properties are not affected.
+ object->ForceAllAncestorsNeedPaintPropertyUpdate();
}
bool LocalFrameView::RequiresMainThreadScrollingForBackgroundAttachmentFixed()
@@ -1525,6 +1523,9 @@ void LocalFrameView::UpdateCompositedSelectionIfNeeded() {
if (!RuntimeEnabledFeatures::CompositedSelectionUpdateEnabled())
return;
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
TRACE_EVENT0("blink", "LocalFrameView::updateCompositedSelectionIfNeeded");
Page* page = GetFrame().GetPage();
@@ -1563,8 +1564,14 @@ void LocalFrameView::SetNeedsCompositingUpdate(
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
if (auto* layout_view = GetLayoutView()) {
- if (frame_->GetDocument()->IsActive())
- layout_view->Compositor()->SetNeedsCompositingUpdate(update_type);
+ if (frame_->GetDocument()->IsActive()) {
+ auto* compositor = layout_view->Compositor();
+ compositor->SetNeedsCompositingUpdate(update_type);
+ // Even if the frame is throttlable, we may still need to decomposite it
+ // in response to a visibility change.
+ if (compositor->StaleInCompositingMode())
+ needs_forced_compositing_update_ = true;
+ }
}
}
@@ -2000,6 +2007,7 @@ void LocalFrameView::PerformPostLayoutTasks() {
DCHECK(!IsInPerformLayout());
TRACE_EVENT0("blink,benchmark", "LocalFrameView::performPostLayoutTasks");
+ GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
frame_->Selection().DidLayout();
DCHECK(frame_->GetDocument());
@@ -2160,6 +2168,12 @@ void LocalFrameView::WillBeRemovedFromFrame() {
}
}
+bool LocalFrameView::IsUpdatingLifecycle() const {
+ LocalFrameView* root_view = GetFrame().LocalFrameRoot().View();
+ DCHECK(root_view);
+ return root_view->target_state_ != DocumentLifecycle::kUninitialized;
+}
+
LocalFrameView* LocalFrameView::ParentFrameView() const {
if (!IsAttached())
return nullptr;
@@ -2220,6 +2234,7 @@ bool LocalFrameView::UpdateAllLifecyclePhases(DocumentUpdateReason reason) {
// kLayoutClean.
ForAllThrottledLocalFrameViews([](LocalFrameView& frame_view) {
DCHECK(frame_view.intersection_observation_state_ != kRequired ||
+ frame_view.IsDisplayLocked() ||
frame_view.Lifecycle().GetState() >=
DocumentLifecycle::kLayoutClean);
});
@@ -2298,8 +2313,7 @@ bool LocalFrameView::UpdateLifecycleToLayoutClean(DocumentUpdateReason reason) {
void LocalFrameView::ScheduleVisualUpdateForPaintInvalidationIfNeeded() {
LocalFrame& local_frame_root = GetFrame().LocalFrameRoot();
// We need a full lifecycle update to clear pending paint invalidations.
- if (local_frame_root.View()->current_update_lifecycle_phases_target_state_ <
- DocumentLifecycle::kPaintClean ||
+ if (local_frame_root.View()->target_state_ < DocumentLifecycle::kPaintClean ||
Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean) {
// Schedule visual update to process the paint invalidation in the next
// cycle.
@@ -2360,6 +2374,18 @@ bool LocalFrameView::LocalFrameTreeAllowsThrottling() const {
return false;
}
+void LocalFrameView::PrepareForLifecycleUpdateRecursive() {
+ // We will run lifecycle phases for LocalFrameViews that are unthrottled; or
+ // are throttled but require IntersectionObserver steps to run.
+ if (!ShouldThrottleRendering() ||
+ intersection_observation_state_ == kRequired) {
+ Lifecycle().EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending);
+ ForAllChildLocalFrameViews([](LocalFrameView& child) {
+ child.PrepareForLifecycleUpdateRecursive();
+ });
+ }
+}
+
// TODO(leviw): We don't assert lifecycle information from documents in child
// WebPluginContainerImpls.
bool LocalFrameView::UpdateLifecyclePhases(
@@ -2406,36 +2432,27 @@ bool LocalFrameView::UpdateLifecyclePhases(
if (frame_->IsLocalRoot())
UpdateLayerDebugInfoEnabled();
+ // If we're throttling and we aren't required to run the IntersectionObserver
+ // steps, then we don't need to update lifecycle phases. The throttling status
+ // will get updated in RunPostLifecycleSteps().
+ if (ShouldThrottleRendering() &&
+ intersection_observation_state_ < kRequired) {
+ return Lifecycle().GetState() == target_state;
+ }
+
+ PrepareForLifecycleUpdateRecursive();
+
// This is used to guard against reentrance. It is also used in conjunction
// with the current lifecycle state to determine which phases are yet to run
- // in this cycle.
+ // in this cycle. Note that this may change the return value of
+ // ShouldThrottleRendering(), hence it cannot be moved before the preceeding
+ // code, which relies on the prior value of ShouldThrottleRendering().
base::AutoReset<DocumentLifecycle::LifecycleState> target_state_scope(
- &current_update_lifecycle_phases_target_state_, target_state);
- // This is used to check if we're within a lifecycle update but have passed
- // the layout update phase. Note there is a bit of a subtlety here: it's not
- // sufficient for us to check the current lifecycle state, since it can be
- // past kLayoutClean but the function to run style and layout phase has not
- // actually been run yet. Since this bool affects throttling, and throttling,
- // in turn, determines whether style and layout function will run, we need a
- // separate bool.
- base::AutoReset<bool> past_layout_lifecycle_resetter(
- &past_layout_lifecycle_update_, false);
- base::AutoReset<bool> in_lifecycle_scope(&in_lifecycle_update_, true);
-
- // If we're throttling, then we don't need to update lifecycle phases. The
- // throttling status will get updated in RunPostLifecycleSteps().
- if (ShouldThrottleRendering()) {
- return Lifecycle().GetState() == target_state;
- }
+ &target_state_, target_state);
lifecycle_data_.start_time = base::TimeTicks::Now();
++lifecycle_data_.count;
- ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
- frame_view.Lifecycle().EnsureStateAtMost(
- DocumentLifecycle::kVisualUpdatePending);
- });
-
if (target_state == DocumentLifecycle::kPaintClean) {
{
TRACE_EVENT0("blink", "LocalFrameView::WillStartLifecycleUpdate");
@@ -2487,6 +2504,9 @@ bool LocalFrameView::UpdateLifecyclePhases(
void LocalFrameView::UpdateLifecyclePhasesInternal(
DocumentLifecycle::LifecycleState target_state) {
+ // RunScrollTimelineSteps must not run more than once.
+ bool should_run_scroll_timeline_steps = true;
+
// Run style, layout, compositing and prepaint lifecycle phases and deliver
// resize observations if required. Resize observer callbacks/delegates have
// the potential to dirty layout (until loop limit is reached) and therefore
@@ -2495,7 +2515,23 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
// Note that after ResizeObserver has settled, we also run intersection
// observations that need to be delievered in post-layout. This process can
// also dirty layout, which will run this loop again.
+
+ // A LocalFrameView can be unthrottled at this point, but become throttled as
+ // it advances through lifecycle stages. If that happens, it will prevent
+ // subsequent passes through the loop from updating the newly-throttled views.
+ // To avoid that, we lock in the set of unthrottled views before entering the
+ // loop.
+ HeapVector<Member<LocalFrameView>> unthrottled_frame_views;
+ ForAllNonThrottledLocalFrameViews(
+ [&unthrottled_frame_views](LocalFrameView& frame_view) {
+ unthrottled_frame_views.push_back(&frame_view);
+ });
+
while (true) {
+ for (LocalFrameView* frame_view : unthrottled_frame_views) {
+ frame_view->Lifecycle().EnsureStateAtMost(
+ DocumentLifecycle::kVisualUpdatePending);
+ }
bool run_more_lifecycle_phases =
RunStyleAndLayoutLifecyclePhases(target_state);
if (!run_more_lifecycle_phases)
@@ -2536,7 +2572,7 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
run_more_lifecycle_phases = RunPrePaintLifecyclePhase(target_state);
DCHECK(ShouldThrottleRendering() ||
Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean);
- if (!run_more_lifecycle_phases)
+ if (ShouldThrottleRendering() || !run_more_lifecycle_phases)
return;
run_more_lifecycle_phases =
@@ -2546,6 +2582,24 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
}
}
+ // Some features may require several passes over style and layout
+ // within the same lifecycle update.
+ bool needs_to_repeat_lifecycle = false;
+
+ // ScrollTimelines may be associated with a source that never had a
+ // a chance to get a layout box at the time style was calculated; when
+ // this situation happens, RunScrollTimelineSteps will re-snapshot all
+ // affected timelines and dirty style for associated effect targets.
+ //
+ // https://github.com/w3c/csswg-drafts/issues/5261
+ if (RuntimeEnabledFeatures::CSSScrollTimelineEnabled() &&
+ should_run_scroll_timeline_steps) {
+ should_run_scroll_timeline_steps = false;
+ needs_to_repeat_lifecycle = RunScrollTimelineSteps();
+ if (needs_to_repeat_lifecycle)
+ continue;
+ }
+
// ResizeObserver and post-layout IntersectionObserver observation
// deliveries may dirty style and layout. RunResizeObserverSteps will return
// true if any observer ran that may have dirtied style or layout;
@@ -2553,7 +2607,7 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
// observations led to content-visibility intersection changing visibility
// state synchronously (which happens on the first intersection
// observeration of a context).
- bool needs_to_repeat_lifecycle = RunResizeObserverSteps(target_state);
+ needs_to_repeat_lifecycle = RunResizeObserverSteps(target_state);
// Only run the rest of the steps here if resize observer is done.
if (needs_to_repeat_lifecycle)
continue;
@@ -2576,14 +2630,29 @@ void LocalFrameView::UpdateLifecyclePhasesInternal(
DCHECK_EQ(target_state, DocumentLifecycle::kPaintClean);
RunPaintLifecyclePhase();
- DCHECK(ShouldThrottleRendering() ||
- frame_->GetDocument()->IsCapturingLayout() ||
+ DCHECK(ShouldThrottleRendering() || AnyFrameIsPrintingOrPaintingPreview() ||
Lifecycle().GetState() == DocumentLifecycle::kPaintClean);
ForAllRemoteFrameViews(
[](RemoteFrameView& frame_view) { frame_view.UpdateCompositingRect(); });
}
+bool LocalFrameView::RunScrollTimelineSteps() {
+ DCHECK_GE(Lifecycle().GetState(),
+ DocumentLifecycle::kCompositingAssignmentsClean);
+ bool re_run_lifecycles = false;
+ ForAllNonThrottledLocalFrameViews(
+ [&re_run_lifecycles](LocalFrameView& frame_view) {
+ frame_view.GetFrame()
+ .GetDocument()
+ ->GetDocumentAnimations()
+ .ValidateTimelines();
+ re_run_lifecycles |= (frame_view.Lifecycle().GetState() <
+ DocumentLifecycle::kCompositingAssignmentsClean);
+ });
+ return re_run_lifecycles;
+}
+
bool LocalFrameView::RunResizeObserverSteps(
DocumentLifecycle::LifecycleState target_state) {
bool re_run_lifecycles = false;
@@ -2612,7 +2681,10 @@ bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
TRACE_EVENT0("blink,benchmark",
"LocalFrameView::RunStyleAndLayoutLifecyclePhases");
UpdateStyleAndLayoutIfNeededRecursive();
- DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
+ DCHECK(ShouldThrottleRendering() ||
+ Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean);
+ if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
+ return false;
frame_->GetDocument()
->GetRootScrollerController()
@@ -2633,18 +2705,6 @@ bool LocalFrameView::RunStyleAndLayoutLifecyclePhases(
if (target_state == DocumentLifecycle::kLayoutClean)
return false;
- // This will be reset by AutoReset in the calling function
- // (UpdateLifecyclePhases()).
- past_layout_lifecycle_update_ = true;
-
- // After layout and the |past_layout_lifecycle_update_| update, the value of
- // ShouldThrottleRendering() can change. OOPIF local frame roots that are
- // throttled can return now that layout is clean. This situation happens if
- // the throttling was disabled due to required intersection observation, which
- // can now be run.
- if (ShouldThrottleRendering())
- return false;
-
// Now we can run post layout steps in preparation for further phases.
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.PerformScrollAnchoringAdjustments();
@@ -2735,21 +2795,41 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
#endif
}
- ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
- frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
- if (frame_view.CanThrottleRendering()) {
- // This frame can be throttled but not throttled, meaning we are not in an
- // AllowThrottlingScope. Now this frame may contain dirty paint flags, and
- // we need to propagate the flags into the ancestor chain so that
- // PrePaintTreeWalk can reach this frame.
- frame_view.SetNeedsPaintPropertyUpdate();
- // We may record more pre-composited layers under the frame.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- frame_view.SetPaintArtifactCompositorNeedsUpdate();
- if (auto* owner = frame_view.GetLayoutEmbeddedContent())
- owner->SetShouldCheckForPaintInvalidation();
- }
- });
+ ForAllNonThrottledLocalFrameViews(
+ [](LocalFrameView& frame_view) {
+ frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
+ // We skipped pre-paint for this frame while it was throttled, or we
+ // have never run pre-paint for this frame. Either way, we're
+ // unthrottled now, so we must propagate our dirty bits into our
+ // parent frame so that pre-paint reaches into this frame.
+ if (LayoutView* layout_view = frame_view.GetLayoutView()) {
+ if (auto* owner = frame_view.GetFrame().OwnerLayoutObject()) {
+ if (layout_view->NeedsPaintPropertyUpdate() ||
+ layout_view->DescendantNeedsPaintPropertyUpdate()) {
+ owner->SetDescendantNeedsPaintPropertyUpdate();
+ }
+ if (layout_view->ShouldCheckForPaintInvalidation()) {
+ owner->SetShouldCheckForPaintInvalidation();
+ }
+ if (layout_view->EffectiveAllowedTouchActionChanged() ||
+ layout_view->DescendantEffectiveAllowedTouchActionChanged()) {
+ owner->MarkDescendantEffectiveAllowedTouchActionChanged();
+ }
+ if (layout_view->BlockingWheelEventHandlerChanged() ||
+ layout_view->DescendantBlockingWheelEventHandlerChanged()) {
+ owner->MarkDescendantBlockingWheelEventHandlerChanged();
+ }
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ (layout_view->Layer()->NeedsCullRectUpdate() ||
+ layout_view->Layer()->DescendantNeedsCullRectUpdate())) {
+ layout_view->Layer()
+ ->MarkCompositingContainerChainForNeedsCullRectUpdate();
+ }
+ }
+ }
+ },
+ // Use post-order to ensure correct flag propagation for nested frames.
+ kPostOrder);
{
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
@@ -2767,98 +2847,110 @@ bool LocalFrameView::RunPrePaintLifecyclePhase(
return target_state > DocumentLifecycle::kPrePaintClean;
}
+bool LocalFrameView::AnyFrameIsPrintingOrPaintingPreview() {
+ bool any_frame_is_printing_or_painting_preview = false;
+ ForAllNonThrottledLocalFrameViews(
+ [&any_frame_is_printing_or_painting_preview](LocalFrameView& frame_view) {
+ if (frame_view.GetFrame().GetDocument()->IsPrintingOrPaintingPreview())
+ any_frame_is_printing_or_painting_preview = true;
+ });
+ return any_frame_is_printing_or_painting_preview;
+}
+
void LocalFrameView::RunPaintLifecyclePhase(PaintBenchmarkMode benchmark_mode) {
TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunPaintLifecyclePhase");
// While printing or capturing a paint preview of a document, the paint walk
// is done into a special canvas. There is no point doing a normal paint step
// (or animations update) when in this mode.
- bool is_capturing_layout = frame_->GetDocument()->IsCapturingLayout();
- bool repainted = false;
- if (!is_capturing_layout)
- repainted = PaintTree(benchmark_mode);
-
- if (benchmark_mode ==
- PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate ||
- // TODO(paint-dev): Separate requirement for update for repaint and full
- // PaintArtifactCompositor update.
- (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- benchmark_mode != PaintBenchmarkMode::kNormal)) {
+ if (AnyFrameIsPrintingOrPaintingPreview())
+ return;
+
+ bool repainted = PaintTree(benchmark_mode);
+
+ if (paint_artifact_compositor_ &&
+ (benchmark_mode ==
+ PaintBenchmarkMode::kForcePaintArtifactCompositorUpdate ||
+ // TODO(paint-dev): Separate requirement for update for repaint and full
+ // PaintArtifactCompositor update.
+ (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ benchmark_mode != PaintBenchmarkMode::kNormal))) {
paint_artifact_compositor_->SetNeedsUpdate();
}
- if (!is_capturing_layout) {
- bool needed_update = !paint_artifact_compositor_ ||
- paint_artifact_compositor_->NeedsUpdate();
- PushPaintArtifactToCompositor(repainted);
- size_t total_animations_count = 0;
- bool current_frame_had_raf = false;
- bool next_frame_has_pending_raf = false;
- ForAllNonThrottledLocalFrameViews([this, &total_animations_count,
- &current_frame_had_raf,
- &next_frame_has_pending_raf](
- LocalFrameView& frame_view) {
- if (auto* scrollable_area = frame_view.GetScrollableArea())
- scrollable_area->UpdateCompositorScrollAnimations();
- if (const auto* animating_scrollable_areas =
- frame_view.AnimatingScrollableAreas()) {
- for (PaintLayerScrollableArea* area : *animating_scrollable_areas)
- area->UpdateCompositorScrollAnimations();
- }
- frame_view.GetLayoutView()
- ->GetDocument()
- .GetDocumentAnimations()
- .UpdateAnimations(DocumentLifecycle::kPaintClean,
- paint_artifact_compositor_.get());
- Document& document = frame_view.GetLayoutView()->GetDocument();
- total_animations_count +=
- document.GetDocumentAnimations().GetAnimationsCount();
- current_frame_had_raf |= document.CurrentFrameHadRAF();
- next_frame_has_pending_raf |= document.NextFrameHasPendingRAF();
- });
-
- if (GetLayoutView()->GetDocument().View() &&
- GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) {
- GetLayoutView()
- ->GetDocument()
- .View()
- ->GetCompositorAnimationHost()
- ->SetAnimationCounts(total_animations_count, current_frame_had_raf,
- next_frame_has_pending_raf);
- }
+ bool needed_update =
+ !paint_artifact_compositor_ || paint_artifact_compositor_->NeedsUpdate();
+ PushPaintArtifactToCompositor(repainted);
+ size_t total_animations_count = 0;
+ bool current_frame_had_raf = false;
+ bool next_frame_has_pending_raf = false;
+ ForAllNonThrottledLocalFrameViews(
+ [this, &total_animations_count, &current_frame_had_raf,
+ &next_frame_has_pending_raf](LocalFrameView& frame_view) {
+ if (auto* scrollable_area = frame_view.GetScrollableArea())
+ scrollable_area->UpdateCompositorScrollAnimations();
+ if (const auto* animating_scrollable_areas =
+ frame_view.AnimatingScrollableAreas()) {
+ for (PaintLayerScrollableArea* area : *animating_scrollable_areas)
+ area->UpdateCompositorScrollAnimations();
+ }
+ {
+ // Updating animations can notify ready promises which could mutate
+ // the DOM. We should delay these until we have finished the lifecycle
+ // update. https://crbug.com/1196781
+ ScriptForbiddenScope forbid_script;
+ frame_view.GetLayoutView()
+ ->GetDocument()
+ .GetDocumentAnimations()
+ .UpdateAnimations(DocumentLifecycle::kPaintClean,
+ paint_artifact_compositor_.get());
+ }
+ Document& document = frame_view.GetLayoutView()->GetDocument();
+ total_animations_count +=
+ document.GetDocumentAnimations().GetAnimationsCount();
+ current_frame_had_raf |= document.CurrentFrameHadRAF();
+ next_frame_has_pending_raf |= document.NextFrameHasPendingRAF();
+ });
- // Initialize animation properties in the newly created paint property
- // nodes according to the current animation state. This is mainly for
- // the running composited animations which didn't change state during
- // above UpdateAnimations() but associated with new paint property nodes.
- if (needed_update) {
- auto* root_layer = RootCcLayer();
- if (root_layer && root_layer->layer_tree_host()) {
- root_layer->layer_tree_host()
- ->mutator_host()
- ->InitClientAnimationState();
- }
+ if (GetLayoutView()->GetDocument().View() &&
+ GetLayoutView()->GetDocument().View()->GetCompositorAnimationHost()) {
+ GetLayoutView()
+ ->GetDocument()
+ .View()
+ ->GetCompositorAnimationHost()
+ ->SetAnimationCounts(total_animations_count, current_frame_had_raf,
+ next_frame_has_pending_raf);
+ }
+
+ // Initialize animation properties in the newly created paint property
+ // nodes according to the current animation state. This is mainly for
+ // the running composited animations which didn't change state during
+ // above UpdateAnimations() but associated with new paint property nodes.
+ if (needed_update) {
+ auto* root_layer = RootCcLayer();
+ if (root_layer && root_layer->layer_tree_host()) {
+ root_layer->layer_tree_host()->mutator_host()->InitClientAnimationState();
}
+ }
- // Notify the controller that the artifact has been pushed and some
- // lifecycle state can be freed (such as raster invalidations).
- if (paint_controller_)
- paint_controller_->FinishCycle();
+ // Notify the controller that the artifact has been pushed and some
+ // lifecycle state can be freed (such as raster invalidations).
+ if (paint_controller_)
+ paint_controller_->FinishCycle();
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
- if (root) {
- ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) {
- // Notify the paint controller that the artifact has been pushed and
- // some lifecycle state can be freed (such as raster invalidations).
- layer.GetPaintController().FinishCycle();
- });
- }
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ auto* root = GetLayoutView()->Compositor()->PaintRootGraphicsLayer();
+ if (root) {
+ ForAllPaintingGraphicsLayers(*root, [](GraphicsLayer& layer) {
+ // Notify the paint controller that the artifact has been pushed and
+ // some lifecycle state can be freed (such as raster invalidations).
+ layer.GetPaintController().FinishCycle();
+ });
}
-
- if (paint_artifact_compositor_)
- paint_artifact_compositor_->ClearPropertyTreeChangedState();
}
+ if (paint_artifact_compositor_)
+ paint_artifact_compositor_->ClearPropertyTreeChangedState();
+
if (GetPage())
GetPage()->Animator().ReportFrameAnimations(GetCompositorAnimationHost());
}
@@ -3161,12 +3253,31 @@ void LocalFrameView::PushPaintArtifactToCompositor(bool repainted) {
});
}
+ WTF::Vector<std::unique_ptr<DocumentTransition::Request>>
+ document_transition_requests;
+ // TODO(vmpstr): We should make this work for subframes as well.
+ AppendDocumentTransitionRequests(document_transition_requests);
+
paint_artifact_compositor_->Update(
- pre_composited_layers_, viewport_properties, scroll_translation_nodes);
+ pre_composited_layers_, viewport_properties, scroll_translation_nodes,
+ std::move(document_transition_requests));
probe::LayerTreePainted(&GetFrame());
}
+void LocalFrameView::AppendDocumentTransitionRequests(
+ WTF::Vector<std::unique_ptr<DocumentTransition::Request>>& requests) {
+ DCHECK(frame_ && frame_->GetDocument());
+ auto* document_transition_supplement =
+ DocumentTransitionSupplement::FromIfExists(*frame_->GetDocument());
+ if (!document_transition_supplement)
+ return;
+ auto* document_transition = document_transition_supplement->GetTransition();
+ auto pending_request = document_transition->TakePendingRequest();
+ if (pending_request)
+ requests.push_back(std::move(pending_request));
+}
+
std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON(
LayerTreeFlags flags) {
auto* root_frame_view = GetFrame().LocalFrameRoot().View();
@@ -3196,7 +3307,7 @@ void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
{
SCOPED_UMA_AND_UKM_TIMER(EnsureUkmAggregator(),
LocalFrameUkmAggregator::kStyle);
- frame_->GetDocument()->UpdateStyleAndLayoutTree();
+ frame_->GetDocument()->UpdateStyleAndLayoutTreeForThisDocument();
// Update style for all embedded SVG documents underneath this frame, so
// that intrinsic size computation for any embedded objects has up-to-date
@@ -3204,7 +3315,7 @@ void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() {
ForAllChildLocalFrameViews([](LocalFrameView& view) {
Document& document = *view.GetFrame().GetDocument();
if (document.IsSVGDocument())
- document.UpdateStyleAndLayoutTree();
+ document.UpdateStyleAndLayoutTreeForThisDocument();
});
}
@@ -3691,7 +3802,8 @@ void LocalFrameView::AttachToLayout() {
if (parent_view->IsVisible())
SetParentVisible(true);
UpdateRenderThrottlingStatus(IsHiddenForThrottling(),
- parent_view->CanThrottleRendering());
+ parent_view->CanThrottleRendering(),
+ IsDisplayLocked());
// We may have updated paint properties in detached frame subtree for
// printing (see UpdateLifecyclePhasesForPrinting()). The paint properties
@@ -3775,7 +3887,15 @@ void LocalFrameView::PropagateFrameRects() {
}
});
- GetFrame().Client()->FrameRectsChanged(FrameRect());
+ // To limit the number of Mojo communications, only notify the browser when
+ // the rect's size changes, not when the position changes. The size needs to
+ // be replicated if the iframe goes out-of-process.
+ IntSize frame_size = FrameRect().Size();
+ if (!frame_size_ || *frame_size_ != frame_size) {
+ frame_size_ = frame_size;
+ GetFrame().GetLocalFrameHostRemote().FrameSizeChanged(
+ gfx::Size(frame_size));
+ }
// It's possible for changing the frame rect to not generate a layout
// or any other event tracked by accessibility, we've seen this with
@@ -3796,33 +3916,6 @@ void LocalFrameView::SetLayoutSizeInternal(const IntSize& size) {
SetNeedsLayout();
}
-void LocalFrameView::ClipPaintRect(FloatRect* paint_rect) const {
- // TODO(wangxianzhu): Support ChromeClient::VisibleContentRectForPainting()
- // with CompositeAfterPaint.
- DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-
- // Paint the whole rect if ClipsContent is false, meaning that the whole
- // document should be recorded. This occurs if:
- // - A paint preview is being captured.
- // - WebPreferences::record_whole_document is true.
- if (!frame_->ClipsContent())
- return;
-
- // By default we consider the bounds of the FrameView to be what is considered
- // visible for the Frame.
- IntRect visible_rect = IntRect(IntPoint(), Size());
- // Non-main frames always clip to their FrameView bounds. Main frames can
- // have this behaviour modified by devtools.
- if (frame_->IsMainFrame()) {
- // If devtools is overriding the viewport, then the FrameView's bounds are
- // not what we should paint, instead we should paint inside the bounds
- // specified by devtools.
- GetPage()->GetChromeClient().OverrideVisibleRectForMainFrame(*frame_,
- &visible_rect);
- }
- paint_rect->Intersect(visible_rect);
-}
-
void LocalFrameView::DidChangeScrollOffset() {
GetFrame().Client()->DidChangeScrollOffset();
if (GetFrame().IsMainFrame()) {
@@ -3998,13 +4091,19 @@ void LocalFrameView::Paint(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
const CullRect& cull_rect,
const IntSize& paint_offset) const {
- // When capturing a Paint Preview we want to capture scrollable embedded
- // content separately. Paint should stop here and ask the browser to
- // coordinate painting such frames as a separate task.
- if (context.IsPaintingPreview() && LayoutViewport()->ScrollsOverflow()) {
- // If capture fails we should fallback to capturing inline if possible.
- if (CapturePaintPreview(context, paint_offset))
- return;
+ const auto* owner_layout_object = GetFrame().OwnerLayoutObject();
+ base::Optional<Document::PaintPreviewScope> paint_preview;
+ if (owner_layout_object &&
+ owner_layout_object->GetDocument().IsPaintingPreview()) {
+ paint_preview.emplace(*GetFrame().GetDocument());
+ // When capturing a Paint Preview we want to capture scrollable embedded
+ // content separately. Paint should stop here and ask the browser to
+ // coordinate painting such frames as a separate task.
+ if (LayoutViewport()->ScrollsOverflow()) {
+ // If capture fails we should fallback to capturing inline if possible.
+ if (CapturePaintPreview(context, paint_offset))
+ return;
+ }
}
// |paint_offset| is not used because paint properties of the contents will
@@ -4051,7 +4150,10 @@ void LocalFrameView::PaintOutsideOfLifecycle(
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- PaintInternal(context, global_paint_flags, cull_rect);
+ {
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
+ PaintInternal(context, global_paint_flags, cull_rect);
+ }
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
@@ -4068,7 +4170,10 @@ void LocalFrameView::PaintContentsOutsideOfLifecycle(
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
});
- FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
+ {
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
+ FramePainter(*this).PaintContents(context, global_paint_flags, cull_rect);
+ }
ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) {
frame_view.Lifecycle().AdvanceTo(DocumentLifecycle::kPaintClean);
@@ -4078,6 +4183,7 @@ void LocalFrameView::PaintContentsOutsideOfLifecycle(
void LocalFrameView::PaintContentsForTest(const CullRect& cull_rect) {
AllowThrottlingScope allow_throttling(*this);
Lifecycle().AdvanceTo(DocumentLifecycle::kInPaint);
+ OverriddenCullRectScope force_cull_rect(*this, cull_rect);
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
PaintController& paint_controller = EnsurePaintController();
if (GetLayoutView()->Layer()->SelfOrDescendantNeedsRepaint()) {
@@ -4277,7 +4383,7 @@ bool LocalFrameView::UpdateViewportIntersectionsForSubtree(
unsigned flags = GetIntersectionObservationFlags(parent_flags);
bool needs_occlusion_tracking = false;
- if (!NeedsLayout()) {
+ if (!NeedsLayout() || IsDisplayLocked()) {
// Notify javascript IntersectionObservers
if (IntersectionObserverController* controller =
GetFrame().GetDocument()->GetIntersectionObserverController()) {
@@ -4287,7 +4393,12 @@ bool LocalFrameView::UpdateViewportIntersectionsForSubtree(
intersection_observation_state_ = kNotNeeded;
}
- UpdateViewportIntersection(flags, needs_occlusion_tracking);
+ {
+ SCOPED_UMA_AND_UKM_TIMER(
+ EnsureUkmAggregator(),
+ LocalFrameUkmAggregator::kUpdateViewportIntersection);
+ UpdateViewportIntersection(flags, needs_occlusion_tracking);
+ }
for (Frame* child = frame_->Tree().FirstChild(); child;
child = child->Tree().NextSibling()) {
@@ -4321,26 +4432,19 @@ void LocalFrameView::CrossOriginToMainFrameChanged() {
// If any of these conditions hold, then a change in cross-origin status does
// not affect throttling.
if (lifecycle_updates_throttled_ || IsSubtreeThrottled() ||
- !IsHiddenForThrottling()) {
+ IsDisplayLocked() || !IsHiddenForThrottling()) {
return;
}
RenderThrottlingStatusChanged();
- // We need to invalidate unconditionally, so if it didn't happen during
- // RenderThrottlingStatusChanged, do it now.
- if (CanThrottleRendering())
- InvalidateForThrottlingChange();
// Immediately propagate changes to children.
UpdateRenderThrottlingStatus(IsHiddenForThrottling(), IsSubtreeThrottled(),
- true);
+ IsDisplayLocked(), true);
}
void LocalFrameView::CrossOriginToParentFrameChanged() {
- if (base::FeatureList::IsEnabled(
- blink::features::kCompositeCrossOriginIframes)) {
- if (LayoutView* layout_view = GetLayoutView()) {
- if (PaintLayer* root_layer = layout_view->Layer())
- root_layer->SetNeedsCompositingInputsUpdate();
- }
+ if (LayoutView* layout_view = GetLayoutView()) {
+ if (PaintLayer* root_layer = layout_view->Layer())
+ root_layer->SetNeedsCompositingInputsUpdate();
}
}
@@ -4367,11 +4471,21 @@ void LocalFrameView::RenderThrottlingStatusChanged() {
SetPaintArtifactCompositorNeedsUpdate();
if (!CanThrottleRendering()) {
- InvalidateForThrottlingChange();
+ // Start ticking animation frames again if necessary.
+ if (GetPage())
+ GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
+ // Ensure we'll recompute viewport intersection for the frame subtree during
+ // the scheduled visual update.
+ SetIntersectionObservationState(kRequired);
+ // When a frame is throttled, we typically delete its previous painted
+ // output, so it will need to be repainted, even if nothing else has
+ // changed.
+ if (LayoutView* layout_view = GetLayoutView())
+ layout_view->Layer()->SetNeedsRepaint();
} else if (GetFrame().IsLocalRoot()) {
// By this point, every frame in the local frame tree has become throttled,
// so painting the tree should just clear the previous painted output.
- DCHECK(!in_lifecycle_update_);
+ DCHECK(!IsUpdatingLifecycle());
AllowThrottlingScope allow_throtting(*this);
RunPaintLifecyclePhase();
}
@@ -4386,26 +4500,6 @@ void LocalFrameView::RenderThrottlingStatusChanged() {
#endif
}
-void LocalFrameView::InvalidateForThrottlingChange() {
- // Start ticking animation frames again if necessary.
- if (GetPage())
- GetPage()->Animator().ScheduleVisualUpdate(frame_.Get());
- // Force a full repaint of this frame to ensure we are not left with a
- // partially painted version of this frame's contents if we skipped
- // painting them while the frame was throttled.
- LayoutView* layout_view = GetLayoutView();
- if (layout_view) {
- layout_view->InvalidatePaintForViewAndDescendants();
- // Also need to update all paint properties that might be skipped while
- // the frame was throttled.
- layout_view->AddSubtreePaintPropertyUpdateReason(
- SubtreePaintPropertyUpdateReason::kPreviouslySkipped);
- }
- // Ensure we'll recompute viewport intersection for the frame subtree during
- // the scheduled visual update.
- SetIntersectionObservationState(kRequired);
-}
-
void LocalFrameView::SetNeedsForcedCompositingUpdate() {
needs_forced_compositing_update_ = true;
if (LocalFrameView* parent = ParentFrameView())
@@ -4479,14 +4573,25 @@ bool LocalFrameView::ShouldThrottleRendering() const {
if (!throttled_for_global_reasons || needs_forced_compositing_update_)
return false;
- if (intersection_observation_state_ == kRequired) {
- auto* local_frame_root_view = GetFrame().LocalFrameRoot().View();
- // When doing a lifecycle update required by intersection observer, we can
- // throttle lifecycle states after layout. Outside of lifecycle updates,
- // the frame should be considered throttled because it is not fully updating
- // the lifecycle.
- return !local_frame_root_view->in_lifecycle_update_ ||
- local_frame_root_view->past_layout_lifecycle_update_;
+ // If we're currently running a lifecycle update, and we are required to run
+ // the IntersectionObserver steps at the end of the update, then there are two
+ // courses of action, depending on whether this frame is display locked by its
+ // parent frame:
+ //
+ // - If it is NOT display locked, then we suppress throttling to force the
+ // lifecycle update to proceed up to the state required to run
+ // IntersectionObserver.
+ //
+ // - If it IS display locked, then we still need IntersectionObserver to
+ // run; but the display lock status will short-circuit the
+ // IntersectionObserver algorithm and create degenerate "not intersecting"
+ // notifications. Hence, we don't need to force lifecycle phases to run,
+ // because IntersectionObserver will not need access to up-to-date
+ // geometry. So there is no point in suppressing throttling here.
+ auto* local_frame_root_view = GetFrame().LocalFrameRoot().View();
+ if (local_frame_root_view->IsUpdatingLifecycle() &&
+ intersection_observation_state_ == kRequired && !IsDisplayLocked()) {
+ return Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean;
}
return true;
@@ -4498,10 +4603,10 @@ bool LocalFrameView::ShouldThrottleRenderingForTest() const {
}
bool LocalFrameView::CanThrottleRendering() const {
- if (lifecycle_updates_throttled_)
- return true;
- if (IsSubtreeThrottled())
+ if (lifecycle_updates_throttled_ || IsSubtreeThrottled() ||
+ IsDisplayLocked()) {
return true;
+ }
// We only throttle hidden cross-origin frames. This is to avoid a situation
// where an ancestor frame directly depends on the pipeline timing of a
// descendant and breaks as a result of throttling. The rationale is that
@@ -4513,10 +4618,11 @@ bool LocalFrameView::CanThrottleRendering() const {
void LocalFrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
bool subtree_throttled,
+ bool display_locked,
bool recurse) {
bool was_throttled = CanThrottleRendering();
- FrameView::UpdateRenderThrottlingStatus(hidden_for_throttling,
- subtree_throttled, recurse);
+ FrameView::UpdateRenderThrottlingStatus(
+ hidden_for_throttling, subtree_throttled, display_locked, recurse);
if (was_throttled != CanThrottleRendering())
RenderThrottlingStatusChanged();
}
@@ -4528,8 +4634,6 @@ void LocalFrameView::BeginLifecycleUpdates() {
if (GetFrame().GetDocument()->IsInitialEmptyDocument())
return;
lifecycle_updates_throttled_ = false;
- if (auto* owner = GetLayoutEmbeddedContent())
- owner->SetShouldCheckForPaintInvalidation();
LayoutView* layout_view = GetLayoutView();
bool layout_view_is_empty = layout_view && !layout_view->FirstChild();
@@ -4588,20 +4692,6 @@ int LocalFrameView::InitialViewportHeight() const {
return initial_viewport_size_.Height();
}
-bool LocalFrameView::HasVisibleSlowRepaintViewportConstrainedObjects() const {
- if (!ViewportConstrainedObjects())
- return false;
- for (const LayoutObject* layout_object : *ViewportConstrainedObjects()) {
- DCHECK(layout_object->HasLayer());
- DCHECK(layout_object->StyleRef().GetPosition() == EPosition::kFixed ||
- layout_object->StyleRef().GetPosition() == EPosition::kSticky);
- if (To<LayoutBoxModelObject>(layout_object)
- ->IsSlowRepaintConstrainedObject())
- return true;
- }
- return false;
-}
-
MainThreadScrollingReasons LocalFrameView::MainThreadScrollingReasonsPerFrame()
const {
MainThreadScrollingReasons reasons =
@@ -4614,18 +4704,6 @@ MainThreadScrollingReasons LocalFrameView::MainThreadScrollingReasonsPerFrame()
reasons |=
cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
}
-
- // Force main-thread scrolling if the frame has uncomposited position: fixed
- // elements. Note: we care about this not only for input-scrollable frames
- // but also for overflow: hidden frames, because script can run composited
- // smooth-scroll animations. For this reason, we use HasOverflow instead of
- // ScrollsOverflow (which is false for overflow: hidden).
- if (LayoutViewport()->HasOverflow() &&
- GetLayoutView()->StyleRef().VisibleToHitTesting() &&
- HasVisibleSlowRepaintViewportConstrainedObjects()) {
- reasons |=
- cc::MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
- }
return reasons;
}