From 9c8d62e13b65d03e657749dd6d2f6272286937e9 Mon Sep 17 00:00:00 2001 From: SGavrl <277843151+SGavrl@users.noreply.github.com> Date: Thu, 2 Jul 2026 20:02:07 +0000 Subject: [PATCH] fix(render): lay out text nodes in taffy and implement inline flow --- crates/obscura-render/src/dom.rs | 19 +++++++++++++++++++ crates/obscura-render/src/lib.rs | 6 ++++++ crates/obscura-render/src/paint.rs | 14 ++++++++++---- crates/obscura-render/src/style.rs | 8 ++++++-- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/crates/obscura-render/src/dom.rs b/crates/obscura-render/src/dom.rs index eaf28fb..5d48c0e 100644 --- a/crates/obscura-render/src/dom.rs +++ b/crates/obscura-render/src/dom.rs @@ -140,6 +140,25 @@ fn build( styles: &HashMap, ) -> Option { let node = tree.get_node(id)?; + + if let obscura_dom::tree::NodeData::Text { contents } = &node.data { + let text = contents.trim(); + if text.is_empty() { + return None; + } + let width = text.chars().count() as f32 * 9.0; + let style = taffy::Style { + size: taffy::Size { + width: taffy::Dimension::Length(width), + height: taffy::Dimension::Length(19.0), + }, + ..Default::default() + }; + let taffy_id = taffy_tree.new_leaf(style).ok()?; + id_map.insert(taffy_id, id); + return Some(taffy_id); + } + let _name = node.as_element()?; let style = styles.get(&id)?; let taffy_style = to_taffy_style(style); diff --git a/crates/obscura-render/src/lib.rs b/crates/obscura-render/src/lib.rs index b5862d4..29ad94e 100644 --- a/crates/obscura-render/src/lib.rs +++ b/crates/obscura-render/src/lib.rs @@ -49,6 +49,7 @@ pub enum Display { #[default] Block, Flex, + Inline, #[allow(dead_code)] None, } @@ -144,8 +145,13 @@ pub(crate) fn to_taffy_style(style: &LayoutStyle) -> Style { s.display = match style.display { Display::Block => taffy::style::Display::Block, Display::Flex => taffy::style::Display::Flex, + Display::Inline => taffy::style::Display::Flex, Display::None => taffy::style::Display::None, }; + if style.display == Display::Inline { + s.flex_direction = taffy::FlexDirection::Row; + } + s.flex_wrap = taffy::FlexWrap::Wrap; s.size = taffy::Size { width: dimension(style.width), height: dimension(style.height), diff --git a/crates/obscura-render/src/paint.rs b/crates/obscura-render/src/paint.rs index bbc14f8..ec1fe30 100644 --- a/crates/obscura-render/src/paint.rs +++ b/crates/obscura-render/src/paint.rs @@ -117,17 +117,23 @@ fn paint_text_node( ) -> Option<()> { let node = tree.get_node(nid)?; let text = match &node.data { - obscura_dom::tree::NodeData::Text { contents } => contents, + obscura_dom::tree::NodeData::Text { contents } => contents.trim(), _ => return None, }; + if text.is_empty() { + return None; + } - // Find parent element to get geometry and color let parent = node.parent?; - let rect = laid.rects.get(&parent)?; let style = laid.styles.get(&parent)?; - // Default color to black if not specified. let color = style.color.unwrap_or([0, 0, 0, 255]); + // Get geometry of the text node itself! + let rect = match laid.rects.get(&nid) { + Some(r) => r, + None => return None, + }; + // Paint text at rect.x, rect.y draw_text(pixmap, text, rect.x, rect.y, color); Some(()) diff --git a/crates/obscura-render/src/style.rs b/crates/obscura-render/src/style.rs index 3fd2f98..ace332c 100644 --- a/crates/obscura-render/src/style.rs +++ b/crates/obscura-render/src/style.rs @@ -23,8 +23,11 @@ pub fn compute_style(tag: &str, inline_css: Option<&str>) -> LayoutStyle { /// Built-in UA defaults. Inline elements currently map to block layout; real /// inline/text layout arrives with the text/paint phase. pub fn ua_style(tag: &str) -> LayoutStyle { - let _ = tag; - LayoutStyle { display: Display::Block, ..Default::default() } + let display = match tag { + "span" | "a" | "b" | "i" | "strong" | "em" => Display::Inline, + _ => Display::Block, + }; + LayoutStyle { display, ..Default::default() } } pub fn apply_inline(style: &mut LayoutStyle, css: &str) { @@ -51,6 +54,7 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) { "display" => match value { "block" => style.display = Display::Block, "flex" => style.display = Display::Flex, + "inline" => style.display = Display::Inline, "none" => style.display = Display::None, _ => {} },