finishing touches and benchmarks

This commit is contained in:
Evan Almloff committed 2022-03-30 20:45:41 -05:00
1 parent 05d04165ba
commit 5b25500c0b
15 files changed
+305 -206

No files matched your search

-89
View File
@@ -1,89 +0,0 @@
use crate::client_tree::BubbledUpState;
use dioxus_core::*;
use stretch2::prelude::*;
use crate::layout_attributes::apply_layout_attributes;
/*
The layout system uses the lineheight as one point.
stretch uses fractional points, so we can rasterize if we need too, but not with characters
this means anything thats "1px" is 1 lineheight. Unfortunately, text cannot be smaller or bigger
*/
#[derive(Clone, PartialEq, Default, Debug)]
pub struct StretchLayout {
pub style: Style,
pub node: Option<Node>,
}
impl BubbledUpState for StretchLayout {
type Ctx = Stretch;
// Although we pass in the parent, the state of RinkLayout must only depend on the parent for optimiztion purposes
fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, stretch: &mut Self::Ctx)
where
I: Iterator<Item = &'a Self>,
Self: 'a,
{
match vnode {
VNode::Text(t) => {
let char_len = t.text.chars().count();
let style = Style {
size: Size {
// characters are 1 point tall
height: Dimension::Points(1.0),
// text is as long as it is declared
width: Dimension::Points(char_len as f32),
},
..Default::default()
};
if let Some(n) = self.node {
if self.style != style {
stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &[]).unwrap());
}
self.style = style;
}
VNode::Element(el) => {
// gather up all the styles from the attribute list
let mut style = Style::default();
for &Attribute { name, value, .. } in el.attributes {
apply_layout_attributes(name, value, &mut style);
}
// the root node fills the entire area
if el.id.get() == Some(ElementId(0)) {
apply_layout_attributes("width", "100%", &mut style);
apply_layout_attributes("height", "100%", &mut style);
}
// Set all direct nodes as our children
let mut child_layout = vec![];
for l in children {
child_layout.push(l.node.unwrap());
}
if let Some(n) = self.node {
if &stretch.children(n).unwrap() != &child_layout {
stretch.set_children(n, &child_layout).unwrap();
}
if self.style != style {
stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &child_layout).unwrap());
}
self.style = style;
}
_ => (),
}
}
}
+4 -11
View File
@@ -32,12 +32,7 @@
use stretch2::{prelude::*, style::PositionType};
/// applies the entire html namespace defined in dioxus-html
pub fn apply_layout_attributes(
//
name: &str,
value: &str,
style: &mut Style,
) {
pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) {
match name {
"align-content"
| "align-items"
@@ -253,6 +248,7 @@ pub fn apply_layout_attributes(
}
}
/// a relative or absolute size
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UnitSystem {
Percent(f32),
@@ -268,6 +264,7 @@ impl Into<Dimension> for UnitSystem {
}
}
/// parse relative or absolute value
pub fn parse_value(value: &str) -> Option<UnitSystem> {
if value.ends_with("px") {
if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
@@ -605,11 +602,7 @@ fn apply_align(name: &str, value: &str, style: &mut Style) {
}
}
pub fn apply_size(_name: &str, _value: &str, _style: &mut Style) {
//
}
pub fn apply_margin(name: &str, value: &str, style: &mut Style) {
fn apply_margin(name: &str, value: &str, style: &mut Style) {
match parse_value(value) {
Some(UnitSystem::Percent(v)) => match name {
"margin" => {
+1 -2
View File
@@ -1,3 +1,2 @@
pub mod client_tree;
pub mod layout;
pub mod layout_attributes;
pub mod real_dom;
@@ -6,20 +6,20 @@ use std::{
use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
/// A tree that can sync with dioxus mutations backed by a hashmap.
/// Intended for use in lazy native renderers with a state that passes from parrent to children and or accumulates state from children to parrents.
/// To get started implement [PushedDownState] and or [BubbledUpState] and call [Tree::apply_mutations] and [Tree::update_state].
/// A tree that can sync with the VirtualDom mutations intended for use in lazy renderers.
/// The render state passes from parent to children and or accumulates state from children to parents.
/// To get started implement [PushedDownState] and or [BubbledUpState] and call [Tree::apply_mutations] to update the tree and [Tree::update_state] to update the state of the nodes.
#[derive(Debug)]
pub struct ClientTree<US: BubbledUpState = (), DS: PushedDownState = ()> {
pub struct RealDom<US: BubbledUpState = (), DS: PushedDownState = ()> {
root: usize,
nodes: Vec<Option<TreeNode<US, DS>>>,
nodes_listening: FxHashMap<&'static str, FxHashSet<usize>>,
node_stack: smallvec::SmallVec<[usize; 10]>,
}
impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
pub fn new() -> ClientTree<US, DS> {
ClientTree {
impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
pub fn new() -> RealDom<US, DS> {
RealDom {
root: 0,
nodes: {
let mut v = Vec::new();
@@ -187,6 +187,7 @@ impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
ds_ctx: &mut DS::Ctx,
) -> Option<FxHashSet<usize>> {
let mut to_rerender = FxHashSet::default();
to_rerender.extend(nodes_updated.iter());
let mut nodes_updated: Vec<_> = nodes_updated
.into_iter()
.map(|id| (id, self[id].height))
@@ -296,10 +297,11 @@ impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
}
}
// remove a node and it's children from the tree.
fn remove(&mut self, id: usize) -> Option<TreeNode<US, DS>> {
// We do not need to remove the node from the parent's children list for children.
fn inner<US: BubbledUpState, DS: PushedDownState>(
tree: &mut ClientTree<US, DS>,
tree: &mut RealDom<US, DS>,
id: usize,
) -> Option<TreeNode<US, DS>> {
let mut node = tree.nodes[id as usize].take()?;
@@ -418,9 +420,9 @@ impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
}
/// Call a function for each node in the tree, depth first.
pub fn traverse(&self, mut f: impl FnMut(&TreeNode<US, DS>)) {
pub fn traverse_depth_first(&self, mut f: impl FnMut(&TreeNode<US, DS>)) {
fn inner<US: BubbledUpState, DS: PushedDownState>(
tree: &ClientTree<US, DS>,
tree: &RealDom<US, DS>,
id: ElementId,
f: &mut impl FnMut(&TreeNode<US, DS>),
) {
@@ -446,7 +448,7 @@ impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
}
}
impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for ClientTree<US, DS> {
impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for RealDom<US, DS> {
type Output = TreeNode<US, DS>;
fn index(&self, idx: usize) -> &Self::Output {
@@ -454,7 +456,7 @@ impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for ClientTree<US, DS
}
}
impl<US: BubbledUpState, DS: PushedDownState> Index<ElementId> for ClientTree<US, DS> {
impl<US: BubbledUpState, DS: PushedDownState> Index<ElementId> for RealDom<US, DS> {
type Output = TreeNode<US, DS>;
fn index(&self, idx: ElementId) -> &Self::Output {
@@ -462,12 +464,12 @@ impl<US: BubbledUpState, DS: PushedDownState> Index<ElementId> for ClientTree<US
}
}
impl<US: BubbledUpState, DS: PushedDownState> IndexMut<usize> for ClientTree<US, DS> {
impl<US: BubbledUpState, DS: PushedDownState> IndexMut<usize> for RealDom<US, DS> {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
self.get_mut(idx).expect("Node does not exist")
}
}
impl<US: BubbledUpState, DS: PushedDownState> IndexMut<ElementId> for ClientTree<US, DS> {
impl<US: BubbledUpState, DS: PushedDownState> IndexMut<ElementId> for RealDom<US, DS> {
fn index_mut(&mut self, idx: ElementId) -> &mut Self::Output {
&mut self[idx.0]
}
@@ -557,7 +559,7 @@ impl PushedDownState for () {
fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {}
}
/// This state is derived from children. For example a non-flexbox div's size could be derived from the size of children.
/// This state is derived from children. For example a node's size could be derived from the size of children.
/// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
/// Called at most once per update.
pub trait BubbledUpState: Default + PartialEq + Clone {