-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move inline layout to it's own module
Signed-off-by: Nico Burns <[email protected]>
- Loading branch information
Showing
2 changed files
with
219 additions
and
212 deletions.
There are no files selected for viewing
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,215 @@ | ||
use taffy::{ | ||
compute_leaf_layout, AvailableSpace, LayoutPartialTree as _, MaybeMath as _, MaybeResolve as _, | ||
NodeId, Position, ResolveOrZero as _, Size, | ||
}; | ||
|
||
use crate::Document; | ||
|
||
impl Document { | ||
pub(crate) fn compute_inline_layout( | ||
&mut self, | ||
node_id: usize, | ||
inputs: taffy::tree::LayoutInput, | ||
) -> taffy::LayoutOutput { | ||
let scale = self.viewport.scale(); | ||
|
||
// Take inline layout to satisfy borrow checker | ||
let mut inline_layout = self.nodes[node_id] | ||
.raw_dom_data | ||
.downcast_element_mut() | ||
.unwrap() | ||
.take_inline_layout() | ||
.unwrap(); | ||
|
||
// TODO: eliminate clone | ||
let style = self.nodes[node_id].style.clone(); | ||
|
||
let output = compute_leaf_layout(inputs, &style, |_known_dimensions, available_space| { | ||
// Short circuit if inline context contains no text or inline boxes | ||
if inline_layout.text.is_empty() && inline_layout.layout.inline_boxes().is_empty() { | ||
return Size::ZERO; | ||
} | ||
|
||
// Compute size of inline boxes | ||
let child_inputs = taffy::tree::LayoutInput { | ||
known_dimensions: Size::NONE, | ||
available_space, | ||
parent_size: available_space.into_options(), | ||
..inputs | ||
}; | ||
for ibox in inline_layout.layout.inline_boxes_mut() { | ||
let style = &self.nodes[ibox.id as usize].style; | ||
let margin = style.margin.resolve_or_zero(inputs.parent_size); | ||
|
||
if style.position == Position::Absolute { | ||
ibox.width = 0.0; | ||
ibox.height = 0.0; | ||
} else { | ||
let output = self.compute_child_layout(NodeId::from(ibox.id), child_inputs); | ||
ibox.width = (margin.left + margin.right + output.size.width) * scale; | ||
ibox.height = (margin.top + margin.bottom + output.size.height) * scale; | ||
} | ||
} | ||
|
||
// Perform inline layout | ||
let max_advance = match available_space.width { | ||
AvailableSpace::Definite(px) => Some(px * scale), | ||
AvailableSpace::MinContent => Some(0.0), | ||
AvailableSpace::MaxContent => None, | ||
}; | ||
|
||
let alignment = self.nodes[node_id] | ||
.primary_styles() | ||
.map(|s| { | ||
use parley::layout::Alignment; | ||
use style::values::specified::TextAlignKeyword; | ||
|
||
match s.clone_text_align() { | ||
TextAlignKeyword::Start => Alignment::Start, | ||
TextAlignKeyword::Left => Alignment::Start, | ||
TextAlignKeyword::Right => Alignment::End, | ||
TextAlignKeyword::Center => Alignment::Middle, | ||
TextAlignKeyword::Justify => Alignment::Justified, | ||
TextAlignKeyword::End => Alignment::End, | ||
TextAlignKeyword::MozCenter => Alignment::Middle, | ||
TextAlignKeyword::MozLeft => Alignment::Start, | ||
TextAlignKeyword::MozRight => Alignment::End, | ||
} | ||
}) | ||
.unwrap_or(parley::layout::Alignment::Start); | ||
|
||
inline_layout.layout.break_all_lines(max_advance); | ||
|
||
let padding = style.padding.resolve_or_zero(inputs.parent_size); | ||
let border = style.border.resolve_or_zero(inputs.parent_size); | ||
|
||
let container_pb = padding + border; | ||
let pbw = container_pb.horizontal_components().sum() * scale; | ||
|
||
// Align layout | ||
let alignment_width = inputs | ||
.known_dimensions | ||
.width | ||
.map(|w| (w * scale) - pbw) | ||
.unwrap_or_else(|| { | ||
let computed_width = inline_layout.layout.width(); | ||
let style_width = style | ||
.size | ||
.width | ||
.maybe_resolve(inputs.parent_size.width) | ||
.map(|w| w * scale); | ||
let min_width = style | ||
.min_size | ||
.width | ||
.maybe_resolve(inputs.parent_size.width) | ||
.map(|w| w * scale); | ||
let max_width = style | ||
.max_size | ||
.width | ||
.maybe_resolve(inputs.parent_size.width) | ||
.map(|w| w * scale); | ||
|
||
(style_width) | ||
.unwrap_or(computed_width + pbw) | ||
.max(computed_width) | ||
.maybe_clamp(min_width, max_width) | ||
- pbw | ||
}); | ||
|
||
inline_layout.layout.align(Some(alignment_width), alignment); | ||
|
||
// Store sizes and positions of inline boxes | ||
for line in inline_layout.layout.lines() { | ||
for item in line.items() { | ||
if let parley::layout::PositionedLayoutItem::InlineBox(ibox) = item { | ||
let node = &mut self.nodes[ibox.id as usize]; | ||
let padding = node.style.padding.resolve_or_zero(child_inputs.parent_size); | ||
let border = node.style.border.resolve_or_zero(child_inputs.parent_size); | ||
let margin = node.style.margin.resolve_or_zero(child_inputs.parent_size); | ||
|
||
// Resolve inset | ||
let left = node | ||
.style | ||
.inset | ||
.left | ||
.maybe_resolve(child_inputs.parent_size.width); | ||
let right = node | ||
.style | ||
.inset | ||
.right | ||
.maybe_resolve(child_inputs.parent_size.width); | ||
let top = node | ||
.style | ||
.inset | ||
.top | ||
.maybe_resolve(child_inputs.parent_size.height); | ||
let bottom = node | ||
.style | ||
.inset | ||
.bottom | ||
.maybe_resolve(child_inputs.parent_size.height); | ||
|
||
if node.style.position == Position::Absolute { | ||
let output = | ||
self.compute_child_layout(NodeId::from(ibox.id), child_inputs); | ||
|
||
let layout = &mut self.nodes[ibox.id as usize].unrounded_layout; | ||
layout.size = output.size; | ||
|
||
// TODO: Implement absolute positioning | ||
layout.location.x = left | ||
.or_else(|| { | ||
child_inputs | ||
.parent_size | ||
.width | ||
.zip(right) | ||
.map(|(w, r)| w - r) | ||
}) | ||
.unwrap_or(0.0); | ||
layout.location.y = top | ||
.or_else(|| { | ||
child_inputs | ||
.parent_size | ||
.height | ||
.zip(bottom) | ||
.map(|(w, r)| w - r) | ||
}) | ||
.unwrap_or(0.0); | ||
|
||
layout.padding = padding; //.map(|p| p / scale); | ||
layout.border = border; //.map(|p| p / scale); | ||
} else { | ||
let layout = &mut node.unrounded_layout; | ||
layout.size.width = (ibox.width / scale) - margin.left - margin.right; | ||
layout.size.height = (ibox.height / scale) - margin.top - margin.bottom; | ||
layout.location.x = (ibox.x / scale) + margin.left + container_pb.left; | ||
layout.location.y = (ibox.y / scale) + margin.top + container_pb.top; | ||
layout.padding = padding; //.map(|p| p / scale); | ||
layout.border = border; //.map(|p| p / scale); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// println!("INLINE LAYOUT FOR {:?}. max_advance: {:?}", node_id, max_advance); | ||
// dbg!(&inline_layout.text); | ||
// println!("Computed: w: {} h: {}", inline_layout.layout.width(), inline_layout.layout.height()); | ||
// println!("known_dimensions: w: {:?} h: {:?}", inputs.known_dimensions.width, inputs.known_dimensions.height); | ||
// println!("\n"); | ||
|
||
inputs.known_dimensions.unwrap_or(taffy::Size { | ||
width: inline_layout.layout.width() / scale, | ||
height: inline_layout.layout.height() / scale, | ||
}) | ||
}); | ||
|
||
// Put layout back | ||
self.nodes[node_id] | ||
.raw_dom_data | ||
.downcast_element_mut() | ||
.unwrap() | ||
.inline_layout_data = Some(inline_layout); | ||
|
||
output | ||
} | ||
} |
Oops, something went wrong.