srctree

Robin Linden parent 9ab10aa7 ed5aa0d9
layout: Remove unnecessary LayoutBox::type member

A LayoutBox is an anonymous block if LayoutBox::node == nullptr, and abox being a block or an inline node is known in the StyledNode.

inlinesplit
layout/layout.cpp added: 140, removed: 255, total 0
@@ -66,13 +66,13 @@ private:
};
 
bool last_node_was_anonymous(LayoutBox const &box) {
return !box.children.empty() && box.children.back().type == LayoutType::AnonymousBlock;
return !box.children.empty() && box.children.back().is_anonymous_block();
}
 
// https://www.w3.org/TR/CSS2/visuren.html#box-gen
std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
if (auto const *text = std::get_if<dom::Text>(&node.node)) {
return LayoutBox{.node = &node, .type = LayoutType::Inline, .layout_text = std::string_view{text->text}};
return LayoutBox{.node = &node, .layout_text = std::string_view{text->text}};
}
 
assert(std::holds_alternative<dom::Element>(node.node));
@@ -81,15 +81,13 @@ std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
return std::nullopt;
}
 
auto type = display == style::DisplayValue::Inline ? LayoutType::Inline : LayoutType::Block;
 
if (auto const &element = std::get<dom::Element>(node.node); element.name == "img"sv) {
if (auto alt = element.attributes.find("alt"sv); alt != element.attributes.end()) {
return LayoutBox{.node = &node, .type = type, .layout_text = std::string_view{alt->second}};
return LayoutBox{.node = &node, .layout_text = std::string_view{alt->second}};
}
}
 
LayoutBox box{&node, type};
LayoutBox box{&node};
 
for (auto const &child : node.children) {
auto child_box = create_tree(child);
@@ -97,9 +95,10 @@ std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
continue;
}
 
if (child_box->type == LayoutType::Inline && box.type != LayoutType::Inline) {
if (child_box->get_property<css::PropertyId::Display>() == style::DisplayValue::Inline
&& display != style::DisplayValue::Inline) {
if (!last_node_was_anonymous(box)) {
box.children.push_back(LayoutBox{nullptr, LayoutType::AnonymousBlock});
box.children.push_back(LayoutBox{nullptr});
}
 
box.children.back().children.push_back(std::move(*child_box));
@@ -124,7 +123,7 @@ void remove_empty_text_boxes(LayoutBox &box) {
}
 
remove_empty_text_boxes(*it);
if (it->type == LayoutType::AnonymousBlock && it->children.empty()) {
if (it->is_anonymous_block() && it->children.empty()) {
it = box.children.erase(it);
continue;
}
@@ -141,7 +140,7 @@ void collapse_whitespace(LayoutBox &box) {
return !std::holds_alternative<std::monostate>(l.layout_text);
};
auto ends_text_run = [](LayoutBox const &l) {
return l.type != LayoutType::Inline;
return l.is_anonymous_block() || l.get_property<css::PropertyId::Display>() != style::DisplayValue::Inline;
};
auto needs_allocating_whitespace_collapsing = [](std::string_view text) {
return (std::ranges::adjacent_find(
@@ -271,17 +270,20 @@ void calculate_position(LayoutBox &box, geom::Rect const &parent) {
}
 
void Layouter::layout(LayoutBox &box, geom::Rect const &bounds) const {
switch (box.type) {
case LayoutType::Inline:
layout_inline(box, bounds);
return;
case LayoutType::Block:
layout_block(box, bounds);
return;
case LayoutType::AnonymousBlock:
layout_anonymous_block(box, bounds);
return;
if (box.is_anonymous_block()) {
layout_anonymous_block(box, bounds);
return;
}
 
// Nodes w/ `display: none` aren't added to the tree and shouldn't end up here.
auto display = box.get_property<css::PropertyId::Display>();
assert(display == style::DisplayValue::Inline || display == style::DisplayValue::Block);
if (display == style::DisplayValue::Inline) {
layout_inline(box, bounds);
return;
}
 
layout_block(box, bounds);
}
 
type::Weight to_type(std::optional<style::FontWeight> const &weight) {
 
layout/layout_box.cpp added: 140, removed: 255, total 0
@@ -16,7 +16,6 @@
 
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <optional>
#include <ostream>
@@ -32,17 +31,18 @@ using namespace std::literals;
namespace layout {
namespace {
 
std::string_view to_str(LayoutType type) {
switch (type) {
case LayoutType::Inline:
return "inline";
case LayoutType::Block:
return "block";
case LayoutType::AnonymousBlock:
return "ablock";
std::string_view layout_type(LayoutBox const &box) {
if (box.is_anonymous_block()) {
return "ablock";
}
assert(false);
std::abort();
 
auto const display = box.get_property<css::PropertyId::Display>();
assert(display == style::DisplayValue::Block || display == style::DisplayValue::Inline);
if (display == style::DisplayValue::Inline) {
return "inline";
}
 
return "block";
}
 
std::string to_str(geom::Rect const &rect) {
@@ -77,7 +77,7 @@ void print_box(LayoutBox const &box, std::ostream &os, std::uint8_t depth = 0) {
}
 
auto const &d = box.dimensions;
os << to_str(box.type) << " " << to_str(d.content) << " " << to_str(d.padding) << " " << to_str(d.margin) << '\n';
os << layout_type(box) << " " << to_str(d.content) << " " << to_str(d.padding) << " " << to_str(d.margin) << '\n';
for (auto const &child : box.children) {
print_box(child, os, depth + 1);
}
@@ -122,7 +122,7 @@ LayoutBox const *box_at_position(LayoutBox const &box, geom::Position p) {
}
}
 
if (box.type == LayoutType::AnonymousBlock) {
if (box.is_anonymous_block()) {
return nullptr;
}
 
 
layout/layout_box.h added: 140, removed: 255, total 0
@@ -14,7 +14,6 @@
#include "style/styled_node.h"
 
#include <cassert>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
@@ -24,27 +23,21 @@
 
namespace layout {
 
enum class LayoutType : std::uint8_t {
Inline,
Block,
AnonymousBlock, // Holds groups of sequential inline boxes.
};
 
struct LayoutBox {
style::StyledNode const *node;
LayoutType type;
BoxModel dimensions;
std::vector<LayoutBox> children;
std::variant<std::monostate, std::string_view, std::string> layout_text;
[[nodiscard]] bool operator==(LayoutBox const &) const = default;
 
bool is_anonymous_block() const { return node == nullptr; }
std::optional<std::string_view> text() const;
 
template<css::PropertyId T>
auto get_property() const {
// Calling get_property on an anonymous block (the only type that
// doesn't have a StyleNode) is a programming error.
assert(type != LayoutType::AnonymousBlock);
assert(!is_anonymous_block());
assert(node);
if constexpr (T == css::PropertyId::BorderBottomLeftRadius || T == css::PropertyId::BorderBottomRightRadius
|| T == css::PropertyId::BorderTopLeftRadius || T == css::PropertyId::BorderTopRightRadius) {
@@ -76,7 +69,7 @@ inline std::vector<LayoutBox const *> dom_children(LayoutBox const &node) {
assert(node.node);
std::vector<LayoutBox const *> children{};
for (auto const &child : node.children) {
if (child.type == LayoutType::AnonymousBlock) {
if (child.is_anonymous_block()) {
for (auto const &inline_child : child.children) {
assert(inline_child.node);
if (!std::holds_alternative<dom::Element>(inline_child.node->node)) {
 
layout/layout_box_test.cpp added: 140, removed: 255, total 0
@@ -21,7 +21,6 @@
 
using etest::expect;
using etest::expect_eq;
using layout::LayoutType;
using namespace std::literals;
 
namespace {
@@ -58,17 +57,15 @@ int main() {
set_up_parent_ptrs(style_root);
 
std::vector<layout::LayoutBox> layout_children{
{&style_root.children[0].children[0], LayoutType::Inline, {{0, 0, 25, 10}}, {}, "hello"sv},
{&style_root.children[0].children[1], LayoutType::Inline, {{25, 0, 35, 10}}, {}, "goodbye"sv},
{&style_root.children[0].children[0], {{0, 0, 25, 10}}, {}, "hello"sv},
{&style_root.children[0].children[1], {{25, 0, 35, 10}}, {}, "goodbye"sv},
};
auto expected_layout = layout::LayoutBox{.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 10}},
.children{{
&style_root.children[0],
LayoutType::Block,
{{0, 0, 100, 10}},
{{nullptr, LayoutType::AnonymousBlock, {{0, 0, 60, 10}}, {std::move(layout_children)}}},
{{nullptr, {{0, 0, 60, 10}}, {std::move(layout_children)}}},
}}};
 
auto layout_root = layout::create_layout(style_root, 100);
@@ -79,17 +76,18 @@ int main() {
});
 
etest::test("box_at_position", [] {
dom::Node dom = dom::Element{"dummy"};
style::StyledNode style{dom, {{css::PropertyId::Display, "block"}}};
std::vector<layout::LayoutBox> children{
{nullptr, LayoutType::AnonymousBlock, {{30, 30, 5, 5}}, {}},
{nullptr, LayoutType::Block, {{45, 45, 5, 5}}, {}},
{nullptr, {{30, 30, 5, 5}}, {}},
{&style, {{45, 45, 5, 5}}, {}},
};
 
auto layout = layout::LayoutBox{
.node = nullptr,
.type = LayoutType::Block,
.node = &style,
.dimensions = {{0, 0, 100, 100}},
.children{
{nullptr, LayoutType::Block, {{25, 25, 50, 50}}, {std::move(children)}},
{&style, {{25, 25, 50, 50}}, {std::move(children)}},
},
};
 
@@ -128,7 +126,6 @@ int main() {
 
// Verify that we have a shady anon-box to deal with in here.
expect_eq(layout.children.size(), std::size_t{2});
expect_eq(layout.children.at(1).type, LayoutType::AnonymousBlock);
 
auto const &anon_block = layout.children.at(1);
 
 
layout/layout_test.cpp added: 140, removed: 255, total 0
@@ -28,7 +28,6 @@ using etest::expect;
using etest::expect_eq;
using etest::require;
using etest::require_eq;
using layout::LayoutType;
 
namespace {
 
@@ -75,22 +74,18 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.layout_text{kCollapsedText},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kTextWidth, 10}},
.children{std::move(p_layout)},
}},
@@ -134,23 +129,19 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox a_layout{
.node = &style.children.at(0).children.at(1),
.type = LayoutType::Inline,
.dimensions{{kFirstWidth, 0, kSecondWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(1).children.at(0),
.type = LayoutType::Inline,
.dimensions{{kFirstWidth, 0, kSecondWidth, 10}},
.layout_text{kCollapsedSecond},
}},
};
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth + kSecondWidth, 10}},
.children{
layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.layout_text{kCollapsedFirst},
},
@@ -159,11 +150,9 @@ void whitespace_collapsing_tests() {
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kFirstWidth + kSecondWidth, 10}},
.children{std::move(p_layout)},
}},
@@ -207,23 +196,19 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox a_layout{
.node = &style.children.at(0).children.at(1),
.type = LayoutType::Inline,
.dimensions{{first_width, 0, second_width, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(1).children.at(0),
.type = LayoutType::Inline,
.dimensions{{first_width, 0, second_width, 10}},
.layout_text{collapsed_second},
}},
};
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, first_width + second_width, 10}},
.children{
layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, first_width, 10}},
.layout_text{collapsed_first},
},
@@ -232,11 +217,9 @@ void whitespace_collapsing_tests() {
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, first_width + second_width, 10}},
.children{std::move(p_layout)},
}},
@@ -283,45 +266,37 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox first_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.layout_text{kCollapsedFirst},
}},
};
layout::LayoutBox second_layout{
.node = &style.children.at(2),
.type = LayoutType::Inline,
.dimensions{{0, 10, kSecondWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(2).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 10, kSecondWidth, 10}},
.layout_text{kCollapsedSecond},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 20}},
.children{
layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kFirstWidth, 10}},
.children{std::move(first_layout)},
},
layout::LayoutBox{
.node = &style.children.at(1),
.type = LayoutType::Block,
.dimensions{{0, 10, 1234, 0}},
},
layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 10, kSecondWidth, 10}},
.children{std::move(second_layout)},
},
@@ -367,40 +342,33 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox first_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.layout_text{kFirstText},
}},
};
layout::LayoutBox space_layout{
.node = &style.children.at(1),
.type = LayoutType::Inline,
.dimensions{{kFirstWidth, 0, kSpaceWidth, 10}},
.layout_text{std::string{" "}},
};
layout::LayoutBox second_layout{
.node = &style.children.at(2),
.type = LayoutType::Inline,
.dimensions{{kFirstWidth + kSpaceWidth, 0, kSecondWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(2).children.at(0),
.type = LayoutType::Inline,
.dimensions{{kFirstWidth + kSpaceWidth, 0, kSecondWidth, 10}},
.layout_text{kSecondText},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{
layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kFirstWidth + kSpaceWidth + kSecondWidth, 10}},
.children{
std::move(first_layout),
@@ -449,16 +417,13 @@ void whitespace_collapsing_tests() {
 
layout::LayoutBox first_layout{
.node = &style.children.at(0),
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{
layout::LayoutBox{
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kFirstWidth, 10}},
.children{
layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kFirstWidth, 10}},
.layout_text{kFirstText},
},
@@ -468,16 +433,13 @@ void whitespace_collapsing_tests() {
};
layout::LayoutBox second_layout{
.node = &style.children.at(2),
.type = LayoutType::Block,
.dimensions{{0, 10, 1234, 10}},
.children{
layout::LayoutBox{
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 10, kSecondWidth, 10}},
.children{
layout::LayoutBox{
.node = &style.children.at(2).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 10, kSecondWidth, 10}},
.layout_text{kSecondText},
},
@@ -487,7 +449,6 @@ void whitespace_collapsing_tests() {
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 20}},
.children{
std::move(first_layout),
@@ -524,22 +485,18 @@ void text_transform_tests() {
 
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.layout_text{std::string{kExpectedText}},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kTextWidth, 10}},
.children{std::move(p_layout)},
}},
@@ -572,22 +529,18 @@ void text_transform_tests() {
 
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.layout_text{std::string{kExpectedText}},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kTextWidth, 10}},
.children{std::move(p_layout)},
}},
@@ -620,22 +573,18 @@ void text_transform_tests() {
 
layout::LayoutBox p_layout{
.node = &style.children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.children{layout::LayoutBox{
.node = &style.children.at(0).children.at(0),
.type = LayoutType::Inline,
.dimensions{{0, 0, kTextWidth, 10}},
.layout_text{std::string{kExpectedText}},
}},
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 1234, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, kTextWidth, 10}},
.children{std::move(p_layout)},
}},
@@ -664,11 +613,9 @@ void img_tests() {
 
auto expected_layout = layout::LayoutBox{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 100, 0}},
.children{{
&style.children[0],
LayoutType::Block,
{{0, 0, 100, 0}},
}},
};
@@ -694,11 +641,9 @@ void img_tests() {
 
auto expected_layout = layout::LayoutBox{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 100, 10}},
.children{{
&style.children[0],
LayoutType::Block,
{{0, 0, 100, 10}},
{},
"hello"sv,
@@ -741,12 +686,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {},
.children = {
{&style_root.children[0], LayoutType::Block, {}, {}},
{&style_root.children[1], LayoutType::Block, {}, {
{&style_root.children[1].children[0], LayoutType::Block, {}, {}},
{&style_root.children[0], {}, {}},
{&style_root.children[1], {}, {
{&style_root.children[1].children[0], {}, {}},
}},
}
};
@@ -778,11 +722,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {},
.children = {
{&style_root.children[1], LayoutType::Block, {}, {
{&style_root.children[1].children[0], LayoutType::Block, {}, {}},
{&style_root.children[1], {}, {
{&style_root.children[1].children[0], {}, {}},
}},
}
};
@@ -813,13 +756,12 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {},
.children = {
{nullptr, LayoutType::AnonymousBlock, {}, {
{&style_root.children[0], LayoutType::Inline, {}, {}},
{&style_root.children[1], LayoutType::Inline, {}, {
{&style_root.children[1].children[0], LayoutType::Inline, {}, {}},
{nullptr, {}, {
{&style_root.children[0], {}, {}},
{&style_root.children[1], {}, {
{&style_root.children[1].children[0], {}, {}},
}},
}},
}
@@ -842,9 +784,8 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Inline,
.dimensions = {},
.children = {{&style_root.children[0], LayoutType::Inline, {}, {}}},
.children = {{&style_root.children[0], {}, {}}},
};
 
auto layout_root = layout::create_layout(style_root, 0);
@@ -875,13 +816,12 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 10}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 10}}, {
{nullptr, LayoutType::AnonymousBlock, {{0, 0, 60, 10}}, {
{&style_root.children[0].children[0], LayoutType::Inline, {{0, 0, 25, 10}}, {}, "hello"sv},
{&style_root.children[0].children[1], LayoutType::Inline, {{25, 0, 35, 10}}, {}, "goodbye"sv},
{&style_root.children[0], {{0, 0, 100, 10}}, {
{nullptr, {{0, 0, 60, 10}}, {
{&style_root.children[0].children[0], {{0, 0, 25, 10}}, {}, "hello"sv},
{&style_root.children[0].children[1], {{25, 0, 35, 10}}, {}, "goodbye"sv},
}},
}},
}
@@ -914,11 +854,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 100, 0}}, {}},
}},
}
};
@@ -946,11 +885,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 100, 0}}, {}},
}},
}
};
@@ -978,11 +916,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 200, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 100, 0}}, {}},
}},
}
};
@@ -1010,11 +947,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 50, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 25, 0}}, {}},
{&style_root.children[0], {{0, 0, 50, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 25, 0}}, {}},
}},
}
};
@@ -1042,11 +978,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 100, 0}}, {}},
}},
}
};
@@ -1074,11 +1009,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 0, 100}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 0, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 0, 0}}, {
{&style_root.children[0].children[0], {{0, 0, 0, 0}}, {}},
}},
}
};
@@ -1108,12 +1042,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 0, 25}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 0, 25}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 0, 25}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 25, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 0, 25}}, {
{&style_root.children[0].children[0], {{0, 0, 0, 25}}, {}},
{&style_root.children[0].children[1], {{0, 25, 0, 0}}, {}},
}},
}
};
@@ -1143,12 +1076,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 0, 400}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 0, 25}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 0, 25}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 25, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 0, 25}}, {
{&style_root.children[0].children[0], {{0, 0, 0, 25}}, {}},
{&style_root.children[0].children[1], {{0, 25, 0, 0}}, {}},
}},
}
};
@@ -1178,12 +1110,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 0, 10}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 0, 400}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 0, 400}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 400, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 0, 400}}, {
{&style_root.children[0].children[0], {{0, 0, 0, 400}}, {}},
{&style_root.children[0].children[1], {{0, 400, 0, 0}}, {}},
}},
}
};
@@ -1222,12 +1153,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 120}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 120}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{10, 10, 80, 100}, {10, 10, 10, 10}, {}, {0, 0, 0, 0}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 120, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 120}}, {
{&style_root.children[0].children[0], {{10, 10, 80, 100}, {10, 10, 10, 10}, {}, {0, 0, 0, 0}}, {}},
{&style_root.children[0].children[1], {{0, 120, 100, 0}}, {}},
}},
}
};
@@ -1270,12 +1200,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 130}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 130}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{10, 14, 78, 100}, {}, {10, 12, 14, 16}, {}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 130, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 130}}, {
{&style_root.children[0].children[0], {{10, 14, 78, 100}, {}, {10, 12, 14, 16}, {}}, {}},
{&style_root.children[0].children[1], {{0, 130, 100, 0}}, {}},
}},
}
};
@@ -1312,11 +1241,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 100}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 100}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{0, 0, 100, 100}, {}, {}, {}}, {}},
{&style_root.children[0], {{0, 0, 100, 100}}, {
{&style_root.children[0].children[0], {{0, 0, 100, 100}, {}, {}, {}}, {}},
}},
}
};
@@ -1354,12 +1282,11 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 20}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 100, 20}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{10, 10, 80, 0}, {}, {}, {10, 10, 10, 10}}, {}},
{&style_root.children[0].children[1], LayoutType::Block, {{0, 20, 100, 0}}, {}},
{&style_root.children[0], {{0, 0, 100, 20}}, {
{&style_root.children[0].children[0], {{10, 10, 80, 0}, {}, {}, {10, 10, 10, 10}}, {}},
{&style_root.children[0].children[1], {{0, 20, 100, 0}}, {}},
}},
}
};
@@ -1394,11 +1321,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 200, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{50, 0, 100, 0}, {}, {}, {50, 50, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], {{50, 0, 100, 0}, {}, {}, {50, 50, 0, 0}}, {}},
}},
}
};
@@ -1433,11 +1359,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 200, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{80, 0, 100, 0}, {}, {}, {80, 20, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], {{80, 0, 100, 0}, {}, {}, {80, 20, 0, 0}}, {}},
}},
}
};
@@ -1472,11 +1397,10 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 200, 0}},
.children = {
{&style_root.children[0], LayoutType::Block, {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], LayoutType::Block, {{75, 0, 100, 0}, {}, {}, {75, 25, 0, 0}}, {}},
{&style_root.children[0], {{0, 0, 200, 0}}, {
{&style_root.children[0].children[0], {{75, 0, 100, 0}, {}, {}, {75, 25, 0, 0}}, {}},
}},
}
};
@@ -1500,7 +1424,6 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 100, 100}},
.children = {}
};
@@ -1522,7 +1445,6 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 200, 200}},
.children = {}
};
@@ -1546,7 +1468,6 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 10, 10}},
.children = {}
};
@@ -1568,7 +1489,6 @@ int main() {
 
auto expected_layout = layout::LayoutBox{
.node = &style_root,
.type = LayoutType::Block,
.dimensions = {{0, 0, 10, 10}},
.children = {}
};
@@ -1585,7 +1505,7 @@ int main() {
{css::PropertyId::Width, "100px"},
{css::PropertyId::MaxWidth, "none"}},
};
layout::LayoutBox expected_layout{.node = &style, .type = LayoutType::Block, .dimensions{{0, 0, 100, 0}}};
layout::LayoutBox expected_layout{.node = &style, .dimensions{{0, 0, 100, 0}}};
 
auto layout = layout::create_layout(style, 0);
expect_eq(layout, expected_layout);
@@ -1599,7 +1519,7 @@ int main() {
{css::PropertyId::Height, "100px"},
{css::PropertyId::MaxHeight, "none"}},
};
layout::LayoutBox expected_layout{.node = &style, .type = LayoutType::Block, .dimensions{{0, 0, 0, 100}}};
layout::LayoutBox expected_layout{.node = &style, .dimensions{{0, 0, 0, 100}}};
 
auto layout = layout::create_layout(style, 0);
expect_eq(layout, expected_layout);
@@ -1619,11 +1539,9 @@ int main() {
};
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 0, 10}},
.children{layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Block,
.dimensions{{0, 0, 0, 10}},
}},
};
@@ -1671,7 +1589,6 @@ int main() {
 
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 0, 0}},
};
 
@@ -1688,7 +1605,6 @@ int main() {
 
layout::LayoutBox expected_layout{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 0, 0}},
};
 
@@ -1724,11 +1640,9 @@ int main() {
 
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.children{layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.layout_text = "hello"sv,
}},
@@ -1749,15 +1663,12 @@ int main() {
 
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 30, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, 25, 10}},
.children{layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.layout_text = "hello"sv,
}},
@@ -1811,23 +1722,19 @@ int main() {
// views into the dom text.
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Block,
// 2 lines, where the widest one is 5 characters.
.dimensions{{0, 0, 30, 20}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, 25, 20}},
.children{
layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 10, 10}},
.layout_text = "hi"s,
},
layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 10, 25, 10}},
.layout_text = "hello"s,
},
@@ -1850,22 +1757,18 @@ int main() {
 
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 30, 20}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, 25, 20}},
.children{
layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.layout_text = "oh no"s,
},
layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 10, 20, 10}},
.layout_text = "!! !"s,
},
@@ -1888,15 +1791,12 @@ int main() {
 
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 15, 10}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, 25, 10}},
.children{layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.layout_text = "hello"sv,
}},
@@ -1931,27 +1831,22 @@ int main() {
 
layout::LayoutBox expected{
.node = &style,
.type = LayoutType::Block,
.dimensions{{0, 0, 25, 20}},
.children{layout::LayoutBox{
.node = nullptr,
.type = LayoutType::AnonymousBlock,
.dimensions{{0, 0, 25, 20}},
.children{
layout::LayoutBox{
.node = &style.children[0],
.type = LayoutType::Inline,
.dimensions{{0, 0, 25, 10}},
.layout_text = "hello"sv,
},
layout::LayoutBox{
.node = &style.children[1],
.type = LayoutType::Inline,
.dimensions{{25, 0, 0, 0}},
},
layout::LayoutBox{
.node = &style.children[2],
.type = LayoutType::Inline,
.dimensions{{0, 10, 25, 10}},
.layout_text = "world"sv,
},
 
render/render.cpp added: 140, removed: 255, total 0
@@ -120,7 +120,12 @@ void do_render(gfx::ICanvas &painter, layout::LayoutBox const &layout) {
}
 
bool should_render(layout::LayoutBox const &layout) {
return layout.type == layout::LayoutType::Block || layout.type == layout::LayoutType::Inline;
if (layout.is_anonymous_block()) {
return false;
}
 
auto const display = layout.get_property<css::PropertyId::Display>();
return display == style::DisplayValue::Block || display == style::DisplayValue::Inline;
}
 
void render_layout_impl(gfx::ICanvas &painter, layout::LayoutBox const &layout, std::optional<geom::Rect> const &clip) {
 
render/render_test.cpp added: 140, removed: 255, total 0
@@ -43,8 +43,7 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Inline,
.children = {{&styled.children[0], layout::LayoutType::Inline, {}, {}, "hello"sv}},
.children = {{&styled.children[0], {}, {}, "hello"sv}},
};
 
gfx::CanvasCommandSaver saver;
@@ -64,7 +63,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{10, 20, 100, 100}, {}, {}, {}},
};
 
@@ -87,11 +85,10 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{10, 20, 100, 100}, {}, {}, {}},
.children{
{nullptr, layout::LayoutType::Block, {{10, 20, 10, 10}}, {}, "hello"sv},
{nullptr, layout::LayoutType::Block, {{10, 30, 10, 10}}, {}, "world"sv},
{nullptr, {{10, 20, 10, 10}}, {}, "hello"sv},
{nullptr, {{10, 30, 10, 10}}, {}, "world"sv},
},
};
 
@@ -115,7 +112,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{10, 20, 100, 100}, {}, {}, {}},
};
 
@@ -134,7 +130,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 40}, {}, {10, 10, 10, 10}, {}},
};
 
@@ -163,7 +158,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 40}, {}, {2, 4, 6, 8}, {}},
};
 
@@ -192,9 +186,8 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Inline,
.dimensions = {},
.children = {{&styled.children[0], layout::LayoutType::Inline, {{0, 0, 20, 20}}, {}}},
.children = {{&styled.children[0], {{0, 0, 20, 20}}, {}}},
};
 
gfx::CanvasCommandSaver saver;
@@ -212,7 +205,6 @@ int main() {
auto styled = style::StyledNode{.node = dom};
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 20}},
};
 
@@ -248,7 +240,6 @@ int main() {
auto styled = style::StyledNode{.node = dom};
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 20}},
};
 
@@ -400,7 +391,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 40}},
};
 
@@ -463,7 +453,6 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {.content{0, 0, 20, 40}, .border{1, 1, 1, 1}},
};
 
@@ -529,9 +518,8 @@ int main() {
 
auto layout = layout::LayoutBox{
.node = &styled,
.type = layout::LayoutType::Block,
.dimensions = {{0, 0, 20, 40}},
.children = {{&styled.children[0], layout::LayoutType::Block, {{0, 0, 10, 10}}}},
.children = {{&styled.children[0], {{0, 0, 10, 10}}}},
};
 
gfx::CanvasCommandSaver saver;
 
tui/BUILD added: 140, removed: 255, total 0
@@ -8,7 +8,9 @@ cc_library(
copts = HASTUR_COPTS,
visibility = ["//visibility:public"],
deps = [
"//css",
"//layout",
"//style",
"@ftxui",
"@spdlog",
],
 
tui/tui.cpp added: 140, removed: 255, total 0
@@ -1,16 +1,18 @@
// SPDX-FileCopyrightText: 2021-2023 Robin Lindén <dev@robinlinden.eu>
// SPDX-FileCopyrightText: 2021-2024 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "tui/tui.h"
 
#include "css/property_id.h"
#include "layout/layout_box.h"
#include "style/styled_node.h"
 
#include <ftxui/dom/elements.hpp>
#include <ftxui/dom/node.hpp>
#include <ftxui/screen/screen.hpp>
 
#include <cstdlib>
#include <cassert>
#include <string>
 
namespace tui {
@@ -28,19 +30,20 @@ ftxui::Elements parse_children(layout::LayoutBox const &box) {
}
 
ftxui::Element element_from_node(layout::LayoutBox const &box) {
switch (box.type) {
case layout::LayoutType::Inline: {
if (auto text = box.text()) {
return ftxui::paragraph(std::string{*text});
}
return hbox(parse_children(box));
}
case layout::LayoutType::AnonymousBlock:
case layout::LayoutType::Block: {
return flex(vbox(parse_children(box)));
}
if (box.is_anonymous_block()) {
return flex(vbox(parse_children(box)));
}
std::abort(); // unreachable
 
auto const display = box.get_property<css::PropertyId::Display>();
assert(display == style::DisplayValue::Block || display == style::DisplayValue::Inline);
if (display == style::DisplayValue::Inline) {
if (auto text = box.text()) {
return ftxui::paragraph(std::string{*text});
}
return hbox(parse_children(box));
}
 
return flex(vbox(parse_children(box)));
}
 
} // namespace