Remove base width
This commit is contained in:
parent
697ae1f925
commit
f4856c18b9
@ -83,16 +83,16 @@ impl Layout for ColumnsNode {
|
||||
) -> SourceResult<Fragment> {
|
||||
// Separating the infinite space into infinite columns does not make
|
||||
// much sense.
|
||||
if !regions.first.x.is_finite() {
|
||||
if !regions.size.x.is_finite() {
|
||||
return self.body.layout(vt, styles, regions);
|
||||
}
|
||||
|
||||
// Determine the width of the gutter and each column.
|
||||
let columns = self.count.get();
|
||||
let gutter = styles.get(Self::GUTTER).relative_to(regions.base.x);
|
||||
let width = (regions.first.x - gutter * (columns - 1) as f64) / columns as f64;
|
||||
let gutter = styles.get(Self::GUTTER).relative_to(regions.base().x);
|
||||
let width = (regions.size.x - gutter * (columns - 1) as f64) / columns as f64;
|
||||
|
||||
let backlog: Vec<_> = std::iter::once(®ions.first.y)
|
||||
let backlog: Vec<_> = std::iter::once(®ions.size.y)
|
||||
.chain(regions.backlog)
|
||||
.flat_map(|&height| std::iter::repeat(height).take(columns))
|
||||
.skip(1)
|
||||
@ -100,8 +100,8 @@ impl Layout for ColumnsNode {
|
||||
|
||||
// Create the pod regions.
|
||||
let pod = Regions {
|
||||
first: Size::new(width, regions.first.y),
|
||||
base: Size::new(width, regions.base.y),
|
||||
size: Size::new(width, regions.size.y),
|
||||
full: regions.full,
|
||||
backlog: &backlog,
|
||||
last: regions.last,
|
||||
expand: Axes::new(true, regions.expand.y),
|
||||
@ -121,7 +121,7 @@ impl Layout for ColumnsNode {
|
||||
// case, the frame is first created with zero height and then
|
||||
// resized.
|
||||
let height = if regions.expand.y { region.y } else { Abs::zero() };
|
||||
let mut output = Frame::new(Size::new(regions.first.x, height));
|
||||
let mut output = Frame::new(Size::new(regions.size.x, height));
|
||||
let mut cursor = Abs::zero();
|
||||
|
||||
for _ in 0..columns {
|
||||
@ -134,7 +134,7 @@ impl Layout for ColumnsNode {
|
||||
let x = if dir == Dir::LTR {
|
||||
cursor
|
||||
} else {
|
||||
regions.first.x - cursor - width
|
||||
regions.size.x - cursor - width
|
||||
};
|
||||
|
||||
output.push_frame(Point::with_x(x), frame);
|
||||
|
@ -77,24 +77,22 @@ impl Layout for BoxNode {
|
||||
let size = self
|
||||
.sizing
|
||||
.resolve(styles)
|
||||
.zip(regions.base)
|
||||
.zip(regions.base())
|
||||
.map(|(s, b)| s.map(|v| v.relative_to(b)))
|
||||
.unwrap_or(regions.first);
|
||||
.unwrap_or(regions.size);
|
||||
|
||||
// Select the appropriate base and expansion for the child depending
|
||||
// on whether it is automatically or relatively sized.
|
||||
let is_auto = self.sizing.as_ref().map(Option::is_none);
|
||||
let base = is_auto.select(regions.base, size);
|
||||
let expand = regions.expand | !is_auto;
|
||||
|
||||
Regions::one(size, base, expand)
|
||||
Regions::one(size, expand)
|
||||
};
|
||||
|
||||
// Layout the child.
|
||||
let mut frame = self.body.layout(vt, styles, pod)?.into_frame();
|
||||
|
||||
// Ensure frame size matches regions size if expansion is on.
|
||||
let target = regions.expand.select(regions.first, frame.size());
|
||||
let target = regions.expand.select(regions.size, frame.size());
|
||||
frame.resize(target, Align::LEFT_TOP);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
|
@ -85,7 +85,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
/// Create a new flow layouter.
|
||||
fn new(mut regions: Regions<'a>) -> Self {
|
||||
let expand = regions.expand;
|
||||
let full = regions.first;
|
||||
let full = regions.size;
|
||||
|
||||
// Disable vertical expansion for children.
|
||||
regions.expand.y = false;
|
||||
@ -122,14 +122,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
let leading = styles.get(ParNode::LEADING);
|
||||
let consecutive = self.last_was_par;
|
||||
let frames = par
|
||||
.layout(
|
||||
vt,
|
||||
styles,
|
||||
consecutive,
|
||||
self.regions.first.x,
|
||||
self.regions.base,
|
||||
self.regions.expand.x,
|
||||
)?
|
||||
.layout(vt, styles, consecutive, self.regions.base(), self.regions.expand.x)?
|
||||
.into_frames();
|
||||
|
||||
let mut sticky = self.items.len();
|
||||
@ -142,7 +135,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
if let [first, ..] = frames.as_slice() {
|
||||
if !self.regions.first.y.fits(first.height()) && !self.regions.in_last() {
|
||||
if !self.regions.size.y.fits(first.height()) && !self.regions.in_last() {
|
||||
let carry: Vec<_> = self.items.drain(sticky..).collect();
|
||||
self.finish_region();
|
||||
for item in carry {
|
||||
@ -199,15 +192,15 @@ impl<'a> FlowLayouter<'a> {
|
||||
/// Layout a finished frame.
|
||||
fn layout_item(&mut self, item: FlowItem) {
|
||||
match item {
|
||||
FlowItem::Absolute(v, _) => self.regions.first.y -= v,
|
||||
FlowItem::Absolute(v, _) => self.regions.size.y -= v,
|
||||
FlowItem::Fractional(_) => {}
|
||||
FlowItem::Frame(ref frame, ..) => {
|
||||
let size = frame.size();
|
||||
if !self.regions.first.y.fits(size.y) && !self.regions.in_last() {
|
||||
if !self.regions.size.y.fits(size.y) && !self.regions.in_last() {
|
||||
self.finish_region();
|
||||
}
|
||||
|
||||
self.regions.first.y -= size.y;
|
||||
self.regions.size.y -= size.y;
|
||||
}
|
||||
FlowItem::Placed(_) => {}
|
||||
}
|
||||
@ -284,7 +277,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
// Advance to the next region.
|
||||
self.finished.push(output);
|
||||
self.regions.next();
|
||||
self.full = self.regions.first;
|
||||
self.full = self.regions.size;
|
||||
}
|
||||
|
||||
/// Finish layouting and return the resulting fragment.
|
||||
|
@ -235,8 +235,6 @@ struct GridLayouter<'a, 'v> {
|
||||
rcols: Vec<Abs>,
|
||||
/// Rows in the current region.
|
||||
lrows: Vec<Row>,
|
||||
/// The full height of the current region.
|
||||
full: Abs,
|
||||
/// The used-up size of the current region. The horizontal size is
|
||||
/// determined once after columns are resolved and not touched again.
|
||||
used: Size,
|
||||
@ -317,7 +315,6 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
cols.reverse();
|
||||
}
|
||||
|
||||
let full = regions.first.y;
|
||||
let rcols = vec![Abs::zero(); cols.len()];
|
||||
let lrows = vec![];
|
||||
|
||||
@ -337,7 +334,6 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
styles,
|
||||
rcols,
|
||||
lrows,
|
||||
full,
|
||||
used: Size::zero(),
|
||||
fr: Fr::zero(),
|
||||
finished: vec![],
|
||||
@ -384,7 +380,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
TrackSizing::Auto => {}
|
||||
TrackSizing::Relative(v) => {
|
||||
let resolved =
|
||||
v.resolve(self.styles).relative_to(self.regions.base.x);
|
||||
v.resolve(self.styles).relative_to(self.regions.base().x);
|
||||
*rcol = resolved;
|
||||
rel += resolved;
|
||||
}
|
||||
@ -393,7 +389,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
}
|
||||
|
||||
// Size that is not used by fixed-size columns.
|
||||
let available = self.regions.first.x - rel;
|
||||
let available = self.regions.size.x - rel;
|
||||
if available >= Abs::zero() {
|
||||
// Determine size of auto columns.
|
||||
let (auto, count) = self.measure_auto_columns(available)?;
|
||||
@ -429,16 +425,17 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
let mut resolved = Abs::zero();
|
||||
for y in 0..self.rows.len() {
|
||||
if let Some(cell) = self.cell(x, y) {
|
||||
let size = Size::new(available, self.regions.base.y);
|
||||
let mut pod = Regions::one(size, size, Axes::splat(false));
|
||||
|
||||
// For relative rows, we can already resolve the correct
|
||||
// base and for auto and fr we could only guess anyway.
|
||||
if let TrackSizing::Relative(v) = self.rows[y] {
|
||||
pod.base.y =
|
||||
v.resolve(self.styles).relative_to(self.regions.base.y);
|
||||
}
|
||||
let height = match self.rows[y] {
|
||||
TrackSizing::Relative(v) => {
|
||||
v.resolve(self.styles).relative_to(self.regions.base().y)
|
||||
}
|
||||
_ => self.regions.base().y,
|
||||
};
|
||||
|
||||
let size = Size::new(available, height);
|
||||
let pod = Regions::one(size, Axes::splat(false));
|
||||
let frame = cell.layout(self.vt, self.styles, pod)?.into_frame();
|
||||
resolved.set_max(frame.width());
|
||||
}
|
||||
@ -508,8 +505,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
for (x, &rcol) in self.rcols.iter().enumerate() {
|
||||
if let Some(cell) = self.cell(x, y) {
|
||||
let mut pod = self.regions;
|
||||
pod.first.x = rcol;
|
||||
pod.base.x = rcol;
|
||||
pod.size.x = rcol;
|
||||
|
||||
let frames = cell.layout(self.vt, self.styles, pod)?.into_frames();
|
||||
if let [first, rest @ ..] = frames.as_slice() {
|
||||
@ -573,12 +569,12 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
/// Layout a row with relative height. Such a row cannot break across
|
||||
/// multiple regions, but it may force a region break.
|
||||
fn layout_relative_row(&mut self, v: Rel<Length>, y: usize) -> SourceResult<()> {
|
||||
let resolved = v.resolve(self.styles).relative_to(self.regions.base.y);
|
||||
let resolved = v.resolve(self.styles).relative_to(self.regions.base().y);
|
||||
let frame = self.layout_single_row(resolved, y)?;
|
||||
|
||||
// Skip to fitting region.
|
||||
let height = frame.height();
|
||||
while !self.regions.first.y.fits(height) && !self.regions.in_last() {
|
||||
while !self.regions.size.y.fits(height) && !self.regions.in_last() {
|
||||
self.finish_region()?;
|
||||
|
||||
// Don't skip multiple regions for gutter and don't push a row.
|
||||
@ -600,14 +596,10 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
for (x, &rcol) in self.rcols.iter().enumerate() {
|
||||
if let Some(cell) = self.cell(x, y) {
|
||||
let size = Size::new(rcol, height);
|
||||
let base = Size::new(
|
||||
rcol,
|
||||
match self.rows[y] {
|
||||
TrackSizing::Auto => self.regions.base.y,
|
||||
_ => height,
|
||||
},
|
||||
);
|
||||
let pod = Regions::one(size, base, Axes::splat(true));
|
||||
let mut pod = Regions::one(size, Axes::splat(true));
|
||||
if self.rows[y] == TrackSizing::Auto {
|
||||
pod.full = self.regions.full;
|
||||
}
|
||||
let frame = cell.layout(self.vt, self.styles, pod)?.into_frame();
|
||||
output.push_frame(pos, frame);
|
||||
}
|
||||
@ -628,15 +620,15 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
|
||||
// Prepare regions.
|
||||
let size = Size::new(self.used.x, heights[0]);
|
||||
let mut pod = Regions::one(size, self.regions.base, Axes::splat(true));
|
||||
let mut pod = Regions::one(size, Axes::splat(true));
|
||||
pod.full = self.regions.full;
|
||||
pod.backlog = &heights[1..];
|
||||
|
||||
// Layout the row.
|
||||
let mut pos = Point::zero();
|
||||
for (x, &rcol) in self.rcols.iter().enumerate() {
|
||||
if let Some(cell) = self.cell(x, y) {
|
||||
pod.first.x = rcol;
|
||||
pod.base.x = rcol;
|
||||
pod.size.x = rcol;
|
||||
|
||||
// Push the layouted frames into the individual output frames.
|
||||
let fragment = cell.layout(self.vt, self.styles, pod)?;
|
||||
@ -653,7 +645,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
|
||||
/// Push a row frame into the current region.
|
||||
fn push_row(&mut self, frame: Frame) {
|
||||
self.regions.first.y -= frame.height();
|
||||
self.regions.size.y -= frame.height();
|
||||
self.used.y += frame.height();
|
||||
self.lrows.push(Row::Frame(frame));
|
||||
}
|
||||
@ -663,8 +655,8 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
// Determine the size of the grid in this region, expanding fully if
|
||||
// there are fr rows.
|
||||
let mut size = self.used;
|
||||
if self.fr.get() > 0.0 && self.full.is_finite() {
|
||||
size.y = self.full;
|
||||
if self.fr.get() > 0.0 && self.regions.full.is_finite() {
|
||||
size.y = self.regions.full;
|
||||
}
|
||||
|
||||
// The frame for the region.
|
||||
@ -676,7 +668,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
let frame = match row {
|
||||
Row::Frame(frame) => frame,
|
||||
Row::Fr(v, y) => {
|
||||
let remaining = self.full - self.used.y;
|
||||
let remaining = self.regions.full - self.used.y;
|
||||
let height = v.share(self.fr, remaining);
|
||||
self.layout_single_row(height, y)?
|
||||
}
|
||||
@ -689,7 +681,6 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
|
||||
|
||||
self.finished.push(output);
|
||||
self.regions.next();
|
||||
self.full = self.regions.first.y;
|
||||
self.used.y = Abs::zero();
|
||||
self.fr = Fr::zero();
|
||||
|
||||
|
@ -293,7 +293,7 @@ impl PageNode {
|
||||
}
|
||||
|
||||
// Layout the child.
|
||||
let regions = Regions::repeat(size, size, size.map(Abs::is_finite));
|
||||
let regions = Regions::repeat(size, size.map(Abs::is_finite));
|
||||
let mut fragment = child.layout(vt, styles, regions)?;
|
||||
|
||||
let header = styles.get(Self::HEADER);
|
||||
@ -316,7 +316,7 @@ impl PageNode {
|
||||
let in_background = std::ptr::eq(marginal, background);
|
||||
let Some(marginal) = marginal else { continue };
|
||||
let content = marginal.resolve(vt, page)?;
|
||||
let pod = Regions::one(area, area, Axes::splat(true));
|
||||
let pod = Regions::one(area, Axes::splat(true));
|
||||
let sub = content.layout(vt, styles, pod)?.into_frame();
|
||||
if in_background {
|
||||
frame.prepend_frame(pos, sub);
|
||||
|
@ -120,8 +120,7 @@ impl ParNode {
|
||||
vt: &mut Vt,
|
||||
styles: StyleChain,
|
||||
consecutive: bool,
|
||||
width: Abs,
|
||||
base: Size,
|
||||
region: Size,
|
||||
expand: bool,
|
||||
) -> SourceResult<Fragment> {
|
||||
#[comemo::memoize]
|
||||
@ -132,8 +131,7 @@ impl ParNode {
|
||||
introspector: Tracked<Introspector>,
|
||||
styles: StyleChain,
|
||||
consecutive: bool,
|
||||
width: Abs,
|
||||
base: Size,
|
||||
region: Size,
|
||||
expand: bool,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut vt = Vt { world, provider, introspector };
|
||||
@ -144,13 +142,13 @@ impl ParNode {
|
||||
// Perform BiDi analysis and then prepare paragraph layout by building a
|
||||
// representation on which we can do line breaking without layouting
|
||||
// each and every line from scratch.
|
||||
let p = prepare(&mut vt, par, &text, segments, styles, width, base)?;
|
||||
let p = prepare(&mut vt, par, &text, segments, styles, region)?;
|
||||
|
||||
// Break the paragraph into lines.
|
||||
let lines = linebreak(&vt, &p, width);
|
||||
let lines = linebreak(&vt, &p, region.x);
|
||||
|
||||
// Stack the lines into one frame per region.
|
||||
finalize(&mut vt, &p, &lines, width, base, expand)
|
||||
finalize(&mut vt, &p, &lines, region, expand)
|
||||
}
|
||||
|
||||
cached(
|
||||
@ -160,8 +158,7 @@ impl ParNode {
|
||||
vt.introspector,
|
||||
styles,
|
||||
consecutive,
|
||||
width,
|
||||
base,
|
||||
region,
|
||||
expand,
|
||||
)
|
||||
}
|
||||
@ -595,8 +592,7 @@ fn prepare<'a>(
|
||||
text: &'a str,
|
||||
segments: Vec<(Segment<'a>, StyleChain<'a>)>,
|
||||
styles: StyleChain<'a>,
|
||||
width: Abs,
|
||||
base: Size,
|
||||
region: Size,
|
||||
) -> SourceResult<Preparation<'a>> {
|
||||
let bidi = BidiInfo::new(
|
||||
text,
|
||||
@ -619,7 +615,7 @@ fn prepare<'a>(
|
||||
}
|
||||
Segment::Spacing(spacing) => match spacing {
|
||||
Spacing::Relative(v) => {
|
||||
let resolved = v.resolve(styles).relative_to(base.x);
|
||||
let resolved = v.resolve(styles).relative_to(region.x);
|
||||
items.push(Item::Absolute(resolved));
|
||||
}
|
||||
Spacing::Fractional(v) => {
|
||||
@ -630,8 +626,7 @@ fn prepare<'a>(
|
||||
if let Some(repeat) = inline.to::<RepeatNode>() {
|
||||
items.push(Item::Repeat(repeat, styles));
|
||||
} else {
|
||||
let size = Size::new(width, base.y);
|
||||
let pod = Regions::one(size, base, Axes::splat(false));
|
||||
let pod = Regions::one(region, Axes::splat(false));
|
||||
let mut frame = inline.layout(vt, styles, pod)?.into_frame();
|
||||
frame.translate(Point::with_y(styles.get(TextNode::BASELINE)));
|
||||
items.push(Item::Frame(frame));
|
||||
@ -1116,20 +1111,20 @@ fn finalize(
|
||||
vt: &mut Vt,
|
||||
p: &Preparation,
|
||||
lines: &[Line],
|
||||
mut width: Abs,
|
||||
base: Size,
|
||||
mut region: Size,
|
||||
expand: bool,
|
||||
) -> SourceResult<Fragment> {
|
||||
// Determine the paragraph's width: Full width of the region if we
|
||||
// should expand or there's fractional spacing, fit-to-width otherwise.
|
||||
if !width.is_finite() || (!expand && lines.iter().all(|line| line.fr().is_zero())) {
|
||||
width = lines.iter().map(|line| line.width).max().unwrap_or_default();
|
||||
if !region.x.is_finite() || (!expand && lines.iter().all(|line| line.fr().is_zero()))
|
||||
{
|
||||
region.x = lines.iter().map(|line| line.width).max().unwrap_or_default();
|
||||
}
|
||||
|
||||
// Stack the lines into one frame per region.
|
||||
let mut frames: Vec<Frame> = lines
|
||||
.iter()
|
||||
.map(|line| commit(vt, p, line, base, width))
|
||||
.map(|line| commit(vt, p, line, region))
|
||||
.collect::<SourceResult<_>>()?;
|
||||
|
||||
// Prevent orphans.
|
||||
@ -1164,10 +1159,9 @@ fn commit(
|
||||
vt: &mut Vt,
|
||||
p: &Preparation,
|
||||
line: &Line,
|
||||
base: Size,
|
||||
width: Abs,
|
||||
region: Size,
|
||||
) -> SourceResult<Frame> {
|
||||
let mut remaining = width - line.width;
|
||||
let mut remaining = region.x - line.width;
|
||||
let mut offset = Abs::zero();
|
||||
|
||||
// Reorder the line from logical to visual order.
|
||||
@ -1242,8 +1236,8 @@ fn commit(
|
||||
Item::Repeat(repeat, styles) => {
|
||||
let before = offset;
|
||||
let fill = Fr::one().share(fr, remaining);
|
||||
let size = Size::new(fill, base.y);
|
||||
let pod = Regions::one(size, base, Axes::new(false, false));
|
||||
let size = Size::new(fill, region.y);
|
||||
let pod = Regions::one(size, Axes::new(false, false));
|
||||
let frame = repeat.layout(vt, *styles, pod)?.into_frame();
|
||||
let width = frame.width();
|
||||
let count = (fill / width).floor();
|
||||
@ -1268,7 +1262,7 @@ fn commit(
|
||||
remaining = Abs::zero();
|
||||
}
|
||||
|
||||
let size = Size::new(width, top + bottom);
|
||||
let size = Size::new(region.x, top + bottom);
|
||||
let mut output = Frame::new(size);
|
||||
output.set_baseline(top);
|
||||
|
||||
|
@ -92,16 +92,16 @@ impl Layout for PlaceNode {
|
||||
// The pod is the base area of the region because for absolute
|
||||
// placement we don't really care about the already used area.
|
||||
let pod = {
|
||||
let finite = regions.base.map(Abs::is_finite);
|
||||
let finite = regions.base().map(Abs::is_finite);
|
||||
let expand = finite & (regions.expand | out_of_flow);
|
||||
Regions::one(regions.base, regions.base, expand)
|
||||
Regions::one(regions.base(), expand)
|
||||
};
|
||||
|
||||
let mut frame = self.0.layout(vt, styles, pod)?.into_frame();
|
||||
|
||||
// If expansion is off, zero all sizes so that we don't take up any
|
||||
// space in our parent. Otherwise, respect the expand settings.
|
||||
let target = regions.expand.select(regions.first, Size::zero());
|
||||
let target = regions.expand.select(regions.size, Size::zero());
|
||||
frame.resize(target, Align::LEFT_TOP);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
|
@ -5,10 +5,10 @@ use typst::geom::{Abs, Axes, Size};
|
||||
/// A sequence of regions to layout into.
|
||||
#[derive(Copy, Clone, Hash)]
|
||||
pub struct Regions<'a> {
|
||||
/// The (remaining) size of the first region.
|
||||
pub first: Size,
|
||||
/// The base size for relative sizing.
|
||||
pub base: Size,
|
||||
/// The remaining size of the first region.
|
||||
pub size: Size,
|
||||
/// The full height of the region for relative sizing.
|
||||
pub full: Abs,
|
||||
/// The height of followup regions. The width is the same for all regions.
|
||||
pub backlog: &'a [Abs],
|
||||
/// The height of the final region that is repeated once the backlog is
|
||||
@ -19,12 +19,12 @@ pub struct Regions<'a> {
|
||||
pub expand: Axes<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Regions<'a> {
|
||||
impl Regions<'_> {
|
||||
/// Create a new region sequence with exactly one region.
|
||||
pub fn one(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
pub fn one(size: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
size,
|
||||
full: size.y,
|
||||
backlog: &[],
|
||||
last: None,
|
||||
expand,
|
||||
@ -32,16 +32,24 @@ impl<'a> Regions<'a> {
|
||||
}
|
||||
|
||||
/// Create a new sequence of same-size regions that repeats indefinitely.
|
||||
pub fn repeat(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
pub fn repeat(size: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
size,
|
||||
full: size.y,
|
||||
backlog: &[],
|
||||
last: Some(size.y),
|
||||
expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// The base size, which doesn't take into account that the regions is
|
||||
/// already partially used up.
|
||||
///
|
||||
/// This is also used for relative sizing.
|
||||
pub fn base(&self) -> Size {
|
||||
Size::new(self.size.x, self.full)
|
||||
}
|
||||
|
||||
/// Create new regions where all sizes are mapped with `f`.
|
||||
///
|
||||
/// Note that since all regions must have the same width, the width returned
|
||||
@ -50,12 +58,12 @@ impl<'a> Regions<'a> {
|
||||
where
|
||||
F: FnMut(Size) -> Size,
|
||||
{
|
||||
let x = self.first.x;
|
||||
let x = self.size.x;
|
||||
backlog.clear();
|
||||
backlog.extend(self.backlog.iter().map(|&y| f(Size::new(x, y)).y));
|
||||
Regions {
|
||||
first: f(self.first),
|
||||
base: f(self.base),
|
||||
size: f(self.size),
|
||||
full: f(Size::new(x, self.full)).y,
|
||||
backlog,
|
||||
last: self.last.map(|y| f(Size::new(x, y)).y),
|
||||
expand: self.expand,
|
||||
@ -64,14 +72,14 @@ impl<'a> Regions<'a> {
|
||||
|
||||
/// Whether the first region is full and a region break is called for.
|
||||
pub fn is_full(&self) -> bool {
|
||||
Abs::zero().fits(self.first.y) && !self.in_last()
|
||||
Abs::zero().fits(self.size.y) && !self.in_last()
|
||||
}
|
||||
|
||||
/// Whether the first region is the last usable region.
|
||||
///
|
||||
/// If this is true, calling `next()` will have no effect.
|
||||
pub fn in_last(&self) -> bool {
|
||||
self.backlog.is_empty() && self.last.map_or(true, |height| self.first.y == height)
|
||||
self.backlog.is_empty() && self.last.map_or(true, |height| self.size.y == height)
|
||||
}
|
||||
|
||||
/// Advance to the next region if there is any.
|
||||
@ -85,8 +93,8 @@ impl<'a> Regions<'a> {
|
||||
})
|
||||
.or(self.last)
|
||||
{
|
||||
self.first.y = height;
|
||||
self.base.y = height;
|
||||
self.size.y = height;
|
||||
self.full = height;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,10 +103,10 @@ impl<'a> Regions<'a> {
|
||||
/// [`next()`](Self::next) repeatedly until all regions are exhausted.
|
||||
/// This iterator may be infinite.
|
||||
pub fn iter(&self) -> impl Iterator<Item = Size> + '_ {
|
||||
let first = std::iter::once(self.first);
|
||||
let first = std::iter::once(self.size);
|
||||
let backlog = self.backlog.iter();
|
||||
let last = self.last.iter().cycle();
|
||||
first.chain(backlog.chain(last).map(|&h| Size::new(self.first.x, h)))
|
||||
first.chain(backlog.chain(last).map(|&h| Size::new(self.size.x, h)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,15 +114,15 @@ impl Debug for Regions<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Regions ")?;
|
||||
let mut list = f.debug_list();
|
||||
let mut prev = self.first.y;
|
||||
list.entry(&self.first);
|
||||
let mut prev = self.size.y;
|
||||
list.entry(&self.size);
|
||||
for &height in self.backlog {
|
||||
list.entry(&Size::new(self.first.x, height));
|
||||
list.entry(&Size::new(self.size.x, height));
|
||||
prev = height;
|
||||
}
|
||||
if let Some(last) = self.last {
|
||||
if last != prev {
|
||||
list.entry(&Size::new(self.first.x, last));
|
||||
list.entry(&Size::new(self.size.x, last));
|
||||
}
|
||||
list.entry(&(..));
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ impl<'a> StackLayouter<'a> {
|
||||
fn new(dir: Dir, regions: Regions<'a>, styles: StyleChain<'a>) -> Self {
|
||||
let axis = dir.axis();
|
||||
let expand = regions.expand;
|
||||
let full = regions.first;
|
||||
let full = regions.size;
|
||||
|
||||
// Disable expansion along the block axis for children.
|
||||
let mut regions = regions.clone();
|
||||
@ -202,11 +202,14 @@ impl<'a> StackLayouter<'a> {
|
||||
match spacing {
|
||||
Spacing::Relative(v) => {
|
||||
// Resolve the spacing and limit it to the remaining space.
|
||||
let resolved =
|
||||
v.resolve(self.styles).relative_to(self.regions.base.get(self.axis));
|
||||
let remaining = self.regions.first.get_mut(self.axis);
|
||||
let resolved = v
|
||||
.resolve(self.styles)
|
||||
.relative_to(self.regions.base().get(self.axis));
|
||||
let remaining = self.regions.size.get_mut(self.axis);
|
||||
let limited = resolved.min(*remaining);
|
||||
*remaining -= limited;
|
||||
if self.dir.axis() == Axis::Y {
|
||||
*remaining -= limited;
|
||||
}
|
||||
self.used.main += limited;
|
||||
self.items.push(StackItem::Absolute(resolved));
|
||||
}
|
||||
@ -242,14 +245,18 @@ impl<'a> StackLayouter<'a> {
|
||||
for (i, frame) in fragment.into_iter().enumerate() {
|
||||
// Grow our size, shrink the region and save the frame for later.
|
||||
let size = frame.size();
|
||||
let size = match self.axis {
|
||||
if self.dir.axis() == Axis::Y {
|
||||
self.regions.size.y -= size.y;
|
||||
}
|
||||
|
||||
let gen = match self.axis {
|
||||
Axis::X => Gen::new(size.y, size.x),
|
||||
Axis::Y => Gen::new(size.x, size.y),
|
||||
};
|
||||
|
||||
self.used.main += size.main;
|
||||
self.used.cross.set_max(size.cross);
|
||||
*self.regions.first.get_mut(self.axis) -= size.main;
|
||||
self.used.main += gen.main;
|
||||
self.used.cross.set_max(gen.cross);
|
||||
|
||||
self.items.push(StackItem::Frame(frame, align));
|
||||
|
||||
if i + 1 < len {
|
||||
@ -310,7 +317,7 @@ impl<'a> StackLayouter<'a> {
|
||||
|
||||
// Advance to the next region.
|
||||
self.regions.next();
|
||||
self.full = self.regions.first;
|
||||
self.full = self.regions.size;
|
||||
self.used = Gen::zero();
|
||||
self.fr = Fr::zero();
|
||||
self.finished.push(output);
|
||||
|
@ -78,7 +78,7 @@ impl Layout for MoveNode {
|
||||
let mut fragment = self.body.layout(vt, styles, regions)?;
|
||||
for frame in &mut fragment {
|
||||
let delta = self.delta.resolve(styles);
|
||||
let delta = delta.zip(regions.base).map(|(d, s)| d.relative_to(s));
|
||||
let delta = delta.zip(regions.base()).map(|(d, s)| d.relative_to(s));
|
||||
frame.translate(delta.to_point());
|
||||
}
|
||||
Ok(fragment)
|
||||
|
@ -25,7 +25,7 @@ macro_rules! percent {
|
||||
/// The context for math layout.
|
||||
pub struct MathContext<'a, 'b, 'v> {
|
||||
pub vt: &'v mut Vt<'b>,
|
||||
pub regions: Regions<'a>,
|
||||
pub regions: Regions<'static>,
|
||||
pub font: &'a Font,
|
||||
pub ttf: &'a ttf_parser::Face<'a>,
|
||||
pub table: ttf_parser::math::Table<'a>,
|
||||
@ -60,10 +60,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
|
||||
let variant = variant(styles);
|
||||
Self {
|
||||
vt,
|
||||
regions: {
|
||||
let size = Size::new(regions.first.x, regions.base.y);
|
||||
Regions::one(size, regions.base, Axes::splat(false))
|
||||
},
|
||||
regions: Regions::one(regions.base(), Axes::splat(false)),
|
||||
font: &font,
|
||||
ttf: font.ttf(),
|
||||
table,
|
||||
|
@ -76,7 +76,7 @@ impl Layout for ImageNode {
|
||||
let px_ratio = pxw / pxh;
|
||||
|
||||
// Find out whether the image is wider or taller than the target size.
|
||||
let Regions { first, expand, .. } = regions;
|
||||
let Regions { size: first, expand, .. } = regions;
|
||||
let region_ratio = first.x / first.y;
|
||||
let wide = px_ratio > region_ratio;
|
||||
|
||||
|
@ -87,17 +87,17 @@ impl Layout for LineNode {
|
||||
let origin = self
|
||||
.start
|
||||
.resolve(styles)
|
||||
.zip(regions.base)
|
||||
.zip(regions.base())
|
||||
.map(|(l, b)| l.relative_to(b));
|
||||
|
||||
let delta = self
|
||||
.delta
|
||||
.resolve(styles)
|
||||
.zip(regions.base)
|
||||
.zip(regions.base())
|
||||
.map(|(l, b)| l.relative_to(b));
|
||||
|
||||
let size = origin.max(origin + delta).max(Size::zero());
|
||||
let target = regions.expand.select(regions.first, size);
|
||||
let target = regions.expand.select(regions.size, size);
|
||||
|
||||
let mut frame = Frame::new(target);
|
||||
let shape = Geometry::Line(delta.to_point()).stroked(stroke);
|
||||
|
@ -555,41 +555,40 @@ fn layout(
|
||||
|
||||
// Pad the child.
|
||||
let child = child.clone().padded(inset.map(|side| side.map(Length::from)));
|
||||
|
||||
let pod = Regions::one(regions.first, regions.base, regions.expand);
|
||||
let pod = Regions::one(regions.size, regions.expand);
|
||||
frame = child.layout(vt, styles, pod)?.into_frame();
|
||||
|
||||
// Relayout with full expansion into square region to make sure
|
||||
// the result is really a square or circle.
|
||||
if kind.is_quadratic() {
|
||||
let length = if regions.expand.x || regions.expand.y {
|
||||
let target = regions.expand.select(regions.first, Size::zero());
|
||||
let target = regions.expand.select(regions.size, Size::zero());
|
||||
target.x.max(target.y)
|
||||
} else {
|
||||
let size = frame.size();
|
||||
let desired = size.x.max(size.y);
|
||||
desired.min(regions.first.x).min(regions.first.y)
|
||||
desired.min(regions.size.x).min(regions.size.y)
|
||||
};
|
||||
|
||||
let size = Size::splat(length);
|
||||
let pod = Regions::one(size, size, Axes::splat(true));
|
||||
let pod = Regions::one(size, Axes::splat(true));
|
||||
frame = child.layout(vt, styles, pod)?.into_frame();
|
||||
}
|
||||
} else {
|
||||
// The default size that a shape takes on if it has no child and
|
||||
// enough space.
|
||||
let mut size = Size::new(Abs::pt(45.0), Abs::pt(30.0)).min(regions.first);
|
||||
let mut size = Size::new(Abs::pt(45.0), Abs::pt(30.0)).min(regions.size);
|
||||
|
||||
if kind.is_quadratic() {
|
||||
let length = if regions.expand.x || regions.expand.y {
|
||||
let target = regions.expand.select(regions.first, Size::zero());
|
||||
let target = regions.expand.select(regions.size, Size::zero());
|
||||
target.x.max(target.y)
|
||||
} else {
|
||||
size.x.min(size.y)
|
||||
};
|
||||
size = Size::splat(length);
|
||||
} else {
|
||||
size = regions.expand.select(regions.first, size);
|
||||
size = regions.expand.select(regions.size, size);
|
||||
}
|
||||
|
||||
frame = Frame::new(size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user