Skip to content

Commit

Permalink
Merge pull request #536 from Sharktheone/layout/layout-trait
Browse files Browse the repository at this point in the history
Put Layouting behind a trait for modularity
  • Loading branch information
Sharktheone authored Aug 8, 2024
2 parents 71b6344 + 55158ae commit 09a9ccf
Show file tree
Hide file tree
Showing 41 changed files with 1,304 additions and 633 deletions.
15 changes: 13 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ gosub_renderer = { path = "./crates/gosub_renderer", features = [] }
gosub_render_backend = { path = "./crates/gosub_render_backend", features = [] }
gosub_vello = { path = "./crates/gosub_vello", features = [] }
gosub_useragent = { path = "./crates/gosub_useragent", features = [] }
gosub_taffy = { path = "./crates/gosub_taffy", features = [] }
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
derive_more = "0.99"
Expand Down
14 changes: 14 additions & 0 deletions crates/gosub_html5/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ impl From<usize> for NodeId {
}
}

impl From<u64> for NodeId {
/// Converts a u64 into a NodeId
fn from(value: u64) -> Self {
Self(value as usize)
}
}

impl From<NodeId> for u64 {
/// Converts a NodeId into a u64
fn from(value: NodeId) -> Self {
value.0 as u64
}
}

impl Default for &NodeId {
/// Returns the default NodeId, which is 0
fn default() -> Self {
Expand Down
2 changes: 1 addition & 1 deletion crates/gosub_html5/src/node/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ mod tests {
let id = document.arena.register_node(node);

assert_eq!(document.arena.nodes.len(), 1);
assert_eq!(document.arena.next_id, 1.into());
assert_eq!(document.arena.next_id, 1usize.into());
assert_eq!(id, NodeId::default());
}

Expand Down
6 changes: 3 additions & 3 deletions crates/gosub_html5/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4561,7 +4561,7 @@ mod test {
let binding = document.get();

// document -> html -> head -> body -> div
let div = binding.get_node_by_id(4.into()).unwrap();
let div = binding.get_node_by_id(4usize.into()).unwrap();

let NodeData::Element(element) = &div.data else {
panic!()
Expand Down Expand Up @@ -4593,7 +4593,7 @@ mod test {
let binding = document.get();

// document -> html -> head -> body -> div
let div = binding.get_node_by_id(4.into()).unwrap();
let div = binding.get_node_by_id(4usize.into()).unwrap();

let NodeData::Element(element) = &div.data else {
panic!()
Expand Down Expand Up @@ -4643,7 +4643,7 @@ mod test {
// we are expecting the div (ID: 4) and p would be ignored
let doc_read = document.get();
let div = doc_read.get_node_by_named_id("myid").unwrap();
assert_eq!(div.id, NodeId::from(4));
assert_eq!(div.id, NodeId::from(4usize));
assert_eq!(div.name, "div");
}
}
42 changes: 24 additions & 18 deletions crates/gosub_html5/src/parser/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,9 @@ mod tests {
let node3 = Node::new_element(&document, "div3", HashMap::new(), HTML_NAMESPACE);
let node3_1 = Node::new_element(&document, "div3_1", HashMap::new(), HTML_NAMESPACE);

let parent_id = document.get_mut().add_node(parent, NodeId::from(0), None);
let parent_id = document
.get_mut()
.add_node(parent, NodeId::from(0usize), None);
let node1_id = document.get_mut().add_node(node1, parent_id, None);
let node2_id = document.get_mut().add_node(node2, parent_id, None);
let node3_id = document.get_mut().add_node(node3, parent_id, None);
Expand Down Expand Up @@ -1142,25 +1144,29 @@ mod tests {
let node1 = Node::new_element(&document, "div", HashMap::new(), HTML_NAMESPACE);
let node2 = Node::new_element(&document, "div", HashMap::new(), HTML_NAMESPACE);

document.get_mut().add_node(node1, NodeId::from(0), None);
document.get_mut().add_node(node2, NodeId::from(0), None);
document
.get_mut()
.add_node(node1, NodeId::from(0usize), None);
document
.get_mut()
.add_node(node2, NodeId::from(0usize), None);

let doc_ptr = document.get();

let get_node1 = doc_ptr.get_node_by_id(NodeId::from(1)).unwrap();
let get_node2 = doc_ptr.get_node_by_id(NodeId::from(2)).unwrap();
let get_node1 = doc_ptr.get_node_by_id(NodeId::from(1usize)).unwrap();
let get_node2 = doc_ptr.get_node_by_id(NodeId::from(2usize)).unwrap();

let NodeData::Element(element1) = &get_node1.data else {
panic!()
};

assert_eq!(element1.node_id, NodeId::from(1));
assert_eq!(element1.node_id, NodeId::from(1usize));

let NodeData::Element(element2) = &get_node2.data else {
panic!()
};

assert_eq!(element2.node_id, NodeId::from(2));
assert_eq!(element2.node_id, NodeId::from(2usize));
}

#[test]
Expand All @@ -1182,10 +1188,10 @@ mod tests {

// NOTE: only elements return the ID
let div_id = task_queue.create_element("div", NodeId::root(), None, HTML_NAMESPACE);
assert_eq!(div_id, NodeId::from(1));
assert_eq!(div_id, NodeId::from(1usize));

let p_id = task_queue.create_element("p", div_id, None, HTML_NAMESPACE);
assert_eq!(p_id, NodeId::from(2));
assert_eq!(p_id, NodeId::from(2usize));

task_queue.create_comment("comment inside p", p_id);
task_queue.create_text("hey", p_id);
Expand Down Expand Up @@ -1282,13 +1288,13 @@ mod tests {

// NOTE: inserting attribute in task queue always succeeds
// since it doesn't touch DOM until flush
let _ = task_queue.insert_attribute("id", "myid", NodeId::from(1));
let _ = task_queue.insert_attribute("id", "myid", NodeId::from(1));
let _ = task_queue.insert_attribute("id", "otherid", NodeId::from(2));
let _ = task_queue.insert_attribute("id", "dummyid", NodeId::from(42));
let _ = task_queue.insert_attribute("id", "my id", NodeId::from(1));
let _ = task_queue.insert_attribute("id", "123", NodeId::from(1));
let _ = task_queue.insert_attribute("id", "", NodeId::from(1));
let _ = task_queue.insert_attribute("id", "myid", NodeId::from(1usize));
let _ = task_queue.insert_attribute("id", "myid", NodeId::from(1usize));
let _ = task_queue.insert_attribute("id", "otherid", NodeId::from(2usize));
let _ = task_queue.insert_attribute("id", "dummyid", NodeId::from(42usize));
let _ = task_queue.insert_attribute("id", "my id", NodeId::from(1usize));
let _ = task_queue.insert_attribute("id", "123", NodeId::from(1usize));
let _ = task_queue.insert_attribute("id", "", NodeId::from(1usize));
let errors = task_queue.flush();
for error in &errors {
println!("{}", error);
Expand Down Expand Up @@ -1335,10 +1341,10 @@ mod tests {

// NOTE: only elements return the ID
let div_id = document.create_element("div", NodeId::root(), None, HTML_NAMESPACE);
assert_eq!(div_id, NodeId::from(1));
assert_eq!(div_id, NodeId::from(1usize));

let p_id = document.create_element("p", div_id, None, HTML_NAMESPACE);
assert_eq!(p_id, NodeId::from(2));
assert_eq!(p_id, NodeId::from(2usize));

document.create_comment("comment inside p", p_id);
document.create_text("hey", p_id);
Expand Down
7 changes: 7 additions & 0 deletions crates/gosub_render_backend/src/geo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use gosub_shared::types::Size as SizeT;

pub type FP = f32;
pub type Point = gosub_shared::types::Point<FP>;
pub type Size = SizeT<f32>;
pub type SizeU32 = SizeT<u32>;
pub type Rect = gosub_shared::types::Rect<FP>;
123 changes: 123 additions & 0 deletions crates/gosub_render_backend/src/layout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use gosub_shared::types::Result;

use crate::geo::{Point, Rect, Size, SizeU32};

pub trait LayoutTree<L: Layouter>: Sized {
type NodeId: Copy + Clone + From<u64> + Into<u64>;
type Node: Node;

fn children(&self, id: Self::NodeId) -> Option<Vec<Self::NodeId>>;
fn contains(&self, id: &Self::NodeId) -> bool;
fn child_count(&self, id: Self::NodeId) -> usize;
fn get_cache(&self, id: Self::NodeId) -> Option<&L::Cache>;
fn get_layout(&self, id: Self::NodeId) -> Option<&L::Layout>;

fn get_cache_mut(&mut self, id: Self::NodeId) -> Option<&mut L::Cache>;
fn get_layout_mut(&mut self, id: Self::NodeId) -> Option<&mut L::Layout>;
fn set_cache(&mut self, id: Self::NodeId, cache: L::Cache);
fn set_layout(&mut self, id: Self::NodeId, layout: L::Layout);

fn style_dirty(&self, id: Self::NodeId) -> bool;

fn clean_style(&mut self, id: Self::NodeId);

fn get_node(&mut self, id: Self::NodeId) -> Option<&mut Self::Node>;
}

pub trait Layouter: Sized + Clone {
type Cache: Default;
type Layout: Layout;
fn layout<LT: LayoutTree<Self>>(
&self,
tree: &mut LT,
root: LT::NodeId,
space: SizeU32,
) -> Result<()>;
}

pub trait Layout: Default {
/// Returns the relative upper left pos of the content box
fn rel_pos(&self) -> Point;

/// Returns the z-index of the element
fn z_index(&self) -> u32;

/// Size of the scroll box (content box without overflow), including scrollbars (if any)
fn size(&self) -> Size;

/// Size of the content box (content without scrollbars, but with overflow)
fn content(&self) -> Size;
fn content_box(&self) -> Rect {
let pos = self.rel_pos();
let size = self.size();
Rect::from_components(pos, size)
}

/// Additional space taken up by the scrollbar
fn scrollbar(&self) -> Size;
fn scrollbar_box(&self) -> Rect {
let pos = self.rel_pos();
let content = self.content();
let size = self.scrollbar();
Rect::new(
pos.x,
pos.y,
content.width + size.width,
content.height + size.height,
)
}

fn border(&self) -> Rect;
fn border_box(&self) -> Rect {
let pos = self.rel_pos();
let size = self.size();
let border = self.border();

Rect::new(
pos.x - border.x1,
pos.y - border.y1,
size.width + border.x2,
size.height + border.y2,
)
}

fn padding(&self) -> Rect;
fn padding_box(&self) -> Rect {
let pos = self.rel_pos();
let border = self.border();
Rect::from_components(pos, border.size())
}

fn margin(&self) -> Rect;
fn margin_box(&self) -> Rect {
let border = self.border_box();
let margin = self.margin();

Rect::new(
border.x1 - margin.x1,
border.y1 - margin.y1,
border.x2 + margin.x2,
border.y2 + margin.y2,
)
}
}

/// TODO: This struct should be removed and done somehow differently...
pub trait Node {
type Property: CssProperty;

fn get_property(&mut self, name: &str) -> Option<&mut Self::Property>; //TODO: this needs to be more generic...
fn text_size(&mut self) -> Option<Size>;
}

pub trait CssProperty {
fn compute_value(&mut self);
fn unit_to_px(&self) -> f32;

fn as_string(&self) -> Option<&str>;
fn as_percentage(&self) -> Option<f32>;
fn as_unit(&self) -> Option<(f32, &str)>;
fn as_color(&self) -> Option<(f32, f32, f32, f32)>;
fn as_number(&self) -> Option<f32>;
fn is_none(&self) -> bool;
}
16 changes: 5 additions & 11 deletions crates/gosub_render_backend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
use std::fmt::Debug;
use std::ops::{Div, Mul, MulAssign};

use crate::svg::SvgRenderer;
pub use geo::*;
use gosub_shared::types::Result;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use smallvec::SmallVec;

use gosub_shared::types::Result;
use gosub_shared::types::Size as SizeT;

use crate::svg::SvgRenderer;

pub mod geo;
pub mod layout;
pub mod svg;

pub type Size = SizeT<f32>;
pub type SizeU32 = SizeT<u32>;

pub trait WindowHandle: HasDisplayHandle + HasWindowHandle + Send + Sync + Clone {}

impl<T> WindowHandle for T where T: HasDisplayHandle + HasWindowHandle + Send + Sync + Clone {}
Expand Down Expand Up @@ -86,9 +83,6 @@ pub trait Scene<B: RenderBackend> {
fn new(data: &mut B::WindowData<'_>) -> Self;
}

pub type FP = f32;
pub type Point = gosub_shared::types::Point<FP>;

pub struct RenderRect<B: RenderBackend> {
pub rect: B::Rect,
pub transform: Option<B::Transform>,
Expand Down
1 change: 0 additions & 1 deletion crates/gosub_render_utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ license = "MIT"
gosub_html5 = { path = "../gosub_html5" }
gosub_styling = { path = "../gosub_styling" }
gosub_render_backend = { path = "../gosub_render_backend" }
taffy = "0.5.2"
anyhow = "1.0.86"
regex = "1.10.6"
rstar = "0.12.0"
Loading

0 comments on commit 09a9ccf

Please sign in to comment.