render: propagate float bands through blocks
This commit is contained in:
1 parent
3ea5ea0b2b
commit
fa471bce43
3 files changed
+404
-3
No files matched your search
@@ -83,6 +83,20 @@ struct IfcRegistry {
|
|||||||
/// table column-balancing pass in `layout_dom_with_images`, which pins
|
/// table column-balancing pass in `layout_dom_with_images`, which pins
|
||||||
/// specified columns instead of sizing them purely from content.
|
/// specified columns instead of sizing them purely from content.
|
||||||
table_cols: HashMap<taffy::NodeId, (Vec<Option<f32>>, Vec<Option<f32>>)>,
|
table_cols: HashMap<taffy::NodeId, (Vec<Option<f32>>, Vec<Option<f32>>)>,
|
||||||
|
/// Floats whose direct block parent does not establish a block formatting
|
||||||
|
/// context and whose exclusion can therefore continue through later
|
||||||
|
/// descendant blocks of the same BFC. The first layout pass gives these
|
||||||
|
/// nodes real geometry; `apply_float_continuations` uses it to narrow the
|
||||||
|
/// later intersecting bands before the final layout.
|
||||||
|
float_continuations: Vec<FloatContinuation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct FloatContinuation {
|
||||||
|
owner: NodeId,
|
||||||
|
float: taffy::NodeId,
|
||||||
|
flow: taffy::NodeId,
|
||||||
|
side: crate::Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk the tree top-down accumulating the clip rect imposed by ancestor
|
/// Walk the tree top-down accumulating the clip rect imposed by ancestor
|
||||||
@@ -942,6 +956,19 @@ pub fn layout_dom_with_images(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let _ = taffy_tree.compute_layout_with_measure(taffy_root, available, &mut measure);
|
let _ = taffy_tree.compute_layout_with_measure(taffy_root, available, &mut measure);
|
||||||
|
if apply_float_continuations(
|
||||||
|
tree,
|
||||||
|
&mut taffy_tree,
|
||||||
|
&id_map,
|
||||||
|
&styles,
|
||||||
|
&ifc_items,
|
||||||
|
) {
|
||||||
|
let _ = taffy_tree.compute_layout_with_measure(
|
||||||
|
taffy_root,
|
||||||
|
available,
|
||||||
|
&mut measure,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "paint"))]
|
#[cfg(not(feature = "paint"))]
|
||||||
{
|
{
|
||||||
@@ -953,6 +980,15 @@ pub fn layout_dom_with_images(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let _ = taffy_tree.compute_layout(taffy_root, available);
|
let _ = taffy_tree.compute_layout(taffy_root, available);
|
||||||
|
if apply_float_continuations(
|
||||||
|
tree,
|
||||||
|
&mut taffy_tree,
|
||||||
|
&id_map,
|
||||||
|
&styles,
|
||||||
|
&ifc_items,
|
||||||
|
) {
|
||||||
|
let _ = taffy_tree.compute_layout(taffy_root, available);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
compute_absolute_rects(&taffy_tree, taffy_root, 0.0, 0.0, &id_map, &words, &mut rects, &mut text_runs, &mut anon_rects);
|
compute_absolute_rects(&taffy_tree, taffy_root, 0.0, 0.0, &id_map, &words, &mut rects, &mut text_runs, &mut anon_rects);
|
||||||
synthesize_row_rects(tree, &mut rects);
|
synthesize_row_rects(tree, &mut rects);
|
||||||
@@ -1384,6 +1420,307 @@ fn taffy_global_origin(
|
|||||||
Some((x, y))
|
Some((x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collect_taffy_global_rects(
|
||||||
|
taffy_tree: &TaffyTree<usize>,
|
||||||
|
node: taffy::NodeId,
|
||||||
|
parent_x: f32,
|
||||||
|
parent_y: f32,
|
||||||
|
rects: &mut HashMap<taffy::NodeId, Rect>,
|
||||||
|
) {
|
||||||
|
let Ok(layout) = taffy_tree.layout(node) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let x = parent_x + layout.location.x;
|
||||||
|
let y = parent_y + layout.location.y;
|
||||||
|
rects.insert(
|
||||||
|
node,
|
||||||
|
Rect {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: layout.size.width,
|
||||||
|
height: layout.size.height,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
for child in taffy_tree.children(node).unwrap_or_default() {
|
||||||
|
collect_taffy_global_rects(taffy_tree, child, x, y, rects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct FloatBand {
|
||||||
|
top: f32,
|
||||||
|
bottom: f32,
|
||||||
|
left: f32,
|
||||||
|
right: f32,
|
||||||
|
side: crate::Float,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn narrow_node_to_float_band(
|
||||||
|
taffy_tree: &mut TaffyTree<usize>,
|
||||||
|
node: taffy::NodeId,
|
||||||
|
preliminary_rects: &HashMap<taffy::NodeId, Rect>,
|
||||||
|
band: FloatBand,
|
||||||
|
) -> bool {
|
||||||
|
let Some(&rect) = preliminary_rects.get(&node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if rect.y >= band.bottom
|
||||||
|
|| rect.y + rect.height <= band.top
|
||||||
|
|| rect.width <= 0.0
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let Ok(current) = taffy_tree.style(node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(layout) = taffy_tree.layout(node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut narrowed = current.clone();
|
||||||
|
let (available, left_shift) = match band.side {
|
||||||
|
crate::Float::Right => {
|
||||||
|
if band.left >= rect.x + rect.width {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
((band.left - rect.x).max(0.0), 0.0)
|
||||||
|
}
|
||||||
|
crate::Float::Left => {
|
||||||
|
if band.right <= rect.x {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let shift = (band.right - rect.x).max(0.0);
|
||||||
|
((rect.width - shift).max(0.0), shift)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if available >= rect.width - 0.01 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let specified = if current.box_sizing == taffy::BoxSizing::ContentBox {
|
||||||
|
(available
|
||||||
|
- layout.padding.left
|
||||||
|
- layout.padding.right
|
||||||
|
- layout.border.left
|
||||||
|
- layout.border.right)
|
||||||
|
.max(0.0)
|
||||||
|
} else {
|
||||||
|
available
|
||||||
|
};
|
||||||
|
narrowed.size.width = taffy::Dimension::length(specified);
|
||||||
|
narrowed.max_size.width = taffy::Dimension::length(specified);
|
||||||
|
if left_shift > 0.0 {
|
||||||
|
narrowed.margin.left =
|
||||||
|
taffy::LengthPercentageAuto::length(layout.margin.left + left_shift);
|
||||||
|
}
|
||||||
|
taffy_tree.set_style(node, narrowed).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grow_bfc_to_float_bottom(
|
||||||
|
taffy_tree: &mut TaffyTree<usize>,
|
||||||
|
node: taffy::NodeId,
|
||||||
|
preliminary_rects: &HashMap<taffy::NodeId, Rect>,
|
||||||
|
float_bottom: f32,
|
||||||
|
) -> bool {
|
||||||
|
let Some(&rect) = preliminary_rects.get(&node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let desired_border_height = (float_bottom - rect.y).max(0.0);
|
||||||
|
if desired_border_height <= rect.height + 0.01 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let Ok(current) = taffy_tree.style(node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(layout) = taffy_tree.layout(node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let specified = if current.box_sizing == taffy::BoxSizing::ContentBox {
|
||||||
|
(desired_border_height
|
||||||
|
- layout.padding.top
|
||||||
|
- layout.padding.bottom
|
||||||
|
- layout.border.top
|
||||||
|
- layout.border.bottom)
|
||||||
|
.max(0.0)
|
||||||
|
} else {
|
||||||
|
desired_border_height
|
||||||
|
};
|
||||||
|
let mut grown = current.clone();
|
||||||
|
grown.min_size.height = taffy::Dimension::length(specified);
|
||||||
|
taffy_tree.set_style(node, grown).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn narrow_intersecting_descendants(
|
||||||
|
tree: &DomTree,
|
||||||
|
id: NodeId,
|
||||||
|
taffy_tree: &mut TaffyTree<usize>,
|
||||||
|
reverse: &HashMap<NodeId, taffy::NodeId>,
|
||||||
|
styles: &HashMap<NodeId, crate::LayoutStyle>,
|
||||||
|
ifc_items: &IfcRegistry,
|
||||||
|
preliminary_rects: &HashMap<taffy::NodeId, Rect>,
|
||||||
|
band: FloatBand,
|
||||||
|
) -> bool {
|
||||||
|
let Some(&node) = reverse.get(&id) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(&rect) = preliminary_rects.get(&node) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if rect.y >= band.bottom || rect.y + rect.height <= band.top {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let Some(style) = styles.get(&id) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if style.display == crate::Display::None
|
||||||
|
|| style.float.is_some()
|
||||||
|
|| matches!(style.position, Some(taffy::Position::Absolute))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float-avoiding formatting contexts move as one box. A shaped IFC or a
|
||||||
|
// leaf has no deeper block boundary at which its width can change, so it
|
||||||
|
// also consumes the current band as a unit.
|
||||||
|
let in_flow_element_children: Vec<NodeId> = tree
|
||||||
|
.children(id)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|child| {
|
||||||
|
styles.get(child).map_or(false, |child_style| {
|
||||||
|
child_style.display != crate::Display::None
|
||||||
|
&& child_style.float.is_none()
|
||||||
|
&& !matches!(
|
||||||
|
child_style.position,
|
||||||
|
Some(taffy::Position::Absolute)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if establishes_block_formatting_context(style)
|
||||||
|
|| ifc_items.whole.contains_key(&id)
|
||||||
|
|| in_flow_element_children.is_empty()
|
||||||
|
{
|
||||||
|
return narrow_node_to_float_band(
|
||||||
|
taffy_tree,
|
||||||
|
node,
|
||||||
|
preliminary_rects,
|
||||||
|
band,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut changed = false;
|
||||||
|
for child in in_flow_element_children {
|
||||||
|
changed |= narrow_intersecting_descendants(
|
||||||
|
tree,
|
||||||
|
child,
|
||||||
|
taffy_tree,
|
||||||
|
reverse,
|
||||||
|
styles,
|
||||||
|
ifc_items,
|
||||||
|
preliminary_rects,
|
||||||
|
band,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_float_continuations(
|
||||||
|
tree: &DomTree,
|
||||||
|
taffy_tree: &mut TaffyTree<usize>,
|
||||||
|
id_map: &HashMap<taffy::NodeId, NodeId>,
|
||||||
|
styles: &HashMap<NodeId, crate::LayoutStyle>,
|
||||||
|
ifc_items: &IfcRegistry,
|
||||||
|
) -> bool {
|
||||||
|
let reverse: HashMap<NodeId, taffy::NodeId> =
|
||||||
|
id_map.iter().map(|(&taffy, &dom)| (dom, taffy)).collect();
|
||||||
|
let Some(root) = id_map
|
||||||
|
.keys()
|
||||||
|
.copied()
|
||||||
|
.find(|node| taffy_tree.parent(*node).is_none())
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut preliminary_rects = HashMap::with_capacity(id_map.len());
|
||||||
|
collect_taffy_global_rects(
|
||||||
|
taffy_tree,
|
||||||
|
root,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
&mut preliminary_rects,
|
||||||
|
);
|
||||||
|
let mut changed = false;
|
||||||
|
for continuation in &ifc_items.float_continuations {
|
||||||
|
let Some(&float_rect) = preliminary_rects.get(&continuation.float) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Ok(float_layout) = taffy_tree.layout(continuation.float) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(&flow_rect) = preliminary_rects.get(&continuation.flow) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let band = FloatBand {
|
||||||
|
top: float_rect.y - float_layout.margin.top,
|
||||||
|
bottom: float_rect.y + float_rect.height + float_layout.margin.bottom,
|
||||||
|
left: float_rect.x - float_layout.margin.left,
|
||||||
|
right: float_rect.x + float_rect.width + float_layout.margin.right,
|
||||||
|
side: continuation.side,
|
||||||
|
};
|
||||||
|
if band.bottom <= flow_rect.y + flow_rect.height + 0.01 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A non-BFC wrapper is transparent to the BFC's float manager. Visit
|
||||||
|
// the wrapper's following siblings, then repeat at each ancestor until
|
||||||
|
// (and including) the nearest ancestor BFC. Descend through ordinary
|
||||||
|
// blocks so only the leaf/block bands that actually intersect the
|
||||||
|
// float are narrowed; later siblings below the float stay full width.
|
||||||
|
let mut current = continuation.owner;
|
||||||
|
while let Some(parent) = tree.get_node(current).and_then(|node| node.parent)
|
||||||
|
{
|
||||||
|
let siblings = tree.children(parent);
|
||||||
|
let Some(index) = siblings.iter().position(|candidate| *candidate == current)
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
for sibling in &siblings[index + 1..] {
|
||||||
|
changed |= narrow_intersecting_descendants(
|
||||||
|
tree,
|
||||||
|
*sibling,
|
||||||
|
taffy_tree,
|
||||||
|
&reverse,
|
||||||
|
styles,
|
||||||
|
ifc_items,
|
||||||
|
&preliminary_rects,
|
||||||
|
band,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let reached_bfc = styles
|
||||||
|
.get(&parent)
|
||||||
|
.map(establishes_block_formatting_context)
|
||||||
|
.unwrap_or(false);
|
||||||
|
if reached_bfc {
|
||||||
|
if styles
|
||||||
|
.get(&parent)
|
||||||
|
.map(|style| matches!(style.height, crate::Dimension::Auto))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
if let Some(&bfc_node) = reverse.get(&parent) {
|
||||||
|
changed |=
|
||||||
|
grow_bfc_to_float_bottom(
|
||||||
|
taffy_tree,
|
||||||
|
bfc_node,
|
||||||
|
&preliminary_rects,
|
||||||
|
band.bottom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_static_positions_and_reparent(
|
fn resolve_static_positions_and_reparent(
|
||||||
taffy_tree: &mut TaffyTree<usize>,
|
taffy_tree: &mut TaffyTree<usize>,
|
||||||
candidates: &[StaticPositionCandidate],
|
candidates: &[StaticPositionCandidate],
|
||||||
@@ -2757,6 +3094,15 @@ fn max_definite_descendant_width(tree: &DomTree, id: NodeId, styles: &HashMap<No
|
|||||||
best
|
best
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn establishes_block_formatting_context(style: &crate::LayoutStyle) -> bool {
|
||||||
|
matches!(style.display, crate::Display::Flex | crate::Display::Grid)
|
||||||
|
|| style.flow_root
|
||||||
|
|| style.overflow_hidden
|
||||||
|
|| style.is_inline_block
|
||||||
|
|| style.float.is_some()
|
||||||
|
|| matches!(style.position, Some(taffy::Position::Absolute))
|
||||||
|
}
|
||||||
|
|
||||||
fn build_children_with_float_zone(
|
fn build_children_with_float_zone(
|
||||||
tree: &DomTree,
|
tree: &DomTree,
|
||||||
parent_id: NodeId,
|
parent_id: NodeId,
|
||||||
@@ -3148,7 +3494,6 @@ fn build_children_with_float_zone(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The float itself is always an element (only elements get style
|
// The float itself is always an element (only elements get style
|
||||||
// entries, and `is_float` above required one), so a direct `build` call
|
// entries, and `is_float` above required one), so a direct `build` call
|
||||||
// is correct here; only its flow siblings need the word-splitting `build_any`.
|
// is correct here; only its flow siblings need the word-splitting `build_any`.
|
||||||
@@ -3227,12 +3572,52 @@ fn build_children_with_float_zone(
|
|||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
// A float does not contribute to the height of a non-BFC block
|
||||||
|
// that contains it. Put an escaping float inside a zero-height,
|
||||||
|
// overflow-visible wrapper: its real width still reserves the
|
||||||
|
// current band, but its height can protrude into later descendant
|
||||||
|
// blocks of the ancestor BFC. A matching `clear` or any remaining
|
||||||
|
// direct full-width sibling keeps the old containing row, since
|
||||||
|
// that content explicitly terminates the local float zone.
|
||||||
|
let can_escape = zone_end == dom_children.len()
|
||||||
|
&& styles
|
||||||
|
.get(&parent_id)
|
||||||
|
.map(|style| !establishes_block_formatting_context(style))
|
||||||
|
.unwrap_or(false);
|
||||||
|
let row_float = if can_escape {
|
||||||
|
let wrapper_style = taffy::Style {
|
||||||
|
display: taffy::style::Display::Block,
|
||||||
|
flex_grow: 0.0,
|
||||||
|
flex_shrink: 0.0,
|
||||||
|
size: taffy::Size {
|
||||||
|
width: taffy::Dimension::auto(),
|
||||||
|
height: taffy::Dimension::length(0.0),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
taffy_tree
|
||||||
|
.new_with_children(wrapper_style, &[float_id])
|
||||||
|
.ok()
|
||||||
|
.unwrap_or(float_id)
|
||||||
|
} else {
|
||||||
|
float_id
|
||||||
|
};
|
||||||
let row_children: Vec<taffy::NodeId> = match float_side {
|
let row_children: Vec<taffy::NodeId> = match float_side {
|
||||||
Some(crate::Float::Left) => [Some(float_id), flow_column].into_iter().flatten().collect(),
|
Some(crate::Float::Left) => [Some(row_float), flow_column].into_iter().flatten().collect(),
|
||||||
_ => [flow_column, Some(float_id)].into_iter().flatten().collect(),
|
_ => [flow_column, Some(row_float)].into_iter().flatten().collect(),
|
||||||
};
|
};
|
||||||
if let Ok(row) = taffy_tree.new_with_children(row_style, &row_children) {
|
if let Ok(row) = taffy_tree.new_with_children(row_style, &row_children) {
|
||||||
result.push(row);
|
result.push(row);
|
||||||
|
if can_escape {
|
||||||
|
if let (Some(flow), Some(side)) = (flow_column, float_side) {
|
||||||
|
ifc_items.float_continuations.push(FloatContinuation {
|
||||||
|
owner: parent_id,
|
||||||
|
float: float_id,
|
||||||
|
flow,
|
||||||
|
side,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The float itself failed to build (e.g. display:none resolved for
|
// The float itself failed to build (e.g. display:none resolved for
|
||||||
|
|||||||
@@ -413,6 +413,11 @@ pub struct LayoutStyle {
|
|||||||
/// own box (including any `::before`/`::after` content attached to it).
|
/// own box (including any `::before`/`::after` content attached to it).
|
||||||
pub is_inline_block: bool,
|
pub is_inline_block: bool,
|
||||||
|
|
||||||
|
/// `display: flow-root`: generates a normal block box but establishes a
|
||||||
|
/// new block formatting context, containing descendant floats and stopping
|
||||||
|
/// their exclusion bands from propagating into outside siblings.
|
||||||
|
pub flow_root: bool,
|
||||||
|
|
||||||
/// `display: contents`: the element generates no box of its own; its
|
/// `display: contents`: the element generates no box of its own; its
|
||||||
/// children participate in the parent's formatting context directly
|
/// children participate in the parent's formatting context directly
|
||||||
/// (`dom::build_any` splices them into the parent's child list). Kept as a
|
/// (`dom::build_any` splices them into the parent's child list). Kept as a
|
||||||
|
|||||||
@@ -257,9 +257,12 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
|
|||||||
| "grid"
|
| "grid"
|
||||||
| "inline-grid"
|
| "inline-grid"
|
||||||
| "block"
|
| "block"
|
||||||
|
| "flow-root"
|
||||||
| "contents"
|
| "contents"
|
||||||
) {
|
) {
|
||||||
style.internal_flex_container = false;
|
style.internal_flex_container = false;
|
||||||
|
style.is_inline_block = false;
|
||||||
|
style.flow_root = false;
|
||||||
}
|
}
|
||||||
match value {
|
match value {
|
||||||
"none" => style.display = crate::Display::None,
|
"none" => style.display = crate::Display::None,
|
||||||
@@ -273,6 +276,10 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
|
|||||||
"grid" => style.display = crate::Display::Grid,
|
"grid" => style.display = crate::Display::Grid,
|
||||||
"inline-grid" => style.display = crate::Display::Grid,
|
"inline-grid" => style.display = crate::Display::Grid,
|
||||||
"block" => style.display = crate::Display::Block,
|
"block" => style.display = crate::Display::Block,
|
||||||
|
"flow-root" => {
|
||||||
|
style.display = crate::Display::Block;
|
||||||
|
style.flow_root = true;
|
||||||
|
}
|
||||||
"contents" => style.display_contents = true,
|
"contents" => style.display_contents = true,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -2742,6 +2749,10 @@ mod tests {
|
|||||||
assert_eq!(s.display, Display::Flex);
|
assert_eq!(s.display, Display::Flex);
|
||||||
assert_eq!(s.width, crate::Dimension::Px(200.0));
|
assert_eq!(s.width, crate::Dimension::Px(200.0));
|
||||||
assert_eq!(s.height, crate::Dimension::Px(50.0));
|
assert_eq!(s.height, crate::Dimension::Px(50.0));
|
||||||
|
|
||||||
|
let flow_root = compute_style("div", Some("display: flow-root"));
|
||||||
|
assert_eq!(flow_root.display, Display::Block);
|
||||||
|
assert!(flow_root.flow_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in new issue
Block a user