srctree

Robin Linden parent 61977f7a 1342e73d
layout: Add whitespace collapsing at the start and end of text runs

inlinesplit
layout/layout.cpp added: 45, removed: 4, total 41
@@ -17,6 +17,7 @@
#include <charconv>
#include <cstdint>
#include <cstdlib>
#include <list>
#include <map>
#include <optional>
#include <sstream>
@@ -72,6 +73,44 @@ std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
return std::visit(visitor, node.node);
}
 
// TODO(robinlinden): Collapse whitespace inside text runs.
// NOLINTBEGIN(bugprone-unchecked-optional-access): False positives.
void collapse_whitespace(LayoutBox &box) {
LayoutBox *last_text_box = nullptr;
std::list<LayoutBox *> to_collapse{&box};
 
auto starts_text_run = [&](LayoutBox const &l) {
return last_text_box == nullptr && l.layout_text.has_value();
};
auto ends_text_run = [&](LayoutBox const &l) {
return last_text_box != nullptr && l.type != LayoutType::Inline;
};
 
for (auto it = to_collapse.begin(); it != to_collapse.end(); ++it) {
auto *current = *it;
if (starts_text_run(*current)) {
last_text_box = current;
last_text_box->layout_text = util::trim_start(*last_text_box->layout_text);
} else if (current->layout_text.has_value()) {
last_text_box = current;
} else if (ends_text_run(*current)) {
last_text_box->layout_text = util::trim_end(*last_text_box->layout_text);
last_text_box = nullptr;
}
 
for (std::size_t child_idx = 0; child_idx < current->children.size(); ++child_idx) {
auto insertion_point = it;
std::advance(insertion_point, 1 + child_idx);
to_collapse.insert(insertion_point, &current->children[child_idx]);
}
}
 
if (last_text_box != nullptr) {
last_text_box->layout_text = util::trim_end(*last_text_box->layout_text);
}
}
// NOLINTEND(bugprone-unchecked-optional-access)
 
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
int to_px(std::string_view property, int const font_size, int const root_font_size) {
// Special case for 0 since it won't ever have a unit that needs to be handled.
@@ -427,6 +466,7 @@ std::optional<LayoutBox> create_layout(style::StyledNode const &node, int width)
return {};
}
 
collapse_whitespace(*tree);
layout(*tree, {0, 0, width, 0}, node.get_property<css::PropertyId::FontSize>());
return *tree;
}
 
layout/layout_test.cpp added: 45, removed: 4, total 41
@@ -1197,7 +1197,8 @@ int main() {
 
etest::test("whitespace collapsing", [] {
constexpr auto kText = " hello "sv;
constexpr auto kTextWidth = kText.length() * 5;
constexpr auto kCollapsedText = util::trim(kText);
constexpr auto kTextWidth = kCollapsedText.length() * 5;
 
dom::Element p{.name{"p"}, .children{dom::Text{std::string{kText}}}};
dom::Node html = dom::Element{.name{"html"}, .children{std::move(p)}};
@@ -1223,7 +1224,7 @@ int main() {
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.layout_text{kText},
.layout_text{kCollapsedText},
}},
};
layout::LayoutBox expected_layout{