fix(render): correct center tag alignment and percentage dimensions
This commit is contained in:
1 parent
42874989eb
commit
bd4845b52c
2 files changed
+62
-26
No files matched your search
@@ -54,13 +54,20 @@ pub enum Display {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
||||||
|
pub enum Dimension {
|
||||||
|
#[default]
|
||||||
|
Auto,
|
||||||
|
Px(f32),
|
||||||
|
Percent(f32),
|
||||||
|
}
|
||||||
|
|
||||||
/// The subset of CSS that influences box layout. Expanded in later phases.
|
/// The subset of CSS that influences box layout. Expanded in later phases.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct LayoutStyle {
|
pub struct LayoutStyle {
|
||||||
pub display: Display,
|
pub display: Display,
|
||||||
/// Content-box size. None means auto.
|
pub width: Dimension,
|
||||||
pub width: Option<f32>,
|
pub height: Dimension,
|
||||||
pub height: Option<f32>,
|
|
||||||
pub margin: Edges,
|
pub margin: Edges,
|
||||||
pub padding: Edges,
|
pub padding: Edges,
|
||||||
pub border: Edges,
|
pub border: Edges,
|
||||||
@@ -70,6 +77,8 @@ pub struct LayoutStyle {
|
|||||||
pub color: Option<[u8; 4]>,
|
pub color: Option<[u8; 4]>,
|
||||||
pub border_color: Option<[u8; 4]>,
|
pub border_color: Option<[u8; 4]>,
|
||||||
pub font_size: Option<f32>,
|
pub font_size: Option<f32>,
|
||||||
|
pub align_items: Option<taffy::AlignItems>,
|
||||||
|
pub flex_direction: Option<taffy::FlexDirection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node in the input layout tree. `text` is carried for the paint phase; it
|
/// A node in the input layout tree. `text` is carried for the paint phase; it
|
||||||
@@ -148,7 +157,9 @@ pub(crate) fn to_taffy_style(style: &LayoutStyle) -> Style {
|
|||||||
Display::Inline => taffy::style::Display::Flex,
|
Display::Inline => taffy::style::Display::Flex,
|
||||||
Display::None => taffy::style::Display::None,
|
Display::None => taffy::style::Display::None,
|
||||||
};
|
};
|
||||||
if style.display == Display::Inline {
|
if let Some(fd) = style.flex_direction {
|
||||||
|
s.flex_direction = fd;
|
||||||
|
} else if style.display == Display::Inline {
|
||||||
s.flex_direction = taffy::FlexDirection::Row;
|
s.flex_direction = taffy::FlexDirection::Row;
|
||||||
}
|
}
|
||||||
s.flex_wrap = taffy::FlexWrap::Wrap;
|
s.flex_wrap = taffy::FlexWrap::Wrap;
|
||||||
@@ -156,16 +167,20 @@ pub(crate) fn to_taffy_style(style: &LayoutStyle) -> Style {
|
|||||||
width: dimension(style.width),
|
width: dimension(style.width),
|
||||||
height: dimension(style.height),
|
height: dimension(style.height),
|
||||||
};
|
};
|
||||||
|
if let Some(ai) = style.align_items {
|
||||||
|
s.align_items = Some(ai);
|
||||||
|
}
|
||||||
s.margin = rect_auto(style.margin);
|
s.margin = rect_auto(style.margin);
|
||||||
s.padding = rect_lp(style.padding);
|
s.padding = rect_lp(style.padding);
|
||||||
s.border = rect_lp(style.border);
|
s.border = rect_lp(style.border);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dimension(v: Option<f32>) -> taffy::style::Dimension {
|
fn dimension(v: Dimension) -> taffy::style::Dimension {
|
||||||
match v {
|
match v {
|
||||||
Some(px) => taffy::style::Dimension::Length(px),
|
Dimension::Px(px) => taffy::style::Dimension::Length(px),
|
||||||
None => taffy::style::Dimension::Auto,
|
Dimension::Percent(p) => taffy::style::Dimension::Percent(p),
|
||||||
|
Dimension::Auto => taffy::style::Dimension::Auto,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +206,8 @@ fn rect_auto(e: Edges) -> taffy::Rect<taffy::style::LengthPercentageAuto> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn styled(display: Display, w: Option<f32>, h: Option<f32>) -> LayoutStyle {
|
fn make_box(display: Display, w: f32, h: f32) -> LayoutStyle {
|
||||||
LayoutStyle { display, width: w, height: h, ..Default::default() }
|
LayoutStyle { display, width: Dimension::Px(w), height: Dimension::Px(h), ..Default::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -200,11 +215,11 @@ mod tests {
|
|||||||
// A 1000px-wide viewport, two fixed-size block children: they should
|
// A 1000px-wide viewport, two fixed-size block children: they should
|
||||||
// stack top-to-bottom at the expected y offsets.
|
// stack top-to-bottom at the expected y offsets.
|
||||||
let root = LayoutNode {
|
let root = LayoutNode {
|
||||||
style: styled(Display::Block, Some(1000.0), None),
|
style: make_box(Display::Block, 1000.0, 800.0),
|
||||||
text: None,
|
text: None,
|
||||||
children: vec![
|
children: vec![
|
||||||
LayoutNode::leaf(styled(Display::Block, Some(1000.0), Some(50.0))),
|
LayoutNode::leaf(make_box(Display::Block, 1000.0, 50.0)),
|
||||||
LayoutNode::leaf(styled(Display::Block, Some(1000.0), Some(30.0))),
|
LayoutNode::leaf(make_box(Display::Block, 1000.0, 30.0)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
let out = layout(&root, (1000.0, 800.0));
|
let out = layout(&root, (1000.0, 800.0));
|
||||||
@@ -225,11 +240,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn flex_row_lays_out_horizontally() {
|
fn flex_row_lays_out_horizontally() {
|
||||||
let root = LayoutNode {
|
let root = LayoutNode {
|
||||||
style: LayoutStyle { display: Display::Flex, width: Some(600.0), height: Some(100.0), ..Default::default() },
|
style: LayoutStyle { display: Display::Flex, width: Dimension::Px(600.0), height: Dimension::Px(100.0), ..Default::default() },
|
||||||
text: None,
|
text: None,
|
||||||
children: vec![
|
children: vec![
|
||||||
LayoutNode::leaf(styled(Display::Block, Some(200.0), Some(100.0))),
|
LayoutNode::leaf(make_box(Display::Block, 200.0, 100.0)),
|
||||||
LayoutNode::leaf(styled(Display::Block, Some(200.0), Some(100.0))),
|
LayoutNode::leaf(make_box(Display::Block, 200.0, 100.0)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
let out = layout(&root, (600.0, 400.0));
|
let out = layout(&root, (600.0, 400.0));
|
||||||
@@ -249,8 +264,8 @@ fn flex_row_lays_out_horizontally() {
|
|||||||
let root = LayoutNode {
|
let root = LayoutNode {
|
||||||
style: LayoutStyle {
|
style: LayoutStyle {
|
||||||
display: Display::Block,
|
display: Display::Block,
|
||||||
width: Some(100.0),
|
width: Dimension::Px(100.0),
|
||||||
height: Some(100.0),
|
height: Dimension::Px(100.0),
|
||||||
padding: Edges { top: 10.0, right: 10.0, bottom: 10.0, left: 10.0 },
|
padding: Edges { top: 10.0, right: 10.0, bottom: 10.0, left: 10.0 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,11 +23,20 @@ pub fn compute_style(tag: &str, inline_css: Option<&str>) -> LayoutStyle {
|
|||||||
/// Built-in UA defaults. Inline elements currently map to block layout; real
|
/// Built-in UA defaults. Inline elements currently map to block layout; real
|
||||||
/// inline/text layout arrives with the text/paint phase.
|
/// inline/text layout arrives with the text/paint phase.
|
||||||
pub fn ua_style(tag: &str) -> LayoutStyle {
|
pub fn ua_style(tag: &str) -> LayoutStyle {
|
||||||
let display = match tag {
|
let mut style = LayoutStyle::default();
|
||||||
"span" | "a" | "b" | "i" | "strong" | "em" => Display::Inline,
|
style.display = match tag {
|
||||||
|
"span" | "a" | "b" | "i" | "strong" | "em" | "font" => Display::Inline,
|
||||||
|
"tr" => Display::Flex,
|
||||||
_ => Display::Block,
|
_ => Display::Block,
|
||||||
};
|
};
|
||||||
LayoutStyle { display, ..Default::default() }
|
if tag == "center" {
|
||||||
|
style.display = Display::Flex;
|
||||||
|
style.flex_direction = Some(taffy::FlexDirection::Column);
|
||||||
|
style.align_items = Some(taffy::AlignItems::Center);
|
||||||
|
} else if tag == "body" {
|
||||||
|
style.margin = Edges { top: 8.0, right: 8.0, bottom: 8.0, left: 8.0 };
|
||||||
|
}
|
||||||
|
style
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_inline(style: &mut LayoutStyle, css: &str) {
|
pub fn apply_inline(style: &mut LayoutStyle, css: &str) {
|
||||||
@@ -58,8 +67,8 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
|
|||||||
"none" => style.display = Display::None,
|
"none" => style.display = Display::None,
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
"width" => style.width = px(value),
|
"width" => style.width = dimension_value(value),
|
||||||
"height" => style.height = px(value),
|
"height" => style.height = dimension_value(value),
|
||||||
"margin" => { if let Some(e) = edges(value) { style.margin = e; } }
|
"margin" => { if let Some(e) = edges(value) { style.margin = e; } }
|
||||||
"margin-top" => set_edge(&mut style.margin, Side::Top, px(value)),
|
"margin-top" => set_edge(&mut style.margin, Side::Top, px(value)),
|
||||||
"margin-right" => set_edge(&mut style.margin, Side::Right, px(value)),
|
"margin-right" => set_edge(&mut style.margin, Side::Right, px(value)),
|
||||||
@@ -150,6 +159,18 @@ fn px(value: &str) -> Option<f32> {
|
|||||||
token(value).and_then(px_value)
|
token(value).and_then(px_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dimension_value(tok: &str) -> crate::Dimension {
|
||||||
|
let n = tok.trim();
|
||||||
|
if n.ends_with("%") {
|
||||||
|
if let Ok(v) = n[..n.len()-1].parse::<f32>() {
|
||||||
|
return crate::Dimension::Percent(v / 100.0);
|
||||||
|
}
|
||||||
|
} else if let Some(px) = px(tok) {
|
||||||
|
return crate::Dimension::Px(px);
|
||||||
|
}
|
||||||
|
crate::Dimension::Auto
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse every length token in a value as px (for box shorthands).
|
/// Parse every length token in a value as px (for box shorthands).
|
||||||
fn edges(value: &str) -> Option<Edges> {
|
fn edges(value: &str) -> Option<Edges> {
|
||||||
let dims: Vec<f32> = value.split_whitespace().filter_map(px_value).collect();
|
let dims: Vec<f32> = value.split_whitespace().filter_map(px_value).collect();
|
||||||
@@ -205,8 +226,8 @@ mod tests {
|
|||||||
fn parses_display_and_size() {
|
fn parses_display_and_size() {
|
||||||
let s = compute_style("div", Some("display: flex; width: 200px; height: 50px"));
|
let s = compute_style("div", Some("display: flex; width: 200px; height: 50px"));
|
||||||
assert_eq!(s.display, Display::Flex);
|
assert_eq!(s.display, Display::Flex);
|
||||||
assert_eq!(s.width, Some(200.0));
|
assert_eq!(s.width, crate::Dimension::Px(200.0));
|
||||||
assert_eq!(s.height, Some(50.0));
|
assert_eq!(s.height, crate::Dimension::Px(50.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -231,7 +252,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn important_and_auto() {
|
fn important_and_auto() {
|
||||||
let s = compute_style("div", Some("width: 100px !important; height: auto"));
|
let s = compute_style("div", Some("width: 100px !important; height: auto"));
|
||||||
assert_eq!(s.width, Some(100.0));
|
assert_eq!(s.width, crate::Dimension::Px(100.0));
|
||||||
assert_eq!(s.height, None);
|
assert_eq!(s.height, crate::Dimension::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user