summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp12
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingContext.cpp175
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingContext.h1
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingState.h9
4 files changed, 105 insertions, 92 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
index 8a47cd7245..6952f367eb 100644
--- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
@@ -1463,8 +1463,7 @@ float FlexFormattingContext::calculate_main_min_content_contribution(FlexItem co
// the larger of its outer min-content size and outer preferred size if that is not auto,
// clamped by its min/max main size.
auto outer_min_content_size = [&]() -> float {
- auto intrinsic_sizes = FormattingContext::calculate_intrinsic_sizes(item.box);
- auto inner_main_size = is_row_layout() ? intrinsic_sizes.min_content_size.width() : intrinsic_sizes.min_content_size.height();
+ auto inner_main_size = is_row_layout() ? calculate_min_content_width(item.box) : calculate_min_content_height(item.box);
auto outer_main_size = inner_main_size
+ item.margins.main_before + item.margins.main_after
+ item.borders.main_before + item.borders.main_after
@@ -1488,8 +1487,7 @@ float FlexFormattingContext::calculate_main_max_content_contribution(FlexItem co
{
// The main-size max-content contribution of a flex item is the larger of its outer max-content size and outer preferred size if that is not auto, clamped by its min/max main size.
auto outer_max_content_size = [&]() -> float {
- auto intrinsic_sizes = FormattingContext::calculate_intrinsic_sizes(item.box);
- auto inner_main_size = is_row_layout() ? intrinsic_sizes.max_content_size.width() : intrinsic_sizes.max_content_size.height();
+ auto inner_main_size = is_row_layout() ? calculate_max_content_width(item.box) : calculate_max_content_height(item.box);
auto outer_main_size = inner_main_size
+ item.margins.main_before + item.margins.main_after
+ item.borders.main_before + item.borders.main_after
@@ -1510,8 +1508,7 @@ float FlexFormattingContext::calculate_main_max_content_contribution(FlexItem co
float FlexFormattingContext::calculate_cross_min_content_contribution(FlexItem const& flex_item) const
{
- auto intrinsic_sizes = FormattingContext::calculate_intrinsic_sizes(flex_item.box);
- auto inner_cross_size = is_row_layout() ? intrinsic_sizes.min_content_size.height() : intrinsic_sizes.min_content_size.width();
+ auto inner_cross_size = is_row_layout() ? calculate_min_content_height(flex_item.box) : calculate_min_content_width(flex_item.box);
auto outer_cross_size = inner_cross_size
+ flex_item.margins.cross_before + flex_item.margins.cross_after
+ flex_item.borders.cross_before + flex_item.borders.cross_after
@@ -1521,8 +1518,7 @@ float FlexFormattingContext::calculate_cross_min_content_contribution(FlexItem c
float FlexFormattingContext::calculate_cross_max_content_contribution(FlexItem const& flex_item) const
{
- auto intrinsic_sizes = FormattingContext::calculate_intrinsic_sizes(flex_item.box);
- auto inner_cross_size = is_row_layout() ? intrinsic_sizes.max_content_size.height() : intrinsic_sizes.max_content_size.width();
+ auto inner_cross_size = is_row_layout() ? calculate_max_content_height(flex_item.box) : calculate_max_content_width(flex_item.box);
auto outer_cross_size = inner_cross_size
+ flex_item.margins.cross_before + flex_item.margins.cross_after
+ flex_item.borders.cross_before + flex_item.borders.cross_after
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
index a15981361a..afae391bbe 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
@@ -812,82 +812,6 @@ void FormattingContext::compute_inset(Box const& box)
resolve_two_opposing_insets(computed_values.inset().top, computed_values.inset().bottom, box_state.inset_top, box_state.inset_bottom, containing_block_state.content_height);
}
-FormattingState::IntrinsicSizes FormattingContext::calculate_intrinsic_sizes(Layout::Box const& box) const
-{
- // FIXME: This should handle replaced elements with "native" intrinsic size properly!
-
- if (box.has_intrinsic_width() && box.has_intrinsic_height()) {
- auto const& replaced_box = static_cast<ReplacedBox const&>(box);
- Gfx::FloatSize size { replaced_box.intrinsic_width().value_or(0), replaced_box.intrinsic_height().value_or(0) };
- return FormattingState::IntrinsicSizes {
- .min_content_size = size,
- .max_content_size = size,
- };
- }
-
- auto& root_state = m_state.m_root;
-
- // If we have cached intrinsic sizes for this box, use them.
- auto it = root_state.intrinsic_sizes.find(&box);
- if (it != root_state.intrinsic_sizes.end())
- return it->value;
-
- // Nothing cached, perform two throwaway layouts to determine the intrinsic sizes.
-
- FormattingState::IntrinsicSizes cached_box_sizes;
- auto const& containing_block = *box.containing_block();
- {
- FormattingState throwaway_state(&m_state);
- auto& containing_block_state = throwaway_state.get_mutable(containing_block);
- containing_block_state.content_width = INFINITY;
- containing_block_state.content_height = INFINITY;
- auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
- VERIFY(independent_formatting_context);
-
- independent_formatting_context->run(box, LayoutMode::MaxContent);
-
- if (independent_formatting_context->type() == FormattingContext::Type::Flex) {
- auto const& box_state = throwaway_state.get(box);
- cached_box_sizes.max_content_size = { box_state.content_width, box_state.content_height };
- } else {
- cached_box_sizes.max_content_size.set_width(independent_formatting_context->greatest_child_width(box));
- cached_box_sizes.max_content_size.set_height(calculate_auto_height(throwaway_state, box));
- }
- }
-
- {
- FormattingState throwaway_state(&m_state);
- auto& containing_block_state = throwaway_state.get_mutable(containing_block);
- containing_block_state.content_width = 0;
- containing_block_state.content_height = 0;
- auto independent_formatting_context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
- VERIFY(independent_formatting_context);
- independent_formatting_context->run(box, LayoutMode::MinContent);
- if (independent_formatting_context->type() == FormattingContext::Type::Flex) {
- auto const& box_state = throwaway_state.get(box);
- cached_box_sizes.min_content_size = { box_state.content_width, box_state.content_height };
- } else {
- cached_box_sizes.min_content_size.set_width(independent_formatting_context->greatest_child_width(box));
- cached_box_sizes.min_content_size.set_height(calculate_auto_height(throwaway_state, box));
- }
- }
-
- if (cached_box_sizes.min_content_size.width() > cached_box_sizes.max_content_size.width()) {
- float tmp = cached_box_sizes.min_content_size.width();
- cached_box_sizes.min_content_size.set_width(cached_box_sizes.max_content_size.width());
- cached_box_sizes.max_content_size.set_width(tmp);
- }
-
- if (cached_box_sizes.min_content_size.height() > cached_box_sizes.max_content_size.height()) {
- float tmp = cached_box_sizes.min_content_size.height();
- cached_box_sizes.min_content_size.set_height(cached_box_sizes.max_content_size.height());
- cached_box_sizes.max_content_size.set_height(tmp);
- }
-
- root_state.intrinsic_sizes.set(&box, cached_box_sizes);
- return cached_box_sizes;
-}
-
float FormattingContext::calculate_fit_content_size(float min_content_size, float max_content_size, Optional<float> available_space) const
{
// If the available space in a given axis is definite, equal to clamp(min-content size, stretch-fit size, max-content size)
@@ -926,22 +850,113 @@ float FormattingContext::calculate_auto_height(FormattingState const& state, Box
float FormattingContext::calculate_min_content_width(Layout::Box const& box) const
{
- return calculate_intrinsic_sizes(box).min_content_size.width();
+ if (box.has_intrinsic_width())
+ return *box.intrinsic_width();
+
+ auto& root_state = m_state.m_root;
+
+ auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new FormattingState::IntrinsicSizes); });
+ if (cache.min_content_width.has_value())
+ return *cache.min_content_width;
+
+ FormattingState throwaway_state(&m_state);
+ auto const& containing_block = *box.containing_block();
+ auto& containing_block_state = throwaway_state.get_mutable(containing_block);
+ containing_block_state.content_width = 0;
+ auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
+ VERIFY(context);
+ context->run(box, LayoutMode::MinContent);
+ if (context->type() == FormattingContext::Type::Flex) {
+ auto const& box_state = throwaway_state.get(box);
+ cache.min_content_width = box_state.content_width;
+ } else {
+ cache.min_content_width = context->greatest_child_width(box);
+ }
+ return *cache.min_content_width;
}
float FormattingContext::calculate_max_content_width(Layout::Box const& box) const
{
- return calculate_intrinsic_sizes(box).max_content_size.width();
+ if (box.has_intrinsic_width())
+ return *box.intrinsic_width();
+
+ auto& root_state = m_state.m_root;
+
+ auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new FormattingState::IntrinsicSizes); });
+ if (cache.max_content_width.has_value())
+ return *cache.max_content_width;
+
+ FormattingState throwaway_state(&m_state);
+ auto const& containing_block = *box.containing_block();
+ auto& containing_block_state = throwaway_state.get_mutable(containing_block);
+ containing_block_state.content_width = INFINITY;
+ auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
+ VERIFY(context);
+ context->run(box, LayoutMode::MaxContent);
+ if (context->type() == FormattingContext::Type::Flex) {
+ auto const& box_state = throwaway_state.get(box);
+ cache.max_content_width = box_state.content_width;
+ } else {
+ cache.max_content_width = context->greatest_child_width(box);
+ }
+
+ return *cache.max_content_width;
}
float FormattingContext::calculate_min_content_height(Layout::Box const& box) const
{
- return calculate_intrinsic_sizes(box).min_content_size.height();
+ if (box.has_intrinsic_height())
+ return *box.intrinsic_height();
+
+ auto& root_state = m_state.m_root;
+
+ auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new FormattingState::IntrinsicSizes); });
+ if (cache.min_content_height.has_value())
+ return *cache.min_content_height;
+
+ FormattingState throwaway_state(&m_state);
+ auto const& containing_block = *box.containing_block();
+ auto& containing_block_state = throwaway_state.get_mutable(containing_block);
+ containing_block_state.content_height = 0;
+ auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
+ VERIFY(context);
+ context->run(box, LayoutMode::MinContent);
+ if (context->type() == FormattingContext::Type::Flex) {
+ auto const& box_state = throwaway_state.get(box);
+ cache.min_content_height = box_state.content_height;
+ } else {
+ cache.min_content_height = calculate_auto_height(throwaway_state, box);
+ }
+
+ return *cache.min_content_height;
}
float FormattingContext::calculate_max_content_height(Layout::Box const& box) const
{
- return calculate_intrinsic_sizes(box).max_content_size.height();
+ if (box.has_intrinsic_height())
+ return *box.intrinsic_height();
+
+ auto& root_state = m_state.m_root;
+
+ auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new FormattingState::IntrinsicSizes); });
+ if (cache.max_content_height.has_value())
+ return *cache.max_content_height;
+
+ FormattingState throwaway_state(&m_state);
+ auto const& containing_block = *box.containing_block();
+ auto& containing_block_state = throwaway_state.get_mutable(containing_block);
+ containing_block_state.content_height = INFINITY;
+ auto context = const_cast<FormattingContext*>(this)->create_independent_formatting_context_if_needed(throwaway_state, box);
+ VERIFY(context);
+ context->run(box, LayoutMode::MaxContent);
+ if (context->type() == FormattingContext::Type::Flex) {
+ auto const& box_state = throwaway_state.get(box);
+ cache.max_content_height = box_state.content_height;
+ } else {
+ cache.max_content_height = calculate_auto_height(throwaway_state, box);
+ }
+
+ return *cache.max_content_height;
}
}
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h
index 98cc417cc3..5ac22caa84 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h
+++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h
@@ -59,7 +59,6 @@ protected:
FormattingContext(Type, FormattingState&, Box const&, FormattingContext* parent = nullptr);
float calculate_fit_content_size(float min_content_size, float max_content_size, Optional<float> available_space) const;
- FormattingState::IntrinsicSizes calculate_intrinsic_sizes(Layout::Box const&) const;
OwnPtr<FormattingContext> layout_inside(Box const&, LayoutMode);
void compute_inset(Box const& box);
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.h b/Userland/Libraries/LibWeb/Layout/FormattingState.h
index 50b08e6062..3c9c13b40a 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingState.h
+++ b/Userland/Libraries/LibWeb/Layout/FormattingState.h
@@ -102,10 +102,13 @@ struct FormattingState {
// We cache intrinsic sizes once determined, as they will not change over the course of a full layout.
// This avoids computing them several times while performing flex layout.
struct IntrinsicSizes {
- Gfx::FloatSize min_content_size;
- Gfx::FloatSize max_content_size;
+ Optional<float> min_content_width;
+ Optional<float> max_content_width;
+ Optional<float> min_content_height;
+ Optional<float> max_content_height;
};
- HashMap<NodeWithStyleAndBoxModelMetrics const*, IntrinsicSizes> mutable intrinsic_sizes;
+
+ HashMap<NodeWithStyleAndBoxModelMetrics const*, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes;
HashMap<Box const*, float> mutable flex_item_size_cache;