mod common;
use common::*;
use ui_layout::*;
#[test]
fn block_basic_box_model() {
let mut root = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Length(Length::Px(100.0)),
..Default::default()
},
spacing: Spacing {
padding_left: Length::Px(10.0),
padding_right: Length::Px(10.0),
padding_top: Length::Px(5.0),
padding_bottom: Length::Px(5.0),
border_left: Length::Px(2.0),
border_right: Length::Px(2.0),
border_top: Length::Px(1.0),
border_bottom: Length::Px(1.0),
..Default::default()
},
..Default::default()
});
LayoutEngine::layout(&mut root, 800.0, 600.0);
let b = block_box(&root);
assert_eq!(b.content_box.width, 200.0);
assert_eq!(b.content_box.height, 100.0);
assert_eq!(b.padding_box.width, 220.0);
assert_eq!(b.padding_box.height, 110.0);
assert_eq!(b.border_box.width, 224.0);
assert_eq!(b.border_box.height, 112.0);
}
#[test]
fn border_box_sizing() {
let mut root = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Length(Length::Px(100.0)),
..Default::default()
},
box_sizing: BoxSizing::BorderBox,
spacing: Spacing {
padding_left: Length::Px(10.0),
padding_right: Length::Px(15.0),
padding_top: Length::Px(5.0),
padding_bottom: Length::Px(8.0),
border_left: Length::Px(2.0),
border_right: Length::Px(3.0),
border_top: Length::Px(1.0),
border_bottom: Length::Px(4.0),
..Default::default()
},
..Default::default()
});
LayoutEngine::layout(&mut root, 800.0, 600.0);
let b = block_box(&root);
assert_eq!(b.border_box.width, 200.0);
assert_eq!(b.border_box.height, 100.0);
assert_eq!(b.padding_box.width, 195.0);
assert_eq!(b.padding_box.height, 95.0);
assert_eq!(b.content_box.width, 170.0);
assert_eq!(b.content_box.height, 82.0);
}
#[test]
fn block_auto_height_from_children() {
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[new_child(40.0)],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert_eq!(block_box(node(&root, 0)).content_box.height, 40.0);
assert_eq!(block_box(&root).content_box.height, 40.0);
}
#[test]
fn auto_height_with_multiple_children() {
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[new_child(30.0), new_child(50.0), new_child(20.0)],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert_eq!(block_box(&root).content_box.height, 100.0);
assert_eq!(block_box(node(&root, 0)).border_box.y, 0.0);
assert_eq!(block_box(node(&root, 1)).border_box.y, 30.0);
assert_eq!(block_box(node(&root, 2)).border_box.y, 80.0);
}
#[test]
fn auto_height_with_padding_and_margins() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(5.0)),
margin_bottom: LengthOrAuto::Length(Length::Px(5.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(10.0)),
margin_bottom: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
spacing: Spacing {
padding_top: Length::Px(8.0),
padding_bottom: Length::Px(8.0),
..Default::default()
},
..Default::default()
},
[child1, child2],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let root_box = block_box(&root);
assert_eq!(root_box.content_box.height, 75.0);
assert_eq!(root_box.border_box.height, 91.0);
assert_eq!(root_box.content_box.y, 8.0);
}
#[test]
fn block_child_with_padding_followed_by_block_node() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Auto,
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
spacing: Spacing {
padding_top: Length::Px(10.0),
padding_bottom: Length::Px(10.0),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Auto,
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert_eq!(block_box(node(&root, 0)).border_box.y, 0.0);
assert_eq!(block_box(node(&root, 1)).border_box.y, 50.0);
assert_eq!(block_box(&root).content_box.height, 100.0);
}
#[test]
fn block_auto_height_from_direct_fragments_single_line() {
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(800.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
line_height: Length::Px(38.4),
..Default::default()
},
[fragment(79.578125, 38.4)],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let b = block_box(&root);
assert_eq!(b.content_box.height, 38.4);
assert!(b.content_box.width >= 79.578125);
}
#[test]
fn block_auto_height_from_direct_fragments_multi_line() {
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
line_height: Length::Px(20.0),
..Default::default()
},
[
fragment(60.0, 10.0),
fragment(50.0, 10.0),
fragment(30.0, 10.0),
],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let b = block_box(&root);
assert_eq!(b.content_box.height, 40.0);
}
#[test]
fn block_margin_auto_centering() {
let child = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
..Default::default()
},
spacing: Spacing {
margin_left: LengthOrAuto::Auto,
margin_right: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(300.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert_eq!(block_box(node(&root, 0)).border_box.x, 100.0);
}
#[test]
fn margins_affect_positioning() {
let child = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_left: LengthOrAuto::Length(Length::Px(20.0)),
margin_top: LengthOrAuto::Length(Length::Px(10.0)),
margin_right: LengthOrAuto::Length(Length::Px(30.0)),
margin_bottom: LengthOrAuto::Length(Length::Px(15.0)),
..Default::default()
},
..Default::default()
});
let inner = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(300.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child],
);
let mut root = LayoutNode::with_children(Style::default(), [inner]);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let c = node(&root.children[0].node().unwrap(), 0);
let b = block_box(c);
assert_eq!(b.border_box.x, 20.0);
assert_eq!(b.border_box.y, 0.0);
}
#[test]
fn block_vertical_margin_collapsing_between_siblings() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let c1 = block_box(node(&root, 0));
let c2 = block_box(node(&root, 1));
assert_eq!(c1.border_box.y, 0.0);
assert_eq!(c2.border_box.y, c1.border_box.height + 30.0);
}
#[test]
fn three_siblings_with_margin_collapse() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(5.0)),
margin_bottom: LengthOrAuto::Length(Length::Px(15.0)),
..Default::default()
},
..Default::default()
});
let child3 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(8.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2, child3],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert_eq!(block_box(node(&root, 0)).border_box.y, 0.0);
assert_eq!(block_box(node(&root, 1)).border_box.y, 30.0);
assert_eq!(block_box(node(&root, 2)).border_box.y, 75.0);
assert_eq!(block_box(&root).content_box.height, 85.0);
}
#[test]
fn parent_child_top_margin_collapse() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(node(&parent, 0)).border_box.y, 0.0);
assert_eq!(block_box(&parent).content_box.height, 50.0);
}
#[test]
fn parent_child_top_margin_collapse_blocked_by_border() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
spacing: Spacing {
border_top: Length::Px(1.0),
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(node(&parent, 0)).border_box.y, 30.0);
assert_eq!(block_box(&parent).content_box.height, 80.0);
}
#[test]
fn parent_child_top_margin_collapse_blocked_by_padding() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
spacing: Spacing {
padding_top: Length::Px(1.0),
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(node(&parent, 0)).border_box.y, 30.0);
}
#[test]
fn parent_child_bottom_margin_collapse() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(&parent).content_box.height, 50.0);
}
#[test]
fn parent_child_bottom_margin_collapse_blocked_by_border() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
spacing: Spacing {
border_bottom: Length::Px(1.0),
..Default::default()
},
..Default::default()
},
[child],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(&parent).content_box.height, 70.0);
}
#[test]
fn nested_margin_collapse_top() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(40.0)),
..Default::default()
},
..Default::default()
});
let parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child],
);
let mut grandparent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[parent],
);
LayoutEngine::layout(&mut grandparent, 800.0, 600.0);
let parent_node = node(&grandparent, 0);
let child_node = node(parent_node, 0);
assert_eq!(block_box(child_node).border_box.y, 0.0);
assert_eq!(block_box(parent_node).border_box.y, 0.0);
assert_eq!(block_box(&grandparent).content_box.height, 30.0);
}
#[test]
fn parent_child_collapse_with_sibling_margins() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(30.0)),
margin_bottom: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(15.0)),
..Default::default()
},
..Default::default()
});
let mut parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2],
);
LayoutEngine::layout(&mut parent, 800.0, 600.0);
assert_eq!(block_box(node(&parent, 0)).border_box.y, 0.0);
assert_eq!(block_box(node(&parent, 1)).border_box.y, 30.0);
assert_eq!(block_box(&parent).content_box.height, 60.0);
}
#[test]
fn parent_own_margin_collapses_with_child_margin() {
let child = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(40.0)),
..Default::default()
},
..Default::default()
});
let parent = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
..Default::default()
},
[child],
);
let mut root = LayoutNode::with_children(
Style {
spacing: Spacing {
border_top: Length::Px(1.0),
..Default::default()
},
..Default::default()
},
[parent],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let parent_node = node(&root, 0);
assert_eq!(block_box(parent_node).border_box.y, 40.0);
assert_eq!(block_box(node(parent_node, 0)).border_box.y, 0.0);
assert_eq!(block_box(parent_node).content_box.height, 50.0);
}
#[test]
fn box_model_width_height_accessors() {
let bm = BoxModel {
border_box: Rect {
x: 5.0,
y: 10.0,
width: 200.0,
height: 100.0,
},
padding_box: Rect {
x: 7.0,
y: 12.0,
width: 196.0,
height: 96.0,
},
content_box: Rect {
x: 9.0,
y: 14.0,
width: 192.0,
height: 92.0,
},
children_box: Rect {
x: 9.0,
y: 14.0,
width: 192.0,
height: 92.0,
},
};
assert_eq!(bm.width(), 200.0);
assert_eq!(bm.height(), 100.0);
}
#[test]
fn block_empty_node() {
let mut root = LayoutNode::new(Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(100.0)),
height: LengthOrAuto::Length(Length::Px(50.0)),
..Default::default()
},
..Default::default()
});
LayoutEngine::layout(&mut root, 800.0, 600.0);
let b = block_box(&root);
assert_eq!(b.content_box.width, 100.0);
assert_eq!(b.content_box.height, 50.0);
}
#[test]
fn block_with_flex_child_followed_by_block_with_margin() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
display: Display {
outer: OuterDisplay::Block,
inner: InnerDisplay::Flex,
},
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(30.0)),
..Default::default()
},
flex_direction: FlexDirection::Row,
..Default::default()
});
let child3 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(40.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(15.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2, child3],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let c1 = block_box(node(&root, 0));
let c2 = block_box(node(&root, 1));
let c3 = block_box(node(&root, 2));
assert_eq!(c1.border_box.y, 0.0);
assert_eq!(c2.border_box.y, 30.0);
assert_eq!(c3.border_box.y, 75.0);
assert_eq!(block_box(&root).content_box.height, 115.0);
}
#[test]
fn block_sibling_with_margin_after_marginless_sibling() {
let child1 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
spacing: Spacing {
margin_bottom: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let child2 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
..Default::default()
});
let child3 = LayoutNode::new(Style {
size: SizeStyle {
height: LengthOrAuto::Length(Length::Px(10.0)),
..Default::default()
},
spacing: Spacing {
margin_top: LengthOrAuto::Length(Length::Px(20.0)),
..Default::default()
},
..Default::default()
});
let mut root = LayoutNode::with_children(
Style {
size: SizeStyle {
width: LengthOrAuto::Length(Length::Px(200.0)),
height: LengthOrAuto::Auto,
..Default::default()
},
..Default::default()
},
[child1, child2, child3],
);
LayoutEngine::layout(&mut root, 800.0, 600.0);
let c1 = block_box(node(&root, 0));
let c2 = block_box(node(&root, 1));
let c3 = block_box(node(&root, 2));
assert_eq!(c1.border_box.y, 0.0);
assert_eq!(c2.border_box.y, 20.0);
assert_eq!(c3.border_box.y, 50.0);
}
#[test]
fn block_display_none() {
let mut root = LayoutNode::new(Style {
display: Display {
outer: OuterDisplay::None,
inner: InnerDisplay::Flow,
},
..Default::default()
});
LayoutEngine::layout(&mut root, 800.0, 600.0);
assert!(root.layout_box.is_empty());
assert_eq!(root.layout_box.width(), 0.0);
assert_eq!(root.layout_box.height(), 0.0);
}