mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-01 12:07:14 +02:00
Parent document paints could still record and paint a nested iframe's contents even while the child document was render-blocked. That let unstyled iframe content leak into the parent display list before the child's blocking stylesheet had loaded, which matched the FOUC seen in Speedometer's TodoMVC suites. Skip painting hosted documents from NavigableContainerViewportPaintable while they are render-blocked. Add a reftest that keeps an iframe child render-blocked with a delayed stylesheet and forces a parent repaint; without the fix the child's inline FAIL text becomes visible. The new reftest passes with this change, and the existing render- blocking requestAnimationFrame tests still pass.
82 lines
3.1 KiB
C++
82 lines
3.1 KiB
C++
/*
|
|
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibWeb/DOM/Document.h>
|
|
#include <LibWeb/HTML/Navigable.h>
|
|
#include <LibWeb/HTML/NavigableContainer.h>
|
|
#include <LibWeb/Layout/NavigableContainerViewport.h>
|
|
#include <LibWeb/Layout/Viewport.h>
|
|
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
|
|
#include <LibWeb/Painting/DisplayList.h>
|
|
#include <LibWeb/Painting/DisplayListRecorder.h>
|
|
#include <LibWeb/Painting/NavigableContainerViewportPaintable.h>
|
|
#include <LibWeb/Painting/ViewportPaintable.h>
|
|
|
|
namespace Web::Painting {
|
|
|
|
GC_DEFINE_ALLOCATOR(NavigableContainerViewportPaintable);
|
|
|
|
GC::Ref<NavigableContainerViewportPaintable> NavigableContainerViewportPaintable::create(Layout::NavigableContainerViewport const& layout_box)
|
|
{
|
|
return layout_box.heap().allocate<NavigableContainerViewportPaintable>(layout_box);
|
|
}
|
|
|
|
NavigableContainerViewportPaintable::NavigableContainerViewportPaintable(Layout::NavigableContainerViewport const& layout_box)
|
|
: PaintableBox(layout_box)
|
|
{
|
|
}
|
|
|
|
void NavigableContainerViewportPaintable::paint(DisplayListRecordingContext& context, PaintPhase phase) const
|
|
{
|
|
if (!is_visible())
|
|
return;
|
|
|
|
PaintableBox::paint(context, phase);
|
|
|
|
if (phase == PaintPhase::Foreground) {
|
|
auto absolute_rect = this->absolute_rect();
|
|
auto clip_rect = context.rounded_device_rect(absolute_rect);
|
|
ScopedCornerRadiusClip corner_clip { context, clip_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
|
|
|
|
auto const& navigable_container = this->navigable_container();
|
|
auto* hosted_document = const_cast<DOM::Document*>(navigable_container.content_document_without_origin_check());
|
|
if (!hosted_document)
|
|
return;
|
|
|
|
if (hosted_document->is_render_blocked())
|
|
return;
|
|
|
|
// NB: The hosted document's layout may have been invalidated during the parent
|
|
// document's layout (e.g., via viewport size changes in did_set_content_size).
|
|
// Ensure it is up to date before painting.
|
|
hosted_document->update_layout(DOM::UpdateLayoutReason::HostedDocumentBeforePaint);
|
|
|
|
auto const* hosted_paint_tree = hosted_document->paintable();
|
|
if (!hosted_paint_tree)
|
|
return;
|
|
|
|
context.display_list_recorder().save();
|
|
|
|
context.display_list_recorder().add_clip_rect(clip_rect.to_type<int>());
|
|
|
|
HTML::PaintConfig paint_config;
|
|
paint_config.paint_overlay = context.should_paint_overlay();
|
|
paint_config.should_show_line_box_borders = context.should_show_line_box_borders();
|
|
auto display_list = hosted_document->record_display_list(paint_config);
|
|
context.display_list_recorder().paint_nested_display_list(display_list, context.enclosing_device_rect(absolute_rect).to_type<int>());
|
|
|
|
context.display_list_recorder().restore();
|
|
|
|
if constexpr (HIGHLIGHT_FOCUSED_FRAME_DEBUG) {
|
|
if (navigable_container.content_navigable()->is_focused()) {
|
|
context.display_list_recorder().draw_rect(clip_rect.to_type<int>(), Color::Cyan);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|