1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 03:37:34 +00:00

LibWeb: Basic support for display:inline-block with width:auto

We now implement the somewhat fuzzy shrink-to-fit algorithm when laying
out inline-block elements with both block and inline children.

Shrink-to-fit works by doing two speculative layouts of the entire
subtree inside the current block, to compute two things:

1. Preferred minimum width: If we made a line break at every chance we
   had, how wide would the widest line be?
2. Preferred width: We break only when explicitly told to (e.g "<br>")
   How wide would the widest line be?

We then shrink the width of the inline-block element to an appropriate
value based on the above, taking the available width in the containing
block into consideration (sans all the box model fluff.)

To make the speculative layouts possible, plumb a LayoutMode enum
throughout the layout system since it needs to be respected in various
places.

Note that this is quite hackish and I'm sure there are smarter ways to
do a lot of this. But it does kinda work! :^)
This commit is contained in:
Andreas Kling 2020-05-26 21:53:10 +02:00
parent 4e8bcda4d1
commit f01af62313
24 changed files with 184 additions and 97 deletions

View file

@ -95,7 +95,7 @@ void LayoutText::render_fragment(RenderingContext& context, const LineBoxFragmen
}
template<typename Callback>
void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_wrap_breaks) const
void LayoutText::for_each_chunk(Callback callback, LayoutMode line_break_policy, bool do_wrap_lines, bool do_wrap_breaks) const
{
Utf8View view(m_text_for_rendering);
if (view.is_empty())
@ -103,7 +103,10 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w
auto start_of_chunk = view.begin();
auto commit_chunk = [&](auto it, bool has_breaking_newline) {
auto commit_chunk = [&](auto it, bool has_breaking_newline, bool must_commit = false) {
if (line_break_policy == LayoutMode::OnlyRequiredLineBreaks && !must_commit)
return;
int start = view.byte_offset_of(start_of_chunk);
int length = view.byte_offset_of(it) - view.byte_offset_of(start_of_chunk);
@ -117,6 +120,9 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w
bool last_was_space = isspace(*view.begin());
bool last_was_newline = false;
for (auto it = view.begin(); it != view.end();) {
if (line_break_policy == LayoutMode::AllPossibleLineBreaks) {
commit_chunk(it, false);
}
if (last_was_newline) {
last_was_newline = false;
commit_chunk(it, true);
@ -137,10 +143,10 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w
if (last_was_newline)
commit_chunk(view.end(), true);
if (start_of_chunk != view.end())
commit_chunk(view.end(), false);
commit_chunk(view.end(), false, true);
}
void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks)
void LayoutText::split_into_lines_by_rules(LayoutBlock& container, LayoutMode line_break_policy, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks)
{
auto& font = style().font();
float space_width = font.glyph_width(' ') + font.glyph_spacing();
@ -182,10 +188,11 @@ void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_colla
};
Vector<Chunk> chunks;
for_each_chunk([&](const Utf8View& view, int start, int length, bool is_break) {
chunks.append({ Utf8View(view), start, length, is_break });
},
do_wrap_lines, do_wrap_breaks);
for_each_chunk(
[&](const Utf8View& view, int start, int length, bool is_break) {
chunks.append({ Utf8View(view), start, length, is_break });
},
line_break_policy, do_wrap_lines, do_wrap_breaks);
for (size_t i = 0; i < chunks.size(); ++i) {
auto& chunk = chunks[i];
@ -229,7 +236,7 @@ void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_colla
}
}
void LayoutText::split_into_lines(LayoutBlock& container)
void LayoutText::split_into_lines(LayoutBlock& container, LayoutMode line_break_policy)
{
bool do_collapse = true;
bool do_wrap_lines = true;
@ -254,7 +261,7 @@ void LayoutText::split_into_lines(LayoutBlock& container)
do_wrap_breaks = true;
}
split_into_lines_by_rules(container, do_collapse, do_wrap_lines, do_wrap_breaks);
split_into_lines_by_rules(container, line_break_policy, do_collapse, do_wrap_lines, do_wrap_breaks);
}
}