mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:07:35 +00:00
LibWeb: Make FormattingContext::run() take available space as input
Instead of formatting contexts flailing around to figure out from the "inside" how much space is available on the "outside", we should provide the amount of available space in both axes as an input to run(). This basically means that when something creates a nested formatting context, the parent context is responsible for telling the nested context how much space is available for layout. This information is provided immediately when invoking run(). Note that this commit doesn't pass accurate values in all cases yet. This first step just makes it build, and passes available values in some cases where getting them was trivial.
This commit is contained in:
parent
6b2ce2ccc3
commit
f161e20e57
17 changed files with 163 additions and 41 deletions
|
@ -809,7 +809,11 @@ void Document::update_layout()
|
|||
icb_state.set_content_width(viewport_rect.width());
|
||||
icb_state.set_content_height(viewport_rect.height());
|
||||
|
||||
root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Normal);
|
||||
root_formatting_context.run(
|
||||
*m_layout_root,
|
||||
Layout::LayoutMode::Normal,
|
||||
Layout::AvailableSpace::make_definite(viewport_rect.width()),
|
||||
Layout::AvailableSpace::make_definite(viewport_rect.height()));
|
||||
}
|
||||
|
||||
layout_state.commit();
|
||||
|
|
53
Userland/Libraries/LibWeb/Layout/AvailableSpace.cpp
Normal file
53
Userland/Libraries/LibWeb/Layout/AvailableSpace.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Layout/AvailableSpace.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
||||
AvailableSpace AvailableSpace::make_definite(float value)
|
||||
{
|
||||
return AvailableSpace { Type::Definite, value };
|
||||
}
|
||||
|
||||
AvailableSpace AvailableSpace::make_indefinite()
|
||||
{
|
||||
return AvailableSpace { Type::Indefinite, INFINITY };
|
||||
}
|
||||
|
||||
AvailableSpace AvailableSpace::make_min_content()
|
||||
{
|
||||
return AvailableSpace { Type::MinContent, 0 };
|
||||
}
|
||||
|
||||
AvailableSpace AvailableSpace::make_max_content()
|
||||
{
|
||||
return AvailableSpace { Type::MaxContent, INFINITY };
|
||||
}
|
||||
|
||||
String AvailableSpace::to_string() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Definite:
|
||||
return String::formatted("definite({})", m_value);
|
||||
case Type::Indefinite:
|
||||
return "indefinite";
|
||||
case Type::MinContent:
|
||||
return "min-content";
|
||||
case Type::MaxContent:
|
||||
return "max-content";
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
AvailableSpace::AvailableSpace(Type type, float value)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
63
Userland/Libraries/LibWeb/Layout/AvailableSpace.h
Normal file
63
Userland/Libraries/LibWeb/Layout/AvailableSpace.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
||||
class AvailableSpace {
|
||||
public:
|
||||
enum class Type {
|
||||
Definite,
|
||||
Indefinite,
|
||||
MinContent,
|
||||
MaxContent,
|
||||
};
|
||||
|
||||
static AvailableSpace make_definite(float);
|
||||
static AvailableSpace make_indefinite();
|
||||
static AvailableSpace make_min_content();
|
||||
static AvailableSpace make_max_content();
|
||||
|
||||
bool is_definite() const { return m_type == Type::Definite; }
|
||||
bool is_indefinite() const { return m_type == Type::Indefinite; }
|
||||
bool is_min_content() const { return m_type == Type::MinContent; }
|
||||
bool is_max_content() const { return m_type == Type::MaxContent; }
|
||||
bool is_intrinsic_sizing_constraint() const { return is_min_content() || is_max_content(); }
|
||||
|
||||
float definite_value() const
|
||||
{
|
||||
VERIFY(is_definite());
|
||||
return m_value;
|
||||
}
|
||||
|
||||
float to_px() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
AvailableSpace(Type type, float);
|
||||
|
||||
Type m_type {};
|
||||
float m_value {};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<Web::Layout::AvailableSpace> : Formatter<StringView> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, Web::Layout::AvailableSpace const& available_space)
|
||||
{
|
||||
return Formatter<StringView>::format(builder, available_space.to_string());
|
||||
}
|
||||
};
|
|
@ -44,7 +44,7 @@ float BlockFormattingContext::automatic_content_height() const
|
|||
return compute_auto_height_for_block_formatting_context_root(m_state, root());
|
||||
}
|
||||
|
||||
void BlockFormattingContext::run(Box const&, LayoutMode layout_mode)
|
||||
void BlockFormattingContext::run(Box const&, LayoutMode layout_mode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
if (is_initial()) {
|
||||
layout_initial_containing_block(layout_mode);
|
||||
|
@ -366,7 +366,11 @@ void BlockFormattingContext::layout_inline_children(BlockContainer const& block_
|
|||
}
|
||||
|
||||
InlineFormattingContext context(m_state, block_container, *this);
|
||||
context.run(block_container, layout_mode);
|
||||
context.run(
|
||||
block_container,
|
||||
layout_mode,
|
||||
AvailableSpace::make_definite(containing_block_width_for(block_container)),
|
||||
AvailableSpace::make_definite(containing_block_height_for(block_container)));
|
||||
|
||||
float max_line_width = 0;
|
||||
float content_height = 0;
|
||||
|
@ -419,7 +423,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
} else {
|
||||
independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
|
||||
if (independent_formatting_context)
|
||||
independent_formatting_context->run(box, layout_mode);
|
||||
independent_formatting_context->run(box, layout_mode, AvailableSpace::make_indefinite(), AvailableSpace::make_indefinite());
|
||||
else
|
||||
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode);
|
||||
}
|
||||
|
@ -442,19 +446,6 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
independent_formatting_context->parent_context_did_dimension_child_root_box();
|
||||
}
|
||||
|
||||
void BlockFormattingContext::run_intrinsic_sizing(Box const& box)
|
||||
{
|
||||
auto& box_state = m_state.get_mutable(box);
|
||||
|
||||
if (box_state.has_definite_width())
|
||||
box_state.set_content_width(box.computed_values().width().resolved(box, CSS::Length::make_px(containing_block_width_for(box))).to_px(box));
|
||||
|
||||
if (box_state.has_definite_height())
|
||||
box_state.set_content_height(box.computed_values().height().resolved(box, CSS::Length::make_px(containing_block_height_for(box))).to_px(box));
|
||||
|
||||
run(box, LayoutMode::IntrinsicSizing);
|
||||
}
|
||||
|
||||
void BlockFormattingContext::layout_block_level_children(BlockContainer const& block_container, LayoutMode layout_mode)
|
||||
{
|
||||
VERIFY(!block_container.children_are_inline());
|
||||
|
|
|
@ -21,8 +21,7 @@ public:
|
|||
explicit BlockFormattingContext(LayoutState&, BlockContainer const&, FormattingContext* parent);
|
||||
~BlockFormattingContext();
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run_intrinsic_sizing(Box const&) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
|
||||
bool is_initial() const;
|
||||
|
|
|
@ -67,7 +67,7 @@ float FlexFormattingContext::automatic_content_height() const
|
|||
return m_state.get(flex_container()).content_height();
|
||||
}
|
||||
|
||||
void FlexFormattingContext::run(Box const& run_box, LayoutMode layout_mode)
|
||||
void FlexFormattingContext::run(Box const& run_box, LayoutMode layout_mode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
VERIFY(&run_box == &flex_container());
|
||||
|
||||
|
@ -598,7 +598,7 @@ void FlexFormattingContext::determine_available_main_and_cross_space(bool& main_
|
|||
cross_available_space = cross_max_size;
|
||||
}
|
||||
|
||||
m_available_space = AvailableSpace { .main = main_available_space, .cross = cross_available_space };
|
||||
m_available_space = AvailableSpaceForItems { .main = main_available_space, .cross = cross_available_space };
|
||||
}
|
||||
|
||||
float FlexFormattingContext::calculate_indefinite_main_size(FlexItem const& item)
|
||||
|
@ -635,7 +635,7 @@ float FlexFormattingContext::calculate_indefinite_main_size(FlexItem const& item
|
|||
VERIFY(independent_formatting_context);
|
||||
|
||||
box_state.set_content_width(fit_content_cross_size);
|
||||
independent_formatting_context->run(item.box, LayoutMode::Normal);
|
||||
independent_formatting_context->run(item.box, LayoutMode::Normal, AvailableSpace::make_indefinite(), AvailableSpace::make_indefinite());
|
||||
|
||||
return independent_formatting_context->automatic_content_height();
|
||||
}
|
||||
|
@ -1100,7 +1100,7 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
|
|||
// NOTE: Flex items should always create an independent formatting context!
|
||||
VERIFY(independent_formatting_context);
|
||||
|
||||
independent_formatting_context->run(item.box, LayoutMode::Normal);
|
||||
independent_formatting_context->run(item.box, LayoutMode::Normal, AvailableSpace::make_indefinite(), AvailableSpace::make_indefinite());
|
||||
|
||||
auto automatic_cross_size = is_row_layout() ? independent_formatting_context->automatic_content_height()
|
||||
: box_state.content_width();
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
|
||||
virtual bool inhibits_floating() const override { return true; }
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
|
||||
Box const& flex_container() const { return context_box(); }
|
||||
|
@ -190,11 +190,11 @@ private:
|
|||
Vector<FlexItem> m_flex_items;
|
||||
CSS::FlexDirection m_flex_direction {};
|
||||
|
||||
struct AvailableSpace {
|
||||
struct AvailableSpaceForItems {
|
||||
Optional<float> main;
|
||||
Optional<float> cross;
|
||||
};
|
||||
Optional<AvailableSpace> m_available_space;
|
||||
Optional<AvailableSpaceForItems> m_available_space;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,18 @@ void FormattingContext::run_intrinsic_sizing(Box const& box)
|
|||
if (box_state.has_definite_height())
|
||||
box_state.set_content_height(box.computed_values().height().resolved(box, CSS::Length::make_px(containing_block_height_for(box))).to_px(box));
|
||||
|
||||
run(box, LayoutMode::IntrinsicSizing);
|
||||
auto to_available_space = [&](SizeConstraint constraint) {
|
||||
if (constraint == SizeConstraint::MinContent)
|
||||
return AvailableSpace::make_min_content();
|
||||
if (constraint == SizeConstraint::MaxContent)
|
||||
return AvailableSpace::make_max_content();
|
||||
return AvailableSpace::make_indefinite();
|
||||
};
|
||||
|
||||
auto available_width = to_available_space(box_state.width_constraint);
|
||||
auto available_height = to_available_space(box_state.height_constraint);
|
||||
|
||||
run(box, LayoutMode::IntrinsicSizing, available_width, available_height);
|
||||
}
|
||||
|
||||
bool FormattingContext::creates_block_formatting_context(Box const& box)
|
||||
|
@ -104,7 +115,7 @@ OwnPtr<FormattingContext> FormattingContext::create_independent_formatting_conte
|
|||
{
|
||||
}
|
||||
virtual float automatic_content_height() const override { return 0; };
|
||||
virtual void run(Box const&, LayoutMode) override { }
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const&, AvailableSpace const&) override { }
|
||||
};
|
||||
return make<ReplacedFormattingContext>(state, child_box);
|
||||
}
|
||||
|
@ -146,7 +157,7 @@ OwnPtr<FormattingContext> FormattingContext::create_independent_formatting_conte
|
|||
{
|
||||
}
|
||||
virtual float automatic_content_height() const override { return 0; };
|
||||
virtual void run(Box const&, LayoutMode) override { }
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const&, AvailableSpace const&) override { }
|
||||
};
|
||||
return make<DummyFormattingContext>(state, child_box);
|
||||
}
|
||||
|
@ -176,9 +187,9 @@ OwnPtr<FormattingContext> FormattingContext::layout_inside(Box const& child_box,
|
|||
|
||||
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, child_box);
|
||||
if (independent_formatting_context)
|
||||
independent_formatting_context->run(child_box, layout_mode);
|
||||
independent_formatting_context->run(child_box, layout_mode, AvailableSpace::make_indefinite(), AvailableSpace::make_indefinite());
|
||||
else
|
||||
run(child_box, layout_mode);
|
||||
run(child_box, layout_mode, AvailableSpace::make_indefinite(), AvailableSpace::make_indefinite());
|
||||
|
||||
return independent_formatting_context;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Layout/AvailableSpace.h>
|
||||
#include <LibWeb/Layout/LayoutState.h>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
@ -24,7 +25,7 @@ public:
|
|||
SVG,
|
||||
};
|
||||
|
||||
virtual void run(Box const&, LayoutMode) = 0;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) = 0;
|
||||
|
||||
// This function returns the automatic content height of the context's root box.
|
||||
virtual float automatic_content_height() const = 0;
|
||||
|
@ -64,7 +65,7 @@ public:
|
|||
static float containing_block_width_for(Box const&, LayoutState const&);
|
||||
static float containing_block_height_for(Box const&, LayoutState const&);
|
||||
|
||||
virtual void run_intrinsic_sizing(Box const&);
|
||||
void run_intrinsic_sizing(Box const&);
|
||||
|
||||
float compute_box_y_position_with_respect_to_siblings(Box const&, LayoutState::UsedValues const&);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ GridFormattingContext::GridFormattingContext(LayoutState& state, BlockContainer
|
|||
|
||||
GridFormattingContext::~GridFormattingContext() = default;
|
||||
|
||||
void GridFormattingContext::run(Box const& box, LayoutMode)
|
||||
void GridFormattingContext::run(Box const& box, LayoutMode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
auto should_skip_is_anonymous_text_run = [&](Box& child_box) -> bool {
|
||||
if (child_box.is_anonymous() && !child_box.first_child_of_type<BlockContainer>()) {
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
explicit GridFormattingContext(LayoutState&, BlockContainer const&, FormattingContext* parent);
|
||||
~GridFormattingContext();
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -83,7 +83,7 @@ float InlineFormattingContext::automatic_content_height() const
|
|||
return compute_auto_height_for_block_formatting_context_root(m_state, containing_block());
|
||||
}
|
||||
|
||||
void InlineFormattingContext::run(Box const&, LayoutMode layout_mode)
|
||||
void InlineFormattingContext::run(Box const&, LayoutMode layout_mode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
VERIFY(containing_block().children_are_inline());
|
||||
generate_line_boxes(layout_mode);
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
|
||||
BlockContainer const& containing_block() const { return static_cast<BlockContainer const&>(context_box()); }
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
|
||||
void dimension_box_on_line(Box const&, LayoutMode);
|
||||
|
|
|
@ -25,7 +25,7 @@ float SVGFormattingContext::automatic_content_height() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
void SVGFormattingContext::run(Box const& box, LayoutMode)
|
||||
void SVGFormattingContext::run(Box const& box, LayoutMode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
auto& svg_svg_element = verify_cast<SVG::SVGSVGElement>(*box.dom_node());
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
explicit SVGFormattingContext(LayoutState&, Box const&, FormattingContext* parent);
|
||||
~SVGFormattingContext();
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ TableFormattingContext::TableFormattingContext(LayoutState& state, BlockContaine
|
|||
|
||||
TableFormattingContext::~TableFormattingContext() = default;
|
||||
|
||||
void TableFormattingContext::run(Box const& box, LayoutMode)
|
||||
void TableFormattingContext::run(Box const& box, LayoutMode, [[maybe_unused]] AvailableSpace const& available_width, [[maybe_unused]] AvailableSpace const& available_height)
|
||||
{
|
||||
auto& box_state = m_state.get_mutable(box);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
explicit TableFormattingContext(LayoutState&, BlockContainer const&, FormattingContext* parent);
|
||||
~TableFormattingContext();
|
||||
|
||||
virtual void run(Box const&, LayoutMode) override;
|
||||
virtual void run(Box const&, LayoutMode, AvailableSpace const& available_width, AvailableSpace const& available_height) override;
|
||||
virtual float automatic_content_height() const override;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue