Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions Libraries/LibWeb/Layout/LayoutRustBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,18 +642,6 @@ LayoutRustBridge::LayoutRustBridge() = default;

LayoutRustBridge::~LayoutRustBridge() = default;

// Stamps the store once per pass entry, so cache entries validate against the
// viewport the pass actually laid out with; a new bridge entry method must call
// this before entering Rust.
static void note_viewport_size_for_pass(Box& pass_root)
{
auto viewport_rect = pass_root.document().viewport_rect();
RustFFI::layout_arena_note_viewport_size(
pass_root.arena_handle(),
viewport_rect.width().raw_value(),
viewport_rect.height().raw_value());
}

void LayoutRustBridge::run_root_layout(Box& viewport, CSSPixels viewport_inline_size, CSSPixels viewport_block_size, bool should_collect_devtools_layout_data)
{
VERIFY(!m_commit_root);
Expand All @@ -663,7 +651,6 @@ void LayoutRustBridge::run_root_layout(Box& viewport, CSSPixels viewport_inline_
};

viewport.document().invalidate_stacking_context_tree();
note_viewport_size_for_pass(viewport);
auto callbacks = formatting_context_callbacks();
auto sink = commit_sink();
{
Expand All @@ -688,7 +675,6 @@ void LayoutRustBridge::compute_subtree_layout(Box& root)
};

root.document().invalidate_stacking_context_tree();
note_viewport_size_for_pass(root);
auto viewport_rect = root.document().viewport_rect();
auto callbacks = formatting_context_callbacks();
auto sink = commit_sink();
Expand All @@ -714,7 +700,6 @@ void LayoutRustBridge::replay_saved_abspos_layout(Box& box)
};

box.document().invalidate_stacking_context_tree();
note_viewport_size_for_pass(box);
auto callbacks = formatting_context_callbacks();
auto sink = commit_sink();
{
Expand Down Expand Up @@ -755,6 +740,7 @@ RustFFI::FfiCommitSink LayoutRustBridge::commit_sink()
VERIFY(!bridge.m_replaced_paintable);
VERIFY(!bridge.m_commit_parent_paintable);
VERIFY(!bridge.m_commit_insert_before_paintable);
VERIFY(bridge.m_reused_paintables.is_empty());

if (!root.is_viewport()) {
bridge.m_replaced_paintable = root.paintable();
Expand All @@ -780,21 +766,35 @@ RustFFI::FfiCommitSink LayoutRustBridge::commit_sink()
}; },
.finish_commit = [](void* context) {
auto& bridge = *static_cast<LayoutRustBridge*>(context);
for (auto& reused : bridge.m_reused_paintables) {
auto new_absolute_position = reused.paintable->absolute_position();
if (new_absolute_position != reused.old_absolute_position)
reused.paintable->translate_reused_subtree_absolute_geometry(new_absolute_position - reused.old_absolute_position);
}
bridge.m_reused_paintables.clear();
bridge.m_commit_insert_before_paintable = nullptr;
bridge.m_commit_parent_paintable = nullptr;
bridge.m_replaced_paintable = nullptr; },
.prepare_node = [](void*, void* node_pointer, bool has_used_values) -> void* {
.prepare_node = [](void* context, void* node_pointer, bool has_used_values, bool reuses_committed_subtree) -> void* {
auto& bridge = *static_cast<LayoutRustBridge*>(context);
auto& node = *static_cast<Node*>(node_pointer);

RefPtr<Painting::Paintable> paintable;
if (has_used_values || (node.is_fragmented_inline() && node.dom_node())) {
// Inline boxes that never went through inline layout (so they have no used values) still
// need a paintable so DOM geometry queries have something to answer from.
paintable = node.paintable();
if (paintable)
if (reuses_committed_subtree) {
VERIFY(paintable);
bridge.m_reused_paintables.append({ *paintable, paintable->absolute_position() });
if (paintable->parent())
paintable->remove();
paintable->set_containing_block(nullptr);
} else if (paintable) {
paintable->reset_for_relayout();
else
} else {
paintable = node.create_paintable();
}
node.set_paintable(paintable);
} else if (node.paintable_ptr()) {
// A paintable surviving from a previous layout on a node this pass did not lay out is
Expand Down Expand Up @@ -831,9 +831,14 @@ RustFFI::FfiCommitSink LayoutRustBridge::commit_sink()
CSSPixels::from_raw(metrics.margin_bottom),
CSSPixels::from_raw(metrics.margin_left),
};
paintable.set_content_size(
CSSPixelSize content_size {
CSSPixels::from_raw(metrics.content_inline_size),
CSSPixels::from_raw(metrics.content_block_size));
CSSPixels::from_raw(metrics.content_block_size)
};
if (metrics.reuses_committed_subtree)
VERIFY(paintable.content_size() == content_size);
else
paintable.set_content_size(content_size);
paintable.set_offset({
CSSPixels::from_raw(metrics.content_offset.x),
CSSPixels::from_raw(metrics.content_offset.y),
Expand Down
6 changes: 6 additions & 0 deletions Libraries/LibWeb/Layout/LayoutRustBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <AK/OwnPtr.h>
#include <AK/RefPtr.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/PercentageOr.h>
#include <LibWeb/Export.h>
Expand Down Expand Up @@ -41,11 +42,16 @@ class LayoutRustBridge {
[[nodiscard]] RustFFI::FfiCommitSink commit_sink();

struct LineCommitContext;
struct ReusedPaintable {
NonnullRefPtr<Painting::Paintable> paintable;
CSSPixelPoint old_absolute_position;
};
Box const* m_commit_root { nullptr };
OwnPtr<LineCommitContext> m_line_commit_context;
RefPtr<Painting::Paintable> m_replaced_paintable;
RefPtr<Painting::Paintable> m_commit_parent_paintable;
RefPtr<Painting::Paintable> m_commit_insert_before_paintable;
Vector<ReusedPaintable> m_reused_paintables;
};

[[nodiscard]] Optional<RustFFI::FfiFormattingContextType> formatting_context_type_created_by_box(Box const&);
Expand Down
10 changes: 9 additions & 1 deletion Libraries/LibWeb/Layout/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,15 @@ void* Node::arena_handle() const

void Node::synchronize_topology()
{
m_data->parent = slot_id(Base::parent_ptr());
auto old_parent = m_data->parent;
auto new_parent = slot_id(Base::parent_ptr());
if (old_parent.index != new_parent.index) {
if (old_parent.index != RustFFI::NodeSlotId_INVALID.index)
node_arena().note_inline_layout_damage(old_parent);
if (new_parent.index != RustFFI::NodeSlotId_INVALID.index)
node_arena().note_inline_layout_damage(new_parent);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
m_data->parent = new_parent;
m_data->first_child = slot_id(Base::first_child_ptr());
m_data->last_child = slot_id(Base::last_child_ptr());
m_data->previous_sibling = slot_id(Base::previous_sibling_ptr());
Expand Down
5 changes: 5 additions & 0 deletions Libraries/LibWeb/Layout/NodeArena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ u64 NodeArena::formatting_context_run_cache_hit_count() const
return RustFFI::layout_arena_fc_run_cache_hit_count(m_handle);
}

void NodeArena::note_inline_layout_damage(RustFFI::NodeSlotId box)
{
RustFFI::layout_arena_note_inline_layout_damage(m_handle, box);
}

void NodeArena::enroll_text_node_for_content_sync(TextNode const& text_node)
{
m_text_nodes_enrolled_for_content_sync.append(text_node.make_weak_ptr<TextNode>());
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/Layout/NodeArena.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class WEB_API NodeArena : public RefCounted<NodeArena> {
void free(RustFFI::NodeSlotId, u32 generation);
void* handle() const { return m_handle; }
u64 formatting_context_run_cache_hit_count() const;
void note_inline_layout_damage(RustFFI::NodeSlotId);

void enroll_text_node_for_content_sync(TextNode const&);
void enroll_node_for_replaced_content_facts_sync(Node const&);
Expand Down
12 changes: 12 additions & 0 deletions Libraries/LibWeb/Painting/Paintable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,18 @@ void Paintable::invalidate_absolute_geometry_cache(InvalidateDescendantGeometry
});
}

void Paintable::translate_reused_subtree_absolute_geometry(CSSPixelPoint delta)
{
for_each_in_inclusive_subtree([&](Paintable& paintable) {
paintable.invalidate_absolute_geometry_cache(InvalidateDescendantGeometry::No);
if (paintable.m_overflow_data.has_value())
paintable.m_overflow_data->scrollable_overflow_rect.translate_by(delta);
// Recorded paint commands bake absolute coordinates.
paintable.invalidate_paint_cache();
return TraversalDecision::Continue;
});
}

CSSPixelPoint Paintable::offset() const
{
return m_offset;
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/Painting/Paintable.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ class WEB_API Paintable

void paint_middle_button_scroll_indicator(DisplayListRecordingContext&) const;
void invalidate_absolute_geometry_cache(InvalidateDescendantGeometry);
void translate_reused_subtree_absolute_geometry(CSSPixelPoint);

GC::Weak<DOM::Node> m_dom_node;
WeakPtr<Layout::NodeWithStyle const> m_layout_node;
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/Rust/src/layout/abspos_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,7 @@ pub(crate) fn drain_abspos_with_placed_containing_blocks(
should_collect_devtools_layout_data,
treat_block_axis_percentage_insets_as_auto_beyond_root: false,
fragments: Some(entry_fragments.clone()),
previous_line_data: None,
};
loop {
let batch = entry_fragments.take_drainable_abspos(accumulator_root, records, &callbacks);
Expand Down
15 changes: 14 additions & 1 deletion Libraries/LibWeb/Rust/src/layout/block_formatting_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,11 @@ pub(crate) struct BlockFormattingContext {
derived_baselines_of_root_box: Cell<DerivedBaselines>,
trailing_collapsed_margin: Cell<Option<(Node, CssPixels)>>,
table_box_in_wrapper_border_box_block_size: Cell<Option<CssPixels>>,
min_content_inline_size_from_max_content_layout: Cell<Option<CssPixels>>,
fragments: Option<std::rc::Rc<RunFragmentBuilder>>,
should_collect_devtools_layout_data: bool,
treat_block_axis_percentage_insets_as_auto_beyond_root: bool,
previous_line_data: Option<std::rc::Rc<LineData>>,
}

impl BlockFormattingContext {
Expand All @@ -222,8 +224,10 @@ impl BlockFormattingContext {
derived_baselines_of_root_box: Cell::new(DerivedBaselines::default()),
trailing_collapsed_margin: Cell::new(None),
table_box_in_wrapper_border_box_block_size: Cell::new(None),
min_content_inline_size_from_max_content_layout: Cell::new(None),
should_collect_devtools_layout_data: run.should_collect_devtools_layout_data,
treat_block_axis_percentage_insets_as_auto_beyond_root: run.treat_block_axis_percentage_insets_as_auto_beyond_root,
previous_line_data: run.previous_line_data.clone(),
}
}

Expand All @@ -237,6 +241,7 @@ impl BlockFormattingContext {
should_collect_devtools_layout_data: self.should_collect_devtools_layout_data,
treat_block_axis_percentage_insets_as_auto_beyond_root: self.treat_block_axis_percentage_insets_as_auto_beyond_root,
fragments: self.fragments.clone(),
previous_line_data: self.previous_line_data.clone(),
}
}

Expand Down Expand Up @@ -293,7 +298,7 @@ impl BlockFormattingContext {
ancestor == node || self.is_ancestor_of(ancestor, node)
}

fn sizing(&self) -> SizingContext {
pub(crate) fn sizing(&self) -> SizingContext {
SizingContext::new(self.purpose, self.records.clone(), self.callbacks)
}

Expand Down Expand Up @@ -2550,6 +2555,10 @@ impl BlockFormattingContext {
context.run();
let automatic_inline_size = context.automatic_content_inline_size;
let automatic_block_size = context.automatic_content_block_size;
if block_container == self.root {
self.min_content_inline_size_from_max_content_layout
.set(context.min_content_inline_size_from_max_content_layout);
}
if !self.used(block_container).has_definite_inline_size() {
// NOTE: min-width or max-width for boxes with inline children can only be applied after inside layout
// is done and the inline size of the box content is known
Expand Down Expand Up @@ -2843,6 +2852,10 @@ impl BlockFormattingContext {
self.greatest_child_inline_size_including_floats(self.root)
}

pub(crate) fn min_content_inline_size_from_max_content_layout(&self) -> Option<CssPixels> {
self.min_content_inline_size_from_max_content_layout.get()
}

pub(crate) fn automatic_content_block_size(&self) -> CssPixels {
automatic_block_size_for_bfc_root(
&self.records,
Expand Down
35 changes: 27 additions & 8 deletions Libraries/LibWeb/Rust/src/layout/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct FfiTableCellCoordinates {
#[repr(C)]
pub struct FfiCommittedBoxMetrics {
pub fragment_identity: u64,
pub reuses_committed_subtree: bool,
pub content_offset: crate::layout::FfiCssPixelPoint,
pub content_inline_size: crate::layout::CssPixels,
pub content_block_size: crate::layout::CssPixels,
Expand Down Expand Up @@ -85,7 +86,7 @@ pub struct FfiCommitSink {
pub context: *mut c_void,
pub begin_commit: unsafe extern "C" fn(*mut c_void, *mut c_void) -> FfiCommitPosition,
pub finish_commit: unsafe extern "C" fn(*mut c_void),
pub prepare_node: unsafe extern "C" fn(*mut c_void, *mut c_void, bool) -> *mut c_void,
pub prepare_node: unsafe extern "C" fn(*mut c_void, *mut c_void, bool, bool) -> *mut c_void,
pub set_box_metrics: unsafe extern "C" fn(*mut c_void, *mut c_void, FfiCommittedBoxMetrics),
pub set_override_borders: unsafe extern "C" fn(*mut c_void, *mut c_void, FfiBordersData),
pub set_table_cell_coordinates: unsafe extern "C" fn(*mut c_void, *mut c_void, FfiTableCellCoordinates),
Expand Down Expand Up @@ -116,6 +117,8 @@ fn commit_subtree(
) {
let slot_index = callbacks.slot_index(node);
let entry = scopes.link_for_slot(slot_index);
let reuses_committed_subtree = scopes.subtree_was_reused(slot_index);
debug_assert!(!reuses_committed_subtree || entry.is_some());
if let Some(link) = entry {
callbacks.set_saved_abspos_layout_inputs(node, link.abspos_layout_inputs);
// SVG roots are the only non-abspos partial relayout boundaries; save their committed
Expand Down Expand Up @@ -156,7 +159,14 @@ fn commit_subtree(
// SAFETY: The C++ sink owns paintables and copies every plain-data
// input synchronously.
let node_shell = callbacks.shell(node);
let paintable = unsafe { (sink.prepare_node)(sink.context, node_shell, entry.is_some()) };
let paintable = unsafe {
(sink.prepare_node)(
sink.context,
node_shell,
entry.is_some(),
reuses_committed_subtree,
)
};

let mut has_pending_inline_box_geometry = false;
if let Some(link) = entry
Expand All @@ -171,6 +181,7 @@ fn commit_subtree(
paintable,
FfiCommittedBoxMetrics {
fragment_identity: fragment.identity,
reuses_committed_subtree,
content_offset: link.committed_offset,
content_inline_size: fragment.content_inline_size,
content_block_size: fragment.content_block_size,
Expand All @@ -196,16 +207,18 @@ fn commit_subtree(
);
}

unsafe {
if !reuses_committed_subtree {
unsafe {
if let Some(borders) = fragment.override_borders_data {
(sink.set_override_borders)(sink.context, paintable, borders);
}
if let Some(coordinates) = fragment.table_cell_coordinates {
(sink.set_table_cell_coordinates)(sink.context, paintable, coordinates);
}
}
}

if let Some(line_data) = &fragment.line_data {
if !reuses_committed_subtree && let Some(line_data) = &fragment.line_data {
// SAFETY: The sink keeps one line accumulator live between
// begin_line_data() and finish_line_data().
let accepts_lines = unsafe { (sink.begin_line_data)(sink.context, paintable) };
Expand All @@ -224,7 +237,8 @@ fn commit_subtree(
}
}

unsafe {
if !reuses_committed_subtree {
unsafe {
if let Some(transform) = fragment.svg_viewport_transform {
(sink.set_svg_viewport_transform)(sink.context, paintable, transform);
}
Expand All @@ -245,18 +259,19 @@ fn commit_subtree(
if let Some(path) = &fragment.computed_svg_path {
(sink.set_computed_svg_path)(sink.context, paintable, path.as_raw(), path.identity());
}
}
}
if let Some(data) = &fragment.grid_layout_data {
if !reuses_committed_subtree && let Some(data) = &fragment.grid_layout_data {
data.with_ffi_view(|view| {
unsafe { (sink.set_grid_layout_data)(sink.context, paintable, view) };
});
}
if let Some(data) = &fragment.flex_layout_data {
if !reuses_committed_subtree && let Some(data) = &fragment.flex_layout_data {
data.with_ffi_view(|view| {
unsafe { (sink.set_flex_layout_data)(sink.context, paintable, view) };
});
}
if let Some(tracks) = &fragment.used_grid_tracks {
if !reuses_committed_subtree && let Some(tracks) = &fragment.used_grid_tracks {
tracks.with_ffi_views(|columns, rows| {
unsafe { (sink.set_used_grid_tracks)(sink.context, paintable, columns, rows) };
});
Expand All @@ -276,6 +291,10 @@ fn commit_subtree(
};
assert_eq!(result.paintable, paintable);

if reuses_committed_subtree {
return;
}

if let Some(link) = entry {
scopes.open_scope(&link.fragment.children);
}
Expand Down
Loading
Loading