srctree

Robin Linden parent ffe78ba3 f47eb8aa
style: Restructure the display property to support more values

engine/engine_test.cpp added: 54, removed: 39, total 15
@@ -115,7 +115,7 @@ int main() {
auto page = e.navigate(uri::Uri::parse("hax://example.com").value()).value();
// Our default CSS gives <html> the property display: block.
require(page->layout.has_value());
expect_eq(page->layout->get_property<css::PropertyId::Display>(), style::DisplayValue::Block);
expect_eq(page->layout->get_property<css::PropertyId::Display>(), style::Display::block_flow());
 
responses = Responses{{
"hax://example.com"s,
@@ -131,7 +131,7 @@ int main() {
// The CSS declared in the page should have a higher priority and give
// <html> the property display: inline.
require(page->layout.has_value());
expect_eq(page->layout->get_property<css::PropertyId::Display>(), style::DisplayValue::Inline);
expect_eq(page->layout->get_property<css::PropertyId::Display>(), style::Display::inline_flow());
});
 
etest::test("multiple inline <head><style> elements are allowed", [] {
 
layout/layout.cpp added: 54, removed: 39, total 15
@@ -78,7 +78,7 @@ std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
 
assert(std::holds_alternative<dom::Element>(node.node));
auto display = node.get_property<css::PropertyId::Display>();
if (display == style::DisplayValue::None) {
if (!display.has_value()) {
return std::nullopt;
}
 
@@ -96,8 +96,9 @@ std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
continue;
}
 
if (child_box->get_property<css::PropertyId::Display>() == style::DisplayValue::Inline
&& display != style::DisplayValue::Inline) {
auto child_display = child.get_property<css::PropertyId::Display>();
assert(child_display.has_value());
if (child_display == style::Display::inline_flow() && display != style::Display::inline_flow()) {
if (!last_node_was_anonymous(box)) {
box.children.push_back(LayoutBox{nullptr});
}
@@ -141,7 +142,7 @@ void collapse_whitespace(LayoutBox &box) {
return !std::holds_alternative<std::monostate>(l.layout_text);
};
auto ends_text_run = [](LayoutBox const &l) {
return l.is_anonymous_block() || l.get_property<css::PropertyId::Display>() != style::DisplayValue::Inline;
return l.is_anonymous_block() || l.get_property<css::PropertyId::Display>() != style::Display::inline_flow();
};
auto needs_allocating_whitespace_collapsing = [](std::string_view text) {
return (std::ranges::adjacent_find(
@@ -278,8 +279,8 @@ void Layouter::layout(LayoutBox &box, geom::Rect const &bounds) const {
 
// 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) {
assert(display.has_value());
if (display == style::Display::inline_flow()) {
layout_inline(box, bounds);
return;
}
 
layout/layout_box.cpp added: 54, removed: 39, total 15
@@ -31,8 +31,9 @@ std::string_view layout_type(LayoutBox const &box) {
}
 
auto const display = box.get_property<css::PropertyId::Display>();
assert(display == style::DisplayValue::Block || display == style::DisplayValue::Inline);
if (display == style::DisplayValue::Inline) {
assert(display.has_value());
assert(display->outer == style::Display::Outer::Block || display->outer == style::Display::Outer::Inline);
if (display->outer == style::Display::Outer::Inline) {
return "inline";
}
 
 
render/render.cpp added: 54, removed: 39, total 15
@@ -124,8 +124,7 @@ bool should_render(layout::LayoutBox const &layout) {
return false;
}
 
auto const display = layout.get_property<css::PropertyId::Display>();
return display == style::DisplayValue::Block || display == style::DisplayValue::Inline;
return layout.get_property<css::PropertyId::Display>().has_value();
}
 
void render_layout_impl(gfx::ICanvas &painter, layout::LayoutBox const &layout, std::optional<geom::Rect> const &clip) {
 
style/styled_node.cpp added: 54, removed: 39, total 15
@@ -344,33 +344,33 @@ gfx::Color StyledNode::get_color_property(css::PropertyId property) const {
 
// https://developer.mozilla.org/en-US/docs/Web/CSS/float
// ^ has info about the weird float<->display property interaction.
DisplayValue StyledNode::get_display_property() const {
std::optional<Display> StyledNode::get_display_property() const {
// TODO(robinlinden): Special-case for text not needed once the special case
// where we get the parent properties for text in get_raw_property is
// removed.
if (std::holds_alternative<dom::Text>(node)) {
return DisplayValue::Inline;
return Display::inline_flow();
}
 
auto raw = get_raw_property(css::PropertyId::Display);
if (raw == "none") {
return DisplayValue::None;
return std::nullopt;
}
 
if (raw == "inline") {
if (get_property<css::PropertyId::Float>().value_or(Float::None) == Float::None) {
return DisplayValue::Inline;
return Display::inline_flow();
}
 
return DisplayValue::Block;
return Display::block_flow();
}
 
if (raw == "block") {
return DisplayValue::Block;
return Display::block_flow();
}
 
spdlog::warn("Unhandled display value '{}'", raw);
return DisplayValue::Block;
return Display::block_flow();
}
 
std::optional<Float> StyledNode::get_float_property() const {
 
style/styled_node.h added: 54, removed: 39, total 15
@@ -38,10 +38,22 @@ enum class BorderStyle : std::uint8_t {
 
using OutlineStyle = BorderStyle;
 
enum class DisplayValue : std::uint8_t {
None,
Inline,
Block,
struct Display {
enum class Outer : std::uint8_t {
Inline,
Block,
};
enum class Inner : std::uint8_t {
Flow,
};
 
Outer outer{};
Inner inner{};
 
[[nodiscard]] constexpr bool operator==(Display const &) const = default;
 
constexpr static Display inline_flow() { return {Outer::Inline, Inner::Flow}; }
constexpr static Display block_flow() { return {Outer::Block, Inner::Flow}; }
};
 
enum class Float : std::uint8_t {
@@ -164,7 +176,7 @@ private:
 
BorderStyle get_border_style_property(css::PropertyId) const;
gfx::Color get_color_property(css::PropertyId) const;
DisplayValue get_display_property() const;
std::optional<Display> get_display_property() const;
std::optional<Float> get_float_property() const;
FontStyle get_font_style_property() const;
int get_font_size_property() const;
 
style/styled_node_test.cpp added: 54, removed: 39, total 15
@@ -307,12 +307,13 @@ int main() {
.children = {},
};
 
expect_eq(styled_node.get_property<css::PropertyId::Display>(), style::DisplayValue::None);
expect_eq(styled_node.get_property<css::PropertyId::Display>(), std::nullopt);
});
 
etest::test("get_property, display", [] {
expect_property_eq<css::PropertyId::Display>("inline", style::DisplayValue::Inline);
expect_property_eq<css::PropertyId::Display>("i cant believe this", style::DisplayValue::Block);
using style::Display;
expect_property_eq<css::PropertyId::Display>("inline", Display::inline_flow());
expect_property_eq<css::PropertyId::Display>("i cant believe this", Display::block_flow());
 
// Weird float interactions.
dom::Node dom_node = dom::Element{"dummy"s};
@@ -325,7 +326,7 @@ int main() {
};
 
styled.properties[0] = {css::PropertyId::Display, "inline"s};
expect_eq(styled.get_property<css::PropertyId::Display>(), style::DisplayValue::Block);
expect_eq(styled.get_property<css::PropertyId::Display>(), Display::block_flow());
});
 
etest::test("get_property, border-style", [] {
@@ -439,7 +440,7 @@ int main() {
std::vector{style::TextDecorationLine::Blink});
 
// Text is always "display: inline".
expect_eq(child.get_property<css::PropertyId::Display>(), style::DisplayValue::Inline);
expect_eq(child.get_property<css::PropertyId::Display>(), style::Display::inline_flow());
});
 
etest::test("get_property, font-weight", [] {
 
tui/tui.cpp added: 54, removed: 39, total 15
@@ -35,8 +35,9 @@ ftxui::Element element_from_node(layout::LayoutBox const &box) {
}
 
auto const display = box.get_property<css::PropertyId::Display>();
assert(display == style::DisplayValue::Block || display == style::DisplayValue::Inline);
if (display == style::DisplayValue::Inline) {
assert(display.has_value());
assert(display == style::Display::inline_flow() || display == style::Display::block_flow());
if (display == style::Display::inline_flow()) {
if (auto text = box.text()) {
return ftxui::paragraph(std::string{*text});
}