-
-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #417 from Sharktheone/rendering/taffy
Calculating layout with taffy
- Loading branch information
Showing
12 changed files
with
2,150 additions
and
29 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use taffy::prelude::*; | ||
|
||
use gosub_html5::node::NodeId as GosubID; | ||
use gosub_styling::render_tree::{RenderNodeData, RenderTree}; | ||
|
||
use crate::style::get_style_from_node; | ||
|
||
pub fn generate_taffy_tree(rt: &mut RenderTree) -> anyhow::Result<(TaffyTree<GosubID>, NodeId)> { | ||
let mut tree: TaffyTree<GosubID> = TaffyTree::with_capacity(rt.nodes.len()); | ||
|
||
rt.get_root(); | ||
|
||
let root = add_children_to_tree(rt, &mut tree, rt.root)?; | ||
|
||
Ok((tree, root)) | ||
} | ||
|
||
fn add_children_to_tree( | ||
rt: &mut RenderTree, | ||
tree: &mut TaffyTree<GosubID>, | ||
node_id: GosubID, | ||
) -> anyhow::Result<NodeId> { | ||
let Some(node_children) = rt.get_children(node_id) else { | ||
return Err(anyhow::anyhow!("Node not found {:?}", node_id)); | ||
}; | ||
|
||
let mut children = Vec::with_capacity(node_children.len()); | ||
|
||
//clone, so we can drop the borrow of RT, we would be copying the NodeID anyway, so it's not a big deal (only a few bytes) | ||
for child in node_children.clone() { | ||
match add_children_to_tree(rt, tree, child) { | ||
Ok(node) => children.push(node), | ||
Err(e) => eprintln!("Error adding child to tree: {:?}", e), | ||
} | ||
} | ||
|
||
let Some(node) = rt.get_node_mut(node_id) else { | ||
return Err(anyhow::anyhow!("Node not found")); | ||
}; | ||
|
||
let style = get_style_from_node(node); | ||
|
||
let node = rt.get_node(node_id).unwrap(); | ||
if let RenderNodeData::Text(text) = &node.data { | ||
println!("Text: {:?}", text.text); | ||
println!("Style: {:?}", style.size); | ||
} | ||
|
||
let node = tree | ||
.new_with_children(style, &children) | ||
.map_err(|e| anyhow::anyhow!(e.to_string()))?; | ||
|
||
tree.set_node_context(node, Some(node_id))?; | ||
|
||
Ok(node) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
mod parse; | ||
mod parse_properties; | ||
|
||
use gosub_styling::render_tree::RenderTreeNode; | ||
use taffy::Style; | ||
|
||
const SCROLLBAR_WIDTH: f32 = 16.0; | ||
|
||
pub fn get_style_from_node(node: &mut RenderTreeNode) -> Style { | ||
let display = parse_properties::parse_display(node); | ||
let overflow = parse_properties::parse_overflow(node); | ||
let position = parse_properties::parse_position(node); | ||
let inset = parse_properties::parse_inset(node); | ||
let size = parse_properties::parse_size(node); | ||
let min_size = parse_properties::parse_min_size(node); | ||
let max_size = parse_properties::parse_max_size(node); | ||
let aspect_ratio = parse_properties::parse_aspect_ratio(node); | ||
let margin = parse_properties::parse_margin(node); | ||
let padding = parse_properties::parse_padding(node); | ||
let border = parse_properties::parse_border(node); | ||
let align_items = parse_properties::parse_align_items(node); | ||
let align_self = parse_properties::parse_align_self(node); | ||
let justify_items = parse_properties::parse_justify_items(node); | ||
let justify_self = parse_properties::parse_justify_self(node); | ||
let align_content = parse_properties::parse_align_content(node); | ||
let justify_content = parse_properties::parse_justify_content(node); | ||
let gap = parse_properties::parse_gap(node); | ||
let flex_direction = parse_properties::parse_flex_direction(node); | ||
let flex_wrap = parse_properties::parse_flex_wrap(node); | ||
let flex_basis = parse_properties::parse_flex_basis(node); | ||
let flex_grow = parse_properties::parse_flex_grow(node); | ||
let flex_shrink = parse_properties::parse_flex_shrink(node); | ||
let grid_template_rows = parse_properties::parse_grid_template_rows(node); | ||
let grid_template_columns = parse_properties::parse_grid_template_columns(node); | ||
let grid_auto_rows = parse_properties::parse_grid_auto_rows(node); | ||
let grid_auto_columns = parse_properties::parse_grid_auto_columns(node); | ||
let grid_auto_flow = parse_properties::parse_grid_auto_flow(node); | ||
let grid_row = parse_properties::parse_grid_row(node); | ||
let grid_column = parse_properties::parse_grid_column(node); | ||
|
||
Style { | ||
display, | ||
overflow, | ||
scrollbar_width: SCROLLBAR_WIDTH, | ||
position, | ||
inset, | ||
size, | ||
min_size, | ||
max_size, | ||
aspect_ratio, | ||
margin, | ||
padding, | ||
border, | ||
align_items, | ||
align_self, | ||
justify_items, | ||
justify_self, | ||
align_content, | ||
justify_content, | ||
gap, | ||
flex_direction, | ||
flex_wrap, | ||
flex_basis, | ||
flex_grow, | ||
flex_shrink, | ||
grid_template_rows, | ||
grid_template_columns, | ||
grid_auto_rows, | ||
grid_auto_columns, | ||
grid_auto_flow, | ||
grid_row, | ||
grid_column, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
use taffy::prelude::*; | ||
use taffy::{ | ||
AlignContent, AlignItems, Dimension, GridPlacement, LengthPercentage, LengthPercentageAuto, | ||
TrackSizingFunction, | ||
}; | ||
|
||
use gosub_styling::css_values::CssValue; | ||
use gosub_styling::render_tree::{RenderNodeData, RenderTreeNode}; | ||
|
||
pub(crate) fn parse_len(node: &mut RenderTreeNode, name: &str) -> LengthPercentage { | ||
let Some(property) = node.get_property(name) else { | ||
return LengthPercentage::Length(0.0); | ||
}; | ||
|
||
property.compute_value(); | ||
|
||
match &property.actual { | ||
CssValue::Percentage(value) => LengthPercentage::Percent(*value), | ||
CssValue::Unit(..) => LengthPercentage::Length(property.actual.unit_to_px()), | ||
CssValue::String(_) => LengthPercentage::Length(property.actual.unit_to_px()), //HACK | ||
_ => LengthPercentage::Length(0.0), | ||
} | ||
} | ||
|
||
pub(crate) fn parse_len_auto(node: &mut RenderTreeNode, name: &str) -> LengthPercentageAuto { | ||
let Some(property) = node.get_property(name) else { | ||
return LengthPercentageAuto::Auto; | ||
}; | ||
|
||
property.compute_value(); | ||
|
||
match &property.actual { | ||
CssValue::String(value) => match value.as_str() { | ||
"auto" => LengthPercentageAuto::Auto, | ||
_ => LengthPercentageAuto::Length(property.actual.unit_to_px()), //HACK | ||
}, | ||
CssValue::Percentage(value) => LengthPercentageAuto::Percent(*value), | ||
CssValue::Unit(..) => LengthPercentageAuto::Length(property.actual.unit_to_px()), | ||
_ => LengthPercentageAuto::Auto, | ||
} | ||
} | ||
|
||
pub(crate) fn parse_dimension(node: &mut RenderTreeNode, name: &str) -> Dimension { | ||
let mut auto = Dimension::Auto; | ||
if let RenderNodeData::Text(text) = &node.data { | ||
if name == "width" { | ||
auto = Dimension::Length(text.width); | ||
} else if name == "height" { | ||
auto = Dimension::Length(text.height); | ||
} | ||
} | ||
|
||
let Some(property) = node.get_property(name) else { | ||
return auto; | ||
}; | ||
|
||
property.compute_value(); | ||
|
||
if name == "width" { | ||
println!("Width: {:?}", property.actual); | ||
} | ||
|
||
match &property.actual { | ||
CssValue::String(value) => match value.as_str() { | ||
"auto" => auto, | ||
s if s.ends_with('%') => { | ||
let value = s.trim_end_matches('%').parse::<f32>().unwrap_or(0.0); | ||
Dimension::Percent(value) | ||
} | ||
_ => Dimension::Length(property.actual.unit_to_px()), //HACK | ||
}, | ||
CssValue::Percentage(value) => Dimension::Percent(*value), | ||
CssValue::Unit(..) => Dimension::Length(property.actual.unit_to_px()), | ||
_ => auto, | ||
} | ||
} | ||
|
||
pub(crate) fn parse_align_i(node: &mut RenderTreeNode, name: &str) -> Option<AlignItems> { | ||
let display = node.get_property(name)?; | ||
display.compute_value(); | ||
|
||
let CssValue::String(ref value) = display.actual else { | ||
return None; | ||
}; | ||
|
||
match value.as_str() { | ||
"start" => Some(AlignItems::Start), | ||
"end" => Some(AlignItems::End), | ||
"flex-start" => Some(AlignItems::FlexStart), | ||
"flex-end" => Some(AlignItems::FlexEnd), | ||
"center" => Some(AlignItems::Center), | ||
"baseline" => Some(AlignItems::Baseline), | ||
"stretch" => Some(AlignItems::Stretch), | ||
_ => None, | ||
} | ||
} | ||
|
||
pub(crate) fn parse_align_c(node: &mut RenderTreeNode, name: &str) -> Option<AlignContent> { | ||
let display = node.get_property(name)?; | ||
|
||
display.compute_value(); | ||
|
||
let CssValue::String(ref value) = display.actual else { | ||
return None; | ||
}; | ||
|
||
match value.as_str() { | ||
"start" => Some(AlignContent::Start), | ||
"end" => Some(AlignContent::End), | ||
"flex-start" => Some(AlignContent::FlexStart), | ||
"flex-end" => Some(AlignContent::FlexEnd), | ||
"center" => Some(AlignContent::Center), | ||
"stretch" => Some(AlignContent::Stretch), | ||
"space-between" => Some(AlignContent::SpaceBetween), | ||
"space-around" => Some(AlignContent::SpaceAround), | ||
_ => None, | ||
} | ||
} | ||
|
||
pub(crate) fn parse_tracking_sizing_function( | ||
node: &mut RenderTreeNode, | ||
name: &str, | ||
) -> Vec<TrackSizingFunction> { | ||
let Some(display) = node.get_property(name) else { | ||
return Vec::new(); | ||
}; | ||
|
||
display.compute_value(); | ||
|
||
let CssValue::String(ref _value) = display.actual else { | ||
return Vec::new(); | ||
}; | ||
|
||
Vec::new() //TODO: Implement this | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub(crate) fn parse_non_repeated_tracking_sizing_function( | ||
_node: &mut RenderTreeNode, | ||
_name: &str, | ||
) -> NonRepeatedTrackSizingFunction { | ||
todo!("implement parse_non_repeated_tracking_sizing_function") | ||
} | ||
|
||
pub(crate) fn parse_grid_auto( | ||
node: &mut RenderTreeNode, | ||
name: &str, | ||
) -> Vec<NonRepeatedTrackSizingFunction> { | ||
let Some(display) = node.get_property(name) else { | ||
return Vec::new(); | ||
}; | ||
|
||
display.compute_value(); | ||
|
||
let CssValue::String(ref _value) = display.actual else { | ||
return Vec::new(); | ||
}; | ||
|
||
Vec::new() //TODO: Implement this | ||
} | ||
|
||
pub(crate) fn parse_grid_placement(node: &mut RenderTreeNode, name: &str) -> GridPlacement { | ||
let Some(display) = node.get_property(name) else { | ||
return GridPlacement::Auto; | ||
}; | ||
|
||
display.compute_value(); | ||
|
||
match &display.actual { | ||
CssValue::String(value) => { | ||
if value.starts_with("span") { | ||
let value = value.trim_start_matches("span").trim(); | ||
|
||
if let Ok(value) = value.parse::<u16>() { | ||
GridPlacement::from_span(value) | ||
} else { | ||
GridPlacement::Auto | ||
} | ||
} else if let Ok(value) = value.parse::<i16>() { | ||
GridPlacement::from_line_index(value) | ||
} else { | ||
GridPlacement::Auto | ||
} | ||
} | ||
CssValue::Number(value) => GridPlacement::from_line_index(*value as i16), | ||
_ => GridPlacement::Auto, | ||
} | ||
} |
Oops, something went wrong.