diff --git a/Cargo.toml b/Cargo.toml index 03177042..21857dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ style_config = { git = "https://github.com/dioxuslabs/stylo", rev = "10767f4" } style_traits = { git = "https://github.com/dioxuslabs/stylo", rev = "10767f4" } # 2024-05-15 + dioxus patches selectors = { git = "https://github.com/dioxuslabs/stylo", rev = "10767f4" } # 2024-05-15 + dioxus patches html5ever = "0.27" # needs to match stylo markup5ever version -taffy = { version = "0.5.1" } +taffy = { git = "https://github.com/dioxuslabs/taffy", rev = "9651a18b7da88204741018545edd13eda8fb2b53" } parley = { git = "https://github.com/nicoburns/parley", rev = "482d0fbd59eceaa68cc879e0102a7a9a87636a0d" } dioxus = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef"} dioxus-ssr = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef" } @@ -39,7 +39,9 @@ publish = false opt-level = 2 # Need to force specific versions of these dependencies -[dependencies] +[dev-dependencies] +# webrender = "0.61.0" +# mozbuild = "0.1.0" blitz = { path = "./packages/blitz" } blitz-dom = { path = "./packages/dom" } comrak = { version = "0.21.0", default-features = false } diff --git a/packages/blitz/src/render.rs b/packages/blitz/src/render.rs index 54c25229..705201dd 100644 --- a/packages/blitz/src/render.rs +++ b/packages/blitz/src/render.rs @@ -1152,19 +1152,11 @@ impl ElementCx<'_> { fn draw_solid_frame(&self, scene: &mut Scene) { let background = self.style.get_background(); - // todo: handle non-absolute colors - let bg_color = background.background_color.clone(); - let bg_color = bg_color.as_absolute().unwrap(); + let bg_color = background.background_color.as_vello(); let shape = self.frame.frame(); // Fill the color - scene.fill( - Fill::NonZero, - self.transform, - bg_color.as_vello(), - None, - &shape, - ); + scene.fill(Fill::NonZero, self.transform, bg_color, None, &shape); } /// Stroke a border diff --git a/packages/dioxus-blitz/Cargo.toml b/packages/dioxus-blitz/Cargo.toml index 67bdc268..90ee37c8 100644 --- a/packages/dioxus-blitz/Cargo.toml +++ b/packages/dioxus-blitz/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [features] accessibility = ["dep:accesskit", "dep:accesskit_winit"] -hot-reload = [] +hot-reload = ["dep:dioxus-cli-config", "dep:dioxus-hot-reload"] menu = ["dep:muda"] default = ["accessibility", "menu"] @@ -16,8 +16,8 @@ winit = { version = "0.30.2", features = ["rwh_06"] } muda = { version = "0.11.5", features = ["serde"], optional = true } tokio = { workspace = true, features = ["full"] } dioxus = { workspace = true } -dioxus-cli-config = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef"} -dioxus-hot-reload = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef"} +dioxus-cli-config = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef", optional = true } +dioxus-hot-reload = { git = "https://github.com/dioxuslabs/dioxus", rev = "a3aa6ae771a2d0a4d8cb6055c41efc0193b817ef", optional = true } futures-util = "0.3.30" vello = { workspace = true } wgpu = { workspace = true } diff --git a/packages/dioxus-blitz/src/documents/dioxus_document.rs b/packages/dioxus-blitz/src/documents/dioxus_document.rs index 70f0edf8..feb2f0f3 100644 --- a/packages/dioxus-blitz/src/documents/dioxus_document.rs +++ b/packages/dioxus-blitz/src/documents/dioxus_document.rs @@ -230,6 +230,7 @@ impl MutationWriter<'_> { } // If element_id is already mapping to a node, remove that node from the document else if let Some(mapped_node_id) = self.state.node_id_mapping[element_id] { + // todo: we should mark these as needing garbage collection? self.doc.remove_node(mapped_node_id); } @@ -271,6 +272,7 @@ impl WriteMutations for MutationWriter<'_> { let parent = self.state.element_to_node_id(id); for child in children { self.doc.get_node_mut(parent).unwrap().children.push(child); + self.doc.get_node_mut(child).unwrap().parent = Some(parent); } } diff --git a/packages/dioxus-blitz/src/lib.rs b/packages/dioxus-blitz/src/lib.rs index d1e75c65..c137b56d 100644 --- a/packages/dioxus-blitz/src/lib.rs +++ b/packages/dioxus-blitz/src/lib.rs @@ -23,6 +23,10 @@ use winit::{ event_loop::ControlFlow, }; +pub mod exports { + pub use dioxus; +} + #[derive(Default)] pub struct Config { pub stylesheets: Vec, @@ -128,21 +132,16 @@ fn launch_with_window(window: View<'static, Doc>) { not(target_os = "ios") ))] { - let Ok(cfg) = dioxus_cli_config::CURRENT_CONFIG.as_ref() else { - return; - }; - - dioxus_hot_reload::connect_at(cfg.target_dir.join("dioxusin"), { - let proxy = proxy.clone(); - move |template| { - let _ = proxy.send_event(UserEvent::HotReloadEvent(template)); - } - }); + if let Ok(cfg) = dioxus_cli_config::CURRENT_CONFIG.as_ref() { + dioxus_hot_reload::connect_at(cfg.target_dir.join("dioxusin"), { + let proxy = proxy.clone(); + move |template| { + let _ = proxy.send_event(UserEvent::HotReloadEvent(template)); + } + }) + } } - // the move to winit wants us to use a struct with a run method instead of the callback approach - // we want to just keep the callback approach for now - #[allow(deprecated)] // the move to winit wants us to use a struct with a run method instead of the callback approach // we want to just keep the callback approach for now #[allow(deprecated)] diff --git a/packages/dom/src/document.rs b/packages/dom/src/document.rs index ec0496da..16939379 100644 --- a/packages/dom/src/document.rs +++ b/packages/dom/src/document.rs @@ -230,8 +230,7 @@ impl Document { let node = &self.nodes[node_id]; let node_child_idx = node.child_idx; - // Get this node's parent, or the root node if it has none. - let parent_id = node.parent.unwrap_or_default(); + let parent_id = node.parent.unwrap(); let parent = &mut self.nodes[parent_id]; // Mark the node's parent as changed. diff --git a/packages/dom/src/layout/construct.rs b/packages/dom/src/layout/construct.rs index f2205beb..0d4d3572 100644 --- a/packages/dom/src/layout/construct.rs +++ b/packages/dom/src/layout/construct.rs @@ -63,12 +63,17 @@ pub(crate) fn collect_layout_children( } else { match display.outside() { DisplayOutside::None => {} - DisplayOutside::Inline => all_block = false, - DisplayOutside::Block => all_inline = false, - - // TODO: Implement table layout - DisplayOutside::TableCaption => {} - DisplayOutside::InternalTable => {} + DisplayOutside::Block + | DisplayOutside::TableCaption + | DisplayOutside::InternalTable => all_inline = false, + DisplayOutside::Inline => { + all_block = false; + + // We need the "complex" tree fixing when an inline contains a block + if child.is_or_contains_block() { + all_inline = false; + } + } } } } @@ -162,11 +167,16 @@ fn collect_complex_layout_children( let child_node_kind = doc.nodes[child_id].raw_dom_data.kind(); // Get Display style. Default to inline because nodes without styles are probably text nodes + let contains_block = doc.nodes[child_id].is_or_contains_block(); let child_display = &doc.nodes[child_id] .display_style() .unwrap_or(Display::inline()); let display_inside = child_display.inside(); - let display_outside = child_display.outside(); + let display_outside = if contains_block { + DisplayOutside::Block + } else { + child_display.outside() + }; let is_whitespace_node = match &doc.nodes[child_id].raw_dom_data { NodeData::Text(data) => data.content.chars().all(|c| c.is_ascii_whitespace()), diff --git a/packages/dom/src/layout/mod.rs b/packages/dom/src/layout/mod.rs index 4e63347e..84131b04 100644 --- a/packages/dom/src/layout/mod.rs +++ b/packages/dom/src/layout/mod.rs @@ -246,13 +246,17 @@ impl Document { ..inputs }; for ibox in inline_layout.layout.inline_boxes_mut() { - let output = self.compute_child_layout(NodeId::from(ibox.id), child_inputs); - let style = &self.nodes[ibox.id as usize].style; let margin = style.margin.resolve_or_zero(inputs.parent_size); - ibox.width = (margin.left + margin.right + output.size.width) * scale; - ibox.height = (margin.top + margin.bottom + output.size.height) * scale; + if style.position == Position::Absolute { + ibox.width = 0.0; + ibox.height = 0.0; + } else { + let output = self.compute_child_layout(NodeId::from(ibox.id), child_inputs); + ibox.width = (margin.left + margin.right + output.size.width) * scale; + ibox.height = (margin.top + margin.bottom + output.size.height) * scale; + } } // Perform inline layout @@ -337,13 +341,66 @@ impl Document { let border = node.style.border.resolve_or_zero(child_inputs.parent_size); let margin = node.style.margin.resolve_or_zero(child_inputs.parent_size); - let layout = &mut node.unrounded_layout; - layout.size.width = (ibox.width / scale) - margin.left - margin.right; - layout.size.height = (ibox.height / scale) - margin.top - margin.bottom; - layout.location.x = (ibox.x / scale) + margin.left; - layout.location.y = (ibox.y / scale) + margin.top; - layout.padding = padding; //.map(|p| p / scale); - layout.border = border; //.map(|p| p / scale); + // Resolve inset + let left = node + .style + .inset + .left + .maybe_resolve(child_inputs.parent_size.width); + let right = node + .style + .inset + .right + .maybe_resolve(child_inputs.parent_size.width); + let top = node + .style + .inset + .top + .maybe_resolve(child_inputs.parent_size.height); + let bottom = node + .style + .inset + .bottom + .maybe_resolve(child_inputs.parent_size.height); + + if node.style.position == Position::Absolute { + let output = + self.compute_child_layout(NodeId::from(ibox.id), child_inputs); + + let layout = &mut self.nodes[ibox.id as usize].unrounded_layout; + layout.size = output.size; + + // TODO: Implement absolute positioning + layout.location.x = left + .or_else(|| { + child_inputs + .parent_size + .width + .zip(right) + .map(|(w, r)| w - r) + }) + .unwrap_or(0.0); + layout.location.y = top + .or_else(|| { + child_inputs + .parent_size + .height + .zip(bottom) + .map(|(w, r)| w - r) + }) + .unwrap_or(0.0); + + layout.padding = padding; //.map(|p| p / scale); + layout.border = border; //.map(|p| p / scale); + } else { + let layout = &mut node.unrounded_layout; + layout.size.width = (ibox.width / scale) - margin.left - margin.right; + layout.size.height = (ibox.height / scale) - margin.top - margin.bottom; + layout.location.x = (ibox.x / scale) + margin.left; + layout.location.y = (ibox.y / scale) + margin.top; + layout.padding = padding; //.map(|p| p / scale); + layout.border = border; //.map(|p| p / scale); + } } } } diff --git a/packages/dom/src/node.rs b/packages/dom/src/node.rs index cf6dcd60..3ba3143c 100644 --- a/packages/dom/src/node.rs +++ b/packages/dom/src/node.rs @@ -8,6 +8,7 @@ use std::fmt::Write; use std::sync::atomic::AtomicBool; use std::sync::Arc; use style::values::computed::Display; +use style::values::specified::box_::DisplayOutside; use style_traits::dom::ElementState; // use string_cache::Atom; use style::properties::ComputedValues; @@ -122,6 +123,20 @@ impl Node { .display, ) } + + pub fn is_or_contains_block(&self) -> bool { + let display = self.display_style().unwrap_or(Display::inline()); + + match display.outside() { + DisplayOutside::None => false, + DisplayOutside::Block => true, + _ => self + .children + .iter() + .copied() + .any(|child_id| self.tree()[child_id].is_or_contains_block()), + } + } } #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/packages/dom/src/stylo.rs b/packages/dom/src/stylo.rs index 73522069..baf18996 100644 --- a/packages/dom/src/stylo.rs +++ b/packages/dom/src/stylo.rs @@ -13,6 +13,7 @@ use selectors::{ sink::Push, Element, OpaqueElement, }; +use style::values::computed::Float; // use slab::Slab; use style::values::specified::box_::DisplayOutside; use style::CaseSensitivityExt; @@ -113,8 +114,8 @@ impl crate::document::Document { _servo_top_layer, _servo_overflow_clip_box, display: stylo_display, - position, - // float, + position: stylo_position, + float, // clear, // vertical_align, overflow_x, @@ -134,10 +135,29 @@ impl crate::document::Document { .. }: &BoxStyle = style.get_box(); + // HACK: Emulate float with 'position: absolute' + let mut position = stylo_to_taffy::position(*stylo_position); + let mut inset = taffy::Rect { + left: stylo_to_taffy::length_percentage_auto(left), + right: stylo_to_taffy::length_percentage_auto(right), + top: stylo_to_taffy::length_percentage_auto(top), + bottom: stylo_to_taffy::length_percentage_auto(bottom), + }; + if position == taffy::Position::Relative && *float != Float::None { + position = taffy::Position::Absolute; + if *float == Float::Right { + inset.left = taffy::LengthPercentageAuto::Auto; + inset.right = taffy::LengthPercentageAuto::Length(0.0); + } else { + inset.left = taffy::LengthPercentageAuto::Length(0.0); + inset.right = taffy::LengthPercentageAuto::Auto; + } + } + let display = stylo_to_taffy::display(*stylo_display); node.style = Style { display, - position: stylo_to_taffy::position(*position), + position, overflow: taffy::Point { x: stylo_to_taffy::overflow(*overflow_x), y: stylo_to_taffy::overflow(*overflow_y), @@ -164,12 +184,7 @@ impl crate::document::Document { margin: stylo_to_taffy::margin(margin), padding: stylo_to_taffy::padding(padding), border: stylo_to_taffy::border(border), - inset: taffy::Rect { - left: stylo_to_taffy::length_percentage_auto(left), - right: stylo_to_taffy::length_percentage_auto(right), - top: stylo_to_taffy::length_percentage_auto(top), - bottom: stylo_to_taffy::length_percentage_auto(bottom), - }, + inset, // Alignment properties justify_content: stylo_to_taffy::content_alignment(justify_content.0),