From 23dce0e38756861b37fd61542c09668c9df81b4c Mon Sep 17 00:00:00 2001 From: AmaiKinono Date: Tue, 17 Sep 2024 23:16:49 +0800 Subject: [PATCH] Compute shrink-to-fit width for tables --- Source/Core/Layout/ContainerBox.cpp | 7 +++-- Source/Core/Layout/LayoutDetails.cpp | 9 +----- Source/Core/Layout/TableFormattingContext.cpp | 31 +++++++++++++++++++ Source/Core/Layout/TableFormattingContext.h | 3 ++ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/Source/Core/Layout/ContainerBox.cpp b/Source/Core/Layout/ContainerBox.cpp index 133e7060e..658a5b021 100644 --- a/Source/Core/Layout/ContainerBox.cpp +++ b/Source/Core/Layout/ContainerBox.cpp @@ -32,6 +32,7 @@ #include "../../../Include/RmlUi/Core/ElementScroll.h" #include "../../../Include/RmlUi/Core/Profiling.h" #include "FlexFormattingContext.h" +#include "TableFormattingContext.h" #include "FormattingContext.h" #include "LayoutDetails.h" #include @@ -305,12 +306,12 @@ void TableWrapper::Close(const Vector2f content_overflow_size, const Box& box, f float TableWrapper::GetShrinkToFitWidth() const { - // We don't currently support shrink-to-fit layout of tables. However, for the trivial case of a fixed width, we - // simply return that. + // For the trivial case of a fixed width, we simply return that. if (element->GetComputedValues().width().type == Style::Width::Type::Length) return box.GetSize().x; - return 0.0f; + // Infer shrink-to-fit width from the intrinsic width of the element. + return TableFormattingContext::GetMaxContentSize(element).x; } String TableWrapper::DebugDumpTree(int depth) const diff --git a/Source/Core/Layout/LayoutDetails.cpp b/Source/Core/Layout/LayoutDetails.cpp index 0378af350..b885f8b21 100644 --- a/Source/Core/Layout/LayoutDetails.cpp +++ b/Source/Core/Layout/LayoutDetails.cpp @@ -257,13 +257,6 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b return box.GetSize().x; } - // Currently we don't support shrink-to-fit width for tables. Just return a zero-sized width. - const Style::Display display = element->GetDisplay(); - if (display == Style::Display::Table || display == Style::Display::InlineTable) - { - return 0.f; - } - // Use a large size for the box content width, so that it is practically unconstrained. This makes the formatting // procedure act as if under a maximum content constraint. Children with percentage sizing values may be scaled // based on this width (such as 'width' or 'margin'), if so, the layout is considered undefined like in CSS 2. @@ -453,7 +446,7 @@ void LayoutDetails::BuildBoxWidth(Box& box, const ComputedValues& computed, floa // See CSS 2.1 section 10.3.7 for when this should be applied. const bool shrink_to_fit = !replaced_element && ((computed.float_() != Style::Float::None) || (absolutely_positioned && inset_auto) || - (computed.display() == Style::Display::InlineBlock || computed.display() == Style::Display::InlineFlex)); + (computed.display() == Style::Display::InlineBlock || computed.display() == Style::Display::InlineFlex || computed.display() == Style::Display::InlineTable)); if (!shrink_to_fit) { diff --git a/Source/Core/Layout/TableFormattingContext.cpp b/Source/Core/Layout/TableFormattingContext.cpp index 8c9ba930f..d2b3fb303 100644 --- a/Source/Core/Layout/TableFormattingContext.cpp +++ b/Source/Core/Layout/TableFormattingContext.cpp @@ -113,6 +113,37 @@ UniquePtr TableFormattingContext::Format(ContainerBox* parent_contain return table_wrapper_box; } +Vector2f TableFormattingContext::GetMaxContentSize(Element* element) +{ + const Vector2f infinity(10000.0f, 10000.0f); + RootBox root(infinity); + auto table_wrapper_box = MakeUnique(element, &root); + + TableFormattingContext context; + context.table_wrapper_box = table_wrapper_box.get(); + context.element_table = element; + context.grid.Build(element, *table_wrapper_box); + + Box& box = table_wrapper_box->GetBox(); + LayoutDetails::BuildBox(box, infinity, element, BuildBoxMode::Block); + const Vector2f initial_content_size = box.GetSize(); + + context.table_auto_height = (initial_content_size.y < 0.0f); + context.table_content_offset = box.GetPosition(); + context.table_initial_content_size = Vector2f(initial_content_size.x, Math::Max(0.0f, initial_content_size.y)); + Math::SnapToPixelGrid(context.table_content_offset, context.table_initial_content_size); + context.table_max_size = Vector2f(FLT_MAX, FLT_MAX); + + const ComputedValues& computed_table = element->GetComputedValues(); + context.table_gap = Vector2f(ResolveValue(computed_table.column_gap(), context.table_initial_content_size.x)); + + + Vector2f table_content_size, table_overflow_size; + float table_baseline = 0.f; + context.FormatTable(table_content_size, table_overflow_size, table_baseline); + return table_content_size; +} + void TableFormattingContext::FormatTable(Vector2f& table_content_size, Vector2f& table_overflow_size, float& table_baseline) const { // Defines the boxes for all columns in this table, one entry per table column (spanning columns will add multiple entries). diff --git a/Source/Core/Layout/TableFormattingContext.h b/Source/Core/Layout/TableFormattingContext.h index 2b5788ffe..0ad42a317 100644 --- a/Source/Core/Layout/TableFormattingContext.h +++ b/Source/Core/Layout/TableFormattingContext.h @@ -48,6 +48,9 @@ class TableFormattingContext final : public FormattingContext { public: static UniquePtr Format(ContainerBox* parent_container, Element* element, const Box* override_initial_box); + /// Conputes max-content size for a table element. + static Vector2f GetMaxContentSize(Element* element); + private: TableFormattingContext() = default;