Cleaner separation between single and multi-region layout

This commit is contained in:
Laurenz 2024-01-18 11:47:45 +01:00
parent 6ac71eeaf7
commit fae358968f
30 changed files with 191 additions and 206 deletions

View File

@ -4,7 +4,8 @@ use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{elem, Behave, Behaviour, Content, Packed, StyleChain};
use crate::layout::{
Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size,
Abs, Axes, Dir, Fragment, Frame, LayoutMultiple, Length, Point, Ratio, Regions, Rel,
Size,
};
use crate::text::TextElem;
use crate::util::Numeric;
@ -40,7 +41,7 @@ use crate::util::Numeric;
/// increasingly been used to solve a
/// variety of problems.
/// ```
#[elem(Layout)]
#[elem(LayoutMultiple)]
pub struct ColumnsElem {
/// The number of columns.
#[positional]
@ -57,7 +58,7 @@ pub struct ColumnsElem {
pub body: Content,
}
impl Layout for Packed<ColumnsElem> {
impl LayoutMultiple for Packed<ColumnsElem> {
#[typst_macros::time(name = "columns", span = self.span())]
fn layout(
&self,

View File

@ -4,8 +4,8 @@ use crate::foundations::{
cast, elem, AutoValue, Content, Packed, Resolve, Smart, StyleChain, Value,
};
use crate::layout::{
Abs, Axes, Corners, Em, Fr, Fragment, FrameKind, Layout, Length, Ratio, Regions, Rel,
Sides, Size, Spacing, VElem,
Abs, Axes, Corners, Em, Fr, Fragment, Frame, FrameKind, LayoutMultiple, Length,
Ratio, Regions, Rel, Sides, Size, Spacing, VElem,
};
use crate::util::Numeric;
use crate::visualize::{clip_rect, Paint, Stroke};
@ -26,7 +26,7 @@ use crate::visualize::{clip_rect, Paint, Stroke};
/// )
/// for more information.
/// ```
#[elem(Layout)]
#[elem]
pub struct BoxElem {
/// The width of the box.
///
@ -109,14 +109,14 @@ pub struct BoxElem {
pub body: Option<Content>,
}
impl Layout for Packed<BoxElem> {
impl Packed<BoxElem> {
#[typst_macros::time(name = "box", span = self.span())]
fn layout(
pub fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let width = match self.width(styles) {
Sizing::Auto => Smart::Auto,
Sizing::Rel(rel) => Smart::Custom(rel),
@ -174,7 +174,7 @@ impl Layout for Packed<BoxElem> {
// Apply metadata.
frame.set_kind(FrameKind::Hard);
Ok(Fragment::frame(frame))
Ok(frame)
}
}
@ -207,7 +207,7 @@ impl Layout for Packed<BoxElem> {
/// = Blocky
/// More text.
/// ```
#[elem(Layout)]
#[elem(LayoutMultiple)]
pub struct BlockElem {
/// The block's width.
///
@ -340,7 +340,7 @@ pub struct BlockElem {
pub sticky: bool,
}
impl Layout for Packed<BlockElem> {
impl LayoutMultiple for Packed<BlockElem> {
#[typst_macros::time(name = "block", span = self.span())]
fn layout(
&self,

View File

@ -10,28 +10,24 @@ use crate::foundations::{
use crate::introspection::{Meta, MetaElem};
use crate::layout::{
Abs, AlignElem, Axes, BlockElem, ColbreakElem, ColumnsElem, FixedAlignment, Fr,
Fragment, Frame, FrameItem, Layout, PlaceElem, Point, Regions, Rel, Size, Spacing,
VAlignment, VElem,
Fragment, Frame, FrameItem, LayoutMultiple, LayoutSingle, PlaceElem, Point, Regions,
Rel, Size, Spacing, VAlignment, VElem,
};
use crate::model::{FootnoteElem, FootnoteEntry, ParElem};
use crate::util::Numeric;
use crate::visualize::{
CircleElem, EllipseElem, ImageElem, LineElem, PathElem, PolygonElem, RectElem,
SquareElem,
};
/// Arranges spacing, paragraphs and block-level elements into a flow.
///
/// This element is responsible for layouting both the top-level content flow
/// and the contents of boxes.
#[elem(Debug, Layout)]
#[elem(Debug, LayoutMultiple)]
pub struct FlowElem {
/// The children that will be arranges into a flow.
#[variadic]
pub children: Vec<Prehashed<Content>>,
}
impl Layout for Packed<FlowElem> {
impl LayoutMultiple for Packed<FlowElem> {
#[typst_macros::time(name = "flow", span = self.span())]
fn layout(
&self,
@ -45,8 +41,8 @@ impl Layout for Packed<FlowElem> {
if !regions.size.y.is_finite() && regions.expand.y {
bail!(self.span(), "cannot expand into infinite height");
}
let mut layouter = FlowLayouter::new(regions, styles);
let mut layouter = FlowLayouter::new(regions, styles);
for mut child in self.children().iter().map(|c| &**c) {
let outer = styles;
let mut styles = styles;
@ -55,32 +51,23 @@ impl Layout for Packed<FlowElem> {
styles = outer.chain(map);
}
if let Some(elem) = child.to_packed::<VElem>() {
layouter.layout_spacing(engine, elem, styles)?;
} else if let Some(elem) = child.to_packed::<ParElem>() {
layouter.layout_par(engine, elem, styles)?;
} else if child.is::<LineElem>()
|| child.is::<RectElem>()
|| child.is::<SquareElem>()
|| child.is::<EllipseElem>()
|| child.is::<CircleElem>()
|| child.is::<ImageElem>()
|| child.is::<PolygonElem>()
|| child.is::<PathElem>()
{
let layoutable = child.with::<dyn Layout>().unwrap();
layouter.layout_single(engine, layoutable, styles)?;
} else if child.is::<MetaElem>() {
if child.is::<MetaElem>() {
layouter.layout_meta(styles);
} else if let Some(elem) = child.to_packed::<VElem>() {
layouter.layout_spacing(engine, elem, styles)?;
} else if let Some(placed) = child.to_packed::<PlaceElem>() {
layouter.layout_placed(engine, placed, styles)?;
} else if child.can::<dyn Layout>() {
layouter.layout_multiple(engine, child, styles)?;
} else if child.is::<ColbreakElem>() {
if !layouter.regions.backlog.is_empty() || layouter.regions.last.is_some()
{
layouter.finish_region(engine, true)?;
}
} else if let Some(elem) = child.to_packed::<ParElem>() {
layouter.layout_par(engine, elem, styles)?;
} else if let Some(layoutable) = child.with::<dyn LayoutSingle>() {
layouter.layout_single(engine, layoutable, styles)?;
} else if child.can::<dyn LayoutMultiple>() {
layouter.layout_multiple(engine, child, styles)?;
} else {
bail!(child.span(), "unexpected flow child");
}
@ -207,6 +194,18 @@ impl<'a> FlowLayouter<'a> {
}
}
/// Place explicit metadata into the flow.
fn layout_meta(&mut self, styles: StyleChain) {
let mut frame = Frame::soft(Size::zero());
frame.meta(styles, true);
self.items.push(FlowItem::Frame {
frame,
align: Axes::splat(FixedAlignment::Start),
sticky: true,
movable: false,
});
}
/// Layout vertical spacing.
fn layout_spacing(
&mut self,
@ -284,13 +283,13 @@ impl<'a> FlowLayouter<'a> {
fn layout_single(
&mut self,
engine: &mut Engine,
content: &dyn Layout,
layoutable: &dyn LayoutSingle,
styles: StyleChain,
) -> SourceResult<()> {
let align = AlignElem::alignment_in(styles).resolve(styles);
let sticky = BlockElem::sticky_in(styles);
let pod = Regions::one(self.regions.base(), Axes::splat(false));
let mut frame = content.layout(engine, styles, pod)?.into_frame();
let mut frame = layoutable.layout(engine, styles, pod)?;
frame.meta(styles, false);
self.layout_item(
engine,
@ -300,18 +299,6 @@ impl<'a> FlowLayouter<'a> {
Ok(())
}
/// Place explicit metadata into the flow.
fn layout_meta(&mut self, styles: StyleChain) {
let mut frame = Frame::soft(Size::zero());
frame.meta(styles, true);
self.items.push(FlowItem::Frame {
frame,
align: Axes::splat(FixedAlignment::Start),
sticky: true,
movable: false,
});
}
/// Layout a placed element.
fn layout_placed(
&mut self,
@ -337,12 +324,12 @@ impl<'a> FlowLayouter<'a> {
fn layout_multiple(
&mut self,
engine: &mut Engine,
block: &Content,
child: &Content,
styles: StyleChain,
) -> SourceResult<()> {
// Temporarily delegerate rootness to the columns.
let is_root = self.root;
if is_root && block.is::<ColumnsElem>() {
if is_root && child.is::<ColumnsElem>() {
self.root = false;
self.regions.root = true;
}
@ -355,9 +342,9 @@ impl<'a> FlowLayouter<'a> {
}
// How to align the block.
let align = if let Some(align) = block.to_packed::<AlignElem>() {
let align = if let Some(align) = child.to_packed::<AlignElem>() {
align.alignment(styles)
} else if let Some((_, local)) = block.to_styled() {
} else if let Some((_, local)) = child.to_styled() {
AlignElem::alignment_in(styles.chain(local))
} else {
AlignElem::alignment_in(styles)
@ -366,7 +353,7 @@ impl<'a> FlowLayouter<'a> {
// Layout the block itself.
let sticky = BlockElem::sticky_in(styles);
let fragment = block.layout(engine, styles, self.regions)?;
let fragment = child.layout(engine, styles, self.regions)?;
for (i, mut frame) in fragment.into_iter().enumerate() {
// Find footnotes in the frame.

View File

@ -9,8 +9,8 @@ use crate::foundations::{
StyleChain, Value,
};
use crate::layout::{
Abs, Alignment, Axes, Dir, Fr, Fragment, Frame, FrameItem, Layout, Length, Point,
Regions, Rel, Sides, Size, Sizing,
Abs, Alignment, Axes, Dir, Fr, Fragment, Frame, FrameItem, LayoutMultiple, Length,
Point, Regions, Rel, Sides, Size, Sizing,
};
use crate::syntax::Span;
use crate::text::TextElem;
@ -102,7 +102,7 @@ impl From<Content> for Cell {
}
}
impl Layout for Cell {
impl LayoutMultiple for Cell {
fn layout(
&self,
engine: &mut Engine,

View File

@ -13,8 +13,8 @@ use crate::foundations::{
cast, elem, scope, Array, Content, Fold, Packed, Show, Smart, StyleChain, Value,
};
use crate::layout::{
Abs, AlignElem, Alignment, Axes, Fragment, Layout, Length, Regions, Rel, Sides,
Sizing,
Abs, AlignElem, Alignment, Axes, Fragment, LayoutMultiple, Length, Regions, Rel,
Sides, Sizing,
};
use crate::syntax::Span;
use crate::visualize::{Paint, Stroke};
@ -154,7 +154,7 @@ use crate::visualize::{Paint, Stroke};
/// grid.cell(y: 2, fill: aqua)[Walk],
/// )
/// ```
#[elem(scope, Layout)]
#[elem(scope, LayoutMultiple)]
pub struct GridElem {
/// The column sizes.
///
@ -279,7 +279,7 @@ impl GridElem {
type GridCell;
}
impl Layout for Packed<GridElem> {
impl LayoutMultiple for Packed<GridElem> {
#[typst_macros::time(name = "grid", span = self.span())]
fn layout(
&self,

View File

@ -17,7 +17,7 @@ use crate::foundations::{Content, Packed, Resolve, Smart, StyleChain};
use crate::introspection::{Introspector, Locator, MetaElem};
use crate::layout::{
Abs, AlignElem, Axes, BoxElem, Dir, Em, FixedAlignment, Fr, Fragment, Frame, HElem,
Layout, Point, Regions, Size, Sizing, Spacing,
Point, Regions, Size, Sizing, Spacing,
};
use crate::math::{EquationElem, MathParItem};
use crate::model::{Linebreaks, ParElem};
@ -594,7 +594,7 @@ fn prepare<'a>(
items.push(Item::Fractional(v, Some((elem, styles))));
} else {
let pod = Regions::one(region, Axes::splat(false));
let mut frame = elem.layout(engine, styles, pod)?.into_frame();
let mut frame = elem.layout(engine, styles, pod)?;
frame.meta(styles, false);
frame.translate(Point::with_y(TextElem::baseline_in(styles)));
items.push(Item::Frame(frame));
@ -1319,7 +1319,7 @@ fn commit(
if let Some((elem, styles)) = elem {
let region = Size::new(amount, full);
let pod = Regions::one(region, Axes::new(true, false));
let mut frame = elem.layout(engine, *styles, pod)?.into_frame();
let mut frame = elem.layout(engine, *styles, pod)?;
frame.meta(*styles, false);
frame.translate(Point::with_y(TextElem::baseline_in(*styles)));
push(&mut offset, frame);

View File

@ -3,7 +3,7 @@ use crate::engine::Engine;
use crate::foundations::{
dict, elem, func, Content, Func, NativeElement, Packed, StyleChain,
};
use crate::layout::{Fragment, Layout, Regions, Size};
use crate::layout::{Fragment, LayoutMultiple, Regions, Size};
use crate::syntax::Span;
/// Provides access to the current outer container's (or page's, if none) size
@ -63,14 +63,14 @@ pub fn layout(
}
/// Executes a `layout` call.
#[elem(Layout)]
#[elem(LayoutMultiple)]
struct LayoutElem {
/// The function to call with the outer container's (or page's) size.
#[required]
func: Func,
}
impl Layout for Packed<LayoutElem> {
impl LayoutMultiple for Packed<LayoutElem> {
#[typst_macros::time(name = "layout", span = self.span())]
fn layout(
&self,

View File

@ -1,7 +1,7 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{dict, func, Content, Dict, StyleChain, Styles};
use crate::layout::{Abs, Axes, Layout, Regions, Size};
use crate::layout::{Abs, Axes, LayoutMultiple, Regions, Size};
/// Measures the layouted size of content.
///

View File

@ -120,7 +120,7 @@ pub fn define(global: &mut Scope) {
/// Root-level layout.
pub trait LayoutRoot {
/// Layout into one frame per page.
/// Layout into a document with one frame per page.
fn layout_root(
&self,
engine: &mut Engine,
@ -128,8 +128,8 @@ pub trait LayoutRoot {
) -> SourceResult<Document>;
}
/// Layout into regions.
pub trait Layout {
/// Layout into multiple regions.
pub trait LayoutMultiple {
/// Layout into one frame per region.
fn layout(
&self,
@ -160,8 +160,18 @@ pub trait Layout {
}
}
/// Layout into a single region.
pub trait LayoutSingle {
/// Layout into one frame per region.
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Frame>;
}
impl LayoutRoot for Content {
#[typst_macros::time(name = "layout root", span = self.span())]
fn layout_root(
&self,
engine: &mut Engine,
@ -186,12 +196,9 @@ impl LayoutRoot for Content {
tracer,
};
let scratch = Scratch::default();
let (realized, styles) =
let (document, styles) =
realize_root(&mut engine, &scratch, content, styles)?;
realized
.with::<dyn LayoutRoot>()
.unwrap()
.layout_root(&mut engine, styles)
document.layout_root(&mut engine, styles)
}
cached(
@ -206,7 +213,7 @@ impl LayoutRoot for Content {
}
}
impl Layout for Content {
impl LayoutMultiple for Content {
fn layout(
&self,
engine: &mut Engine,
@ -244,10 +251,11 @@ impl Layout for Content {
let scratch = Scratch::default();
let (realized, styles) =
realize_block(&mut engine, &scratch, content, styles)?;
realized
.with::<dyn Layout>()
.unwrap()
.layout(&mut engine, styles, regions)
realized.with::<dyn LayoutMultiple>().unwrap().layout(
&mut engine,
styles,
regions,
)
}
let fragment = cached(

View File

@ -1,7 +1,9 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size};
use crate::layout::{
Abs, Fragment, LayoutMultiple, Length, Point, Regions, Rel, Sides, Size,
};
/// Adds spacing around content.
///
@ -16,7 +18,7 @@ use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, S
/// _Typing speeds can be
/// measured in words per minute._
/// ```
#[elem(title = "Padding", Layout)]
#[elem(title = "Padding", LayoutMultiple)]
pub struct PadElem {
/// The padding at the left side.
#[parse(
@ -58,7 +60,7 @@ pub struct PadElem {
pub body: Content,
}
impl Layout for Packed<PadElem> {
impl LayoutMultiple for Packed<PadElem> {
#[typst_macros::time(name = "pad", span = self.span())]
fn layout(
&self,

View File

@ -11,8 +11,8 @@ use crate::foundations::{
};
use crate::introspection::{Counter, CounterKey, ManualPageCounter};
use crate::layout::{
Abs, AlignElem, Alignment, Axes, ColumnsElem, Dir, Frame, HAlignment, Layout, Length,
Point, Ratio, Regions, Rel, Sides, Size, VAlignment,
Abs, AlignElem, Alignment, Axes, ColumnsElem, Dir, Frame, HAlignment, LayoutMultiple,
Length, Point, Ratio, Regions, Rel, Sides, Size, VAlignment,
};
use crate::model::Numbering;

View File

@ -2,7 +2,7 @@ use crate::diag::{bail, At, Hint, SourceResult};
use crate::engine::Engine;
use crate::foundations::{elem, Behave, Behaviour, Content, Packed, Smart, StyleChain};
use crate::layout::{
Alignment, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlignment,
Alignment, Axes, Em, Fragment, LayoutMultiple, Length, Regions, Rel, VAlignment,
};
/// Places content at an absolute position.
@ -25,7 +25,7 @@ use crate::layout::{
/// ),
/// )
/// ```
#[elem(Layout, Behave)]
#[elem(Behave)]
pub struct PlaceElem {
/// Relative to which position in the parent container to place the content.
///
@ -86,9 +86,9 @@ pub struct PlaceElem {
pub body: Content,
}
impl Layout for Packed<PlaceElem> {
impl Packed<PlaceElem> {
#[typst_macros::time(name = "place", span = self.span())]
fn layout(
pub fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,

View File

@ -2,7 +2,7 @@ use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size,
Abs, AlignElem, Axes, Fragment, Frame, LayoutMultiple, Point, Regions, Size,
};
use crate::util::Numeric;
@ -27,14 +27,14 @@ use crate::util::Numeric;
/// Berlin, the 22nd of December, 2022
/// ]
/// ```
#[elem(Layout)]
#[elem(LayoutMultiple)]
pub struct RepeatElem {
/// The content to repeat.
#[required]
pub body: Content,
}
impl Layout for Packed<RepeatElem> {
impl LayoutMultiple for Packed<RepeatElem> {
#[typst_macros::time(name = "repeat", span = self.span())]
fn layout(
&self,

View File

@ -4,8 +4,8 @@ use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{cast, elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, AlignElem, Axes, Axis, Dir, FixedAlignment, Fr, Fragment, Frame, Layout, Point,
Regions, Size, Spacing,
Abs, AlignElem, Axes, Axis, Dir, FixedAlignment, Fr, Fragment, Frame, LayoutMultiple,
Point, Regions, Size, Spacing,
};
use crate::util::{Get, Numeric};
@ -23,7 +23,7 @@ use crate::util::{Get, Numeric};
/// rect(width: 90pt),
/// )
/// ```
#[elem(Layout)]
#[elem(LayoutMultiple)]
pub struct StackElem {
/// The direction along which the items are stacked. Possible values are:
///
@ -51,7 +51,7 @@ pub struct StackElem {
pub children: Vec<StackChild>,
}
impl Layout for Packed<StackElem> {
impl LayoutMultiple for Packed<StackElem> {
#[typst_macros::time(name = "stack", span = self.span())]
fn layout(
&self,

View File

@ -2,8 +2,8 @@ use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, Alignment, Angle, Axes, FixedAlignment, Fragment, Frame, HAlignment, Layout,
Length, Point, Ratio, Regions, Rel, Size, VAlignment,
Abs, Alignment, Angle, Axes, FixedAlignment, Frame, HAlignment, LayoutMultiple,
LayoutSingle, Length, Point, Ratio, Regions, Rel, Size, VAlignment,
};
/// Moves content without affecting layout.
@ -24,7 +24,7 @@ use crate::layout::{
/// )
/// ))
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct MoveElem {
/// The horizontal displacement of the content.
pub dx: Rel<Length>,
@ -37,20 +37,20 @@ pub struct MoveElem {
pub body: Content,
}
impl Layout for Packed<MoveElem> {
impl LayoutSingle for Packed<MoveElem> {
#[typst_macros::time(name = "move", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let pod = Regions::one(regions.base(), Axes::splat(false));
let mut frame = self.body().layout(engine, styles, pod)?.into_frame();
let delta = Axes::new(self.dx(styles), self.dy(styles)).resolve(styles);
let delta = delta.zip_map(regions.base(), Rel::relative_to);
frame.translate(delta.to_point());
Ok(Fragment::frame(frame))
Ok(frame)
}
}
@ -68,7 +68,7 @@ impl Layout for Packed<MoveElem> {
/// .map(i => rotate(24deg * i)[X]),
/// )
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct RotateElem {
/// The amount of rotation.
///
@ -115,14 +115,14 @@ pub struct RotateElem {
pub body: Content,
}
impl Layout for Packed<RotateElem> {
impl LayoutSingle for Packed<RotateElem> {
#[typst_macros::time(name = "rotate", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let angle = self.angle(styles);
let align = self.origin(styles).resolve(styles);
@ -157,7 +157,7 @@ impl Layout for Packed<RotateElem> {
/// #scale(x: -100%)[This is mirrored.]
/// #scale(x: -100%, reflow: true)[This is mirrored.]
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct ScaleElem {
/// The horizontal scaling factor.
///
@ -203,14 +203,14 @@ pub struct ScaleElem {
pub body: Content,
}
impl Layout for Packed<ScaleElem> {
impl LayoutSingle for Packed<ScaleElem> {
#[typst_macros::time(name = "scale", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let sx = self.x(styles);
let sy = self.y(styles);
let align = self.origin(styles).resolve(styles);
@ -370,7 +370,7 @@ fn measure_and_layout(
transform: Transform,
align: Axes<FixedAlignment>,
reflow: bool,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
if !reflow {
// Layout the body.
let pod = Regions::one(base_size, Axes::splat(false));
@ -383,7 +383,7 @@ fn measure_and_layout(
.pre_concat(Transform::translate(-x, -y));
frame.transform(ts);
return Ok(Fragment::frame(frame));
return Ok(frame);
}
// Measure the size of the body.
@ -405,7 +405,7 @@ fn measure_and_layout(
frame.transform(ts);
frame.translate(offset);
frame.set_size(size);
Ok(Fragment::frame(frame))
Ok(frame)
}
/// Computes the bounding box and offset of a transformed frame.

View File

@ -13,7 +13,7 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{Content, Packed, Smart, StyleChain, Styles};
use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size};
use crate::layout::{Abs, Axes, BoxElem, Em, Frame, LayoutMultiple, Regions, Size};
use crate::math::{
FrameFragment, GlyphFragment, LayoutMath, MathFragment, MathRow, MathSize, MathStyle,
MathVariant, THICK,
@ -174,9 +174,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
}
pub fn layout_box(&mut self, boxed: &Packed<BoxElem>) -> SourceResult<Frame> {
Ok(boxed
.layout(self.engine, self.outer.chain(&self.local), self.regions)?
.into_frame())
boxed.layout(self.engine, self.outer.chain(&self.local), self.regions)
}
pub fn layout_content(&mut self, content: &Content) -> SourceResult<Frame> {

View File

@ -8,8 +8,8 @@ use crate::foundations::{
};
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
use crate::layout::{
Abs, AlignElem, Alignment, Axes, Dir, Em, FixedAlignment, Fragment, Frame, Layout,
Point, Regions, Size,
Abs, AlignElem, Alignment, Axes, Dir, Em, FixedAlignment, Frame, LayoutMultiple,
LayoutSingle, Point, Regions, Size,
};
use crate::math::{LayoutMath, MathContext};
use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement};
@ -45,7 +45,15 @@ use crate::World;
/// horizontally. For more details about math syntax, see the
/// [main math page]($category/math).
#[elem(
Locatable, Synthesize, Show, Finalize, Layout, LayoutMath, Count, LocalName, Refable,
Locatable,
Synthesize,
Show,
Finalize,
LayoutSingle,
LayoutMath,
Count,
LocalName,
Refable,
Outlinable
)]
pub struct EquationElem {
@ -194,14 +202,14 @@ impl Packed<EquationElem> {
}
}
impl Layout for Packed<EquationElem> {
impl LayoutSingle for Packed<EquationElem> {
#[typst_macros::time(name = "math.equation", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
const NUMBER_GUTTER: Em = Em::new(0.5);
assert!(self.block(styles));
@ -248,7 +256,7 @@ impl Layout for Packed<EquationElem> {
frame.push_frame(Point::new(x, y), counter)
}
Ok(Fragment::frame(frame))
Ok(frame)
}
}

View File

@ -67,7 +67,6 @@ impl Construct for DocumentElem {
}
impl LayoutRoot for Packed<DocumentElem> {
/// Layout the document into a sequence of frames, one per page.
#[typst_macros::time(name = "document", span = self.span())]
fn layout_root(
&self,

View File

@ -7,7 +7,7 @@ use crate::foundations::{
};
use crate::layout::{
Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment,
Layout, Length, Regions, Sizing, Spacing, VAlignment,
LayoutMultiple, Length, Regions, Sizing, Spacing, VAlignment,
};
use crate::model::{Numbering, NumberingPattern, ParElem};
use crate::text::TextElem;
@ -68,7 +68,7 @@ use crate::text::TextElem;
/// Enumeration items can contain multiple paragraphs and other block-level
/// content. All content that is indented more than an item's marker becomes
/// part of that item.
#[elem(scope, title = "Numbered List", Layout)]
#[elem(scope, title = "Numbered List", LayoutMultiple)]
pub struct EnumElem {
/// If this is `{false}`, the items are spaced apart with
/// [enum spacing]($enum.spacing). If it is `{true}`, they use normal
@ -208,7 +208,7 @@ impl EnumElem {
type EnumItem;
}
impl Layout for Packed<EnumElem> {
impl LayoutMultiple for Packed<EnumElem> {
#[typst_macros::time(name = "enum", span = self.span())]
fn layout(
&self,

View File

@ -4,8 +4,8 @@ use crate::foundations::{
cast, elem, scope, Array, Content, Fold, Func, Packed, Smart, StyleChain, Value,
};
use crate::layout::{
Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, Layout,
Length, Regions, Sizing, Spacing, VAlignment,
Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment,
LayoutMultiple, Length, Regions, Sizing, Spacing, VAlignment,
};
use crate::model::ParElem;
use crate::text::TextElem;
@ -41,7 +41,7 @@ use crate::text::TextElem;
/// followed by a space to create a list item. A list item can contain multiple
/// paragraphs and other block-level content. All content that is indented
/// more than an item's marker becomes part of that item.
#[elem(scope, title = "Bullet List", Layout)]
#[elem(scope, title = "Bullet List", LayoutMultiple)]
pub struct ListElem {
/// If this is `{false}`, the items are spaced apart with
/// [list spacing]($list.spacing). If it is `{true}`, they use normal
@ -133,7 +133,7 @@ impl ListElem {
type ListItem;
}
impl Layout for Packed<ListElem> {
impl LayoutMultiple for Packed<ListElem> {
#[typst_macros::time(name = "list", span = self.span())]
fn layout(
&self,

View File

@ -7,7 +7,7 @@ use crate::foundations::{
};
use crate::layout::{
show_grid_cell, Abs, Alignment, Axes, Cell, CellGrid, Celled, Fragment, GridLayouter,
Layout, Length, Regions, Rel, ResolvableCell, Sides, TrackSizings,
LayoutMultiple, Length, Regions, Rel, ResolvableCell, Sides, TrackSizings,
};
use crate::model::Figurable;
use crate::syntax::Span;
@ -86,7 +86,7 @@ use crate::visualize::{Paint, Stroke};
/// ..(table.cell(y: 4, fill: aqua)[B],) * 2,
/// )
/// ```
#[elem(scope, Layout, LocalName, Figurable)]
#[elem(scope, LayoutMultiple, LocalName, Figurable)]
pub struct TableElem {
/// The column sizes. See the [grid documentation]($grid) for more
/// information on track sizing.
@ -205,7 +205,7 @@ impl TableElem {
type TableCell;
}
impl Layout for Packed<TableElem> {
impl LayoutMultiple for Packed<TableElem> {
#[typst_macros::time(name = "table", span = self.span())]
fn layout(
&self,
@ -240,7 +240,6 @@ impl Layout for Packed<TableElem> {
.trace(engine.world, tracepoint, self.span())?;
let layouter = GridLayouter::new(&grid, &stroke, regions, styles, self.span());
layouter.layout(engine)
}
}

View File

@ -4,7 +4,7 @@ use crate::foundations::{
cast, elem, scope, Array, Content, NativeElement, Packed, Smart, StyleChain,
};
use crate::layout::{
BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem,
BlockElem, Em, Fragment, HElem, LayoutMultiple, Length, Regions, Spacing, VElem,
};
use crate::model::ParElem;
use crate::util::Numeric;
@ -25,7 +25,7 @@ use crate::util::Numeric;
/// # Syntax
/// This function also has dedicated syntax: Starting a line with a slash,
/// followed by a term, a colon and a description creates a term list item.
#[elem(scope, title = "Term List", Layout)]
#[elem(scope, title = "Term List", LayoutMultiple)]
pub struct TermsElem {
/// If this is `{false}`, the items are spaced apart with
/// [term list spacing]($terms.spacing). If it is `{true}`, they use normal
@ -107,7 +107,7 @@ impl TermsElem {
type TermItem;
}
impl Layout for Packed<TermsElem> {
impl LayoutMultiple for Packed<TermsElem> {
#[typst_macros::time(name = "terms", span = self.span())]
fn layout(
&self,

View File

@ -18,8 +18,8 @@ use crate::foundations::{
};
use crate::introspection::{Locatable, Meta, MetaElem};
use crate::layout::{
AlignElem, BlockElem, BoxElem, ColbreakElem, FlowElem, HElem, Layout, LayoutRoot,
PageElem, PagebreakElem, Parity, PlaceElem, VElem,
AlignElem, BlockElem, BoxElem, ColbreakElem, FlowElem, HElem, LayoutMultiple,
LayoutSingle, PageElem, PagebreakElem, Parity, PlaceElem, VElem,
};
use crate::math::{EquationElem, LayoutMath};
use crate::model::{
@ -29,10 +29,6 @@ use crate::model::{
use crate::syntax::Span;
use crate::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem};
use crate::util::hash128;
use crate::visualize::{
CircleElem, EllipseElem, ImageElem, LineElem, PathElem, PolygonElem, RectElem,
SquareElem,
};
/// Realize into an element that is capable of root-level layout.
#[typst_macros::time(name = "realize root")]
@ -41,17 +37,13 @@ pub fn realize_root<'a>(
scratch: &'a Scratch<'a>,
content: &'a Content,
styles: StyleChain<'a>,
) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> {
if content.can::<dyn LayoutRoot>() && !applicable(content, styles) {
return Ok((Cow::Borrowed(content), styles));
}
) -> SourceResult<(Packed<DocumentElem>, StyleChain<'a>)> {
let mut builder = Builder::new(engine, scratch, true);
builder.accept(content, styles)?;
builder.interrupt_page(Some(styles), true)?;
let (pages, shared) = builder.doc.unwrap().pages.finish();
let span = first_span(&pages);
Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack().spanned(span)), shared))
Ok((Packed::new(DocumentElem::new(pages.to_vec())).spanned(span), shared))
}
/// Realize into an element that is capable of block-level layout.
@ -64,19 +56,7 @@ pub fn realize_block<'a>(
) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> {
// These elements implement `Layout` but still require a flow for
// proper layout.
if content.can::<dyn Layout>()
&& !content.is::<BoxElem>()
&& !content.is::<LineElem>()
&& !content.is::<RectElem>()
&& !content.is::<SquareElem>()
&& !content.is::<EllipseElem>()
&& !content.is::<CircleElem>()
&& !content.is::<ImageElem>()
&& !content.is::<PolygonElem>()
&& !content.is::<PathElem>()
&& !content.is::<PlaceElem>()
&& !applicable(content, styles)
{
if content.can::<dyn LayoutMultiple>() && !applicable(content, styles) {
return Ok((Cow::Borrowed(content), styles));
}
@ -560,7 +540,10 @@ impl<'a> FlowBuilder<'a> {
return true;
}
if content.can::<dyn Layout>() || content.is::<ParElem>() {
if content.can::<dyn LayoutSingle>()
|| content.can::<dyn LayoutMultiple>()
|| content.is::<ParElem>()
{
let is_tight_list = if let Some(elem) = content.to_packed::<ListElem>() {
elem.tight(styles)
} else if let Some(elem) = content.to_packed::<EnumElem>() {

View File

@ -20,8 +20,8 @@ use crate::foundations::{
StyleChain,
};
use crate::layout::{
Abs, Axes, FixedAlignment, Fragment, Frame, FrameItem, Layout, Length, Point,
Regions, Rel, Size,
Abs, Axes, FixedAlignment, Frame, FrameItem, LayoutSingle, Length, Point, Regions,
Rel, Size,
};
use crate::loading::Readable;
use crate::model::Figurable;
@ -51,7 +51,7 @@ use crate::World;
/// ```
///
/// [gh-svg]: https://github.com/typst/typst/issues?q=is%3Aopen+is%3Aissue+label%3Asvg
#[elem(scope, Layout, LocalName, Figurable)]
#[elem(scope, LayoutSingle, LocalName, Figurable)]
pub struct ImageElem {
/// Path to an image file.
#[required]
@ -144,14 +144,14 @@ impl ImageElem {
}
}
impl Layout for Packed<ImageElem> {
impl LayoutSingle for Packed<ImageElem> {
#[typst_macros::time(name = "image", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
// Take the format that was explicitly defined, or parse the extension,
// or try to detect the format.
let data = self.data();
@ -239,7 +239,7 @@ impl Layout for Packed<ImageElem> {
frame.clip(Path::rect(frame.size()));
}
Ok(Fragment::frame(frame))
Ok(frame)
}
}

View File

@ -2,7 +2,7 @@ use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{elem, Packed, StyleChain};
use crate::layout::{
Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size,
Abs, Angle, Axes, Frame, FrameItem, LayoutSingle, Length, Regions, Rel, Size,
};
use crate::util::Numeric;
use crate::visualize::{Geometry, Stroke};
@ -20,7 +20,7 @@ use crate::visualize::{Geometry, Stroke};
/// stroke: 2pt + maroon,
/// )
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct LineElem {
/// The start point of the line.
///
@ -58,14 +58,14 @@ pub struct LineElem {
pub stroke: Stroke,
}
impl Layout for Packed<LineElem> {
impl LayoutSingle for Packed<LineElem> {
#[typst_macros::time(name = "line", span = self.span())]
fn layout(
&self,
_: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let resolve =
|axes: Axes<Rel<Abs>>| axes.zip_map(regions.base(), Rel::relative_to);
let start = resolve(self.start(styles));
@ -89,6 +89,6 @@ impl Layout for Packed<LineElem> {
let mut frame = Frame::soft(target);
let shape = Geometry::Line(delta.to_point()).stroked(stroke);
frame.push(start.to_point(), FrameItem::Shape(shape, self.span()));
Ok(Fragment::frame(frame))
Ok(frame)
}
}

View File

@ -6,7 +6,8 @@ use crate::foundations::{
array, cast, elem, Array, Packed, Reflect, Resolve, Smart, StyleChain,
};
use crate::layout::{
Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size,
Abs, Axes, Fragment, Frame, FrameItem, LayoutMultiple, Length, Point, Regions, Rel,
Size,
};
use crate::visualize::{FixedStroke, Geometry, Paint, Shape, Stroke};
@ -25,7 +26,7 @@ use PathVertex::{AllControlPoints, MirroredControlPoint, Vertex};
/// ((50%, 0pt), (40pt, 0pt)),
/// )
/// ```
#[elem(Layout)]
#[elem(LayoutMultiple)]
pub struct PathElem {
/// How to fill the path.
///
@ -70,7 +71,7 @@ pub struct PathElem {
pub vertices: Vec<PathVertex>,
}
impl Layout for Packed<PathElem> {
impl LayoutMultiple for Packed<PathElem> {
#[typst_macros::time(name = "path", span = self.span())]
fn layout(
&self,

View File

@ -7,7 +7,7 @@ use ecow::{eco_format, EcoString};
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{func, repr, scope, ty, Content, Smart, StyleChain};
use crate::layout::{Abs, Axes, Frame, Layout, Length, Regions, Size};
use crate::layout::{Abs, Axes, Frame, LayoutMultiple, Length, Regions, Size};
use crate::syntax::{Span, Spanned};
use crate::util::Numeric;
use crate::visualize::RelativeTo;

View File

@ -6,7 +6,7 @@ use crate::foundations::{
elem, func, scope, Content, NativeElement, Packed, Resolve, Smart, StyleChain,
};
use crate::layout::{
Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel,
Axes, Em, Frame, FrameItem, LayoutSingle, Length, Point, Regions, Rel,
};
use crate::syntax::Span;
use crate::util::Numeric;
@ -27,7 +27,7 @@ use crate::visualize::{FixedStroke, Geometry, Paint, Path, Shape, Stroke};
/// (0%, 2cm),
/// )
/// ```
#[elem(scope, Layout)]
#[elem(scope, LayoutSingle)]
pub struct PolygonElem {
/// How to fill the polygon.
///
@ -125,14 +125,14 @@ impl PolygonElem {
}
}
impl Layout for Packed<PolygonElem> {
impl LayoutSingle for Packed<PolygonElem> {
#[typst_macros::time(name = "polygon", span = self.span())]
fn layout(
&self,
_: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let points: Vec<Point> = self
.vertices()
.iter()
@ -150,7 +150,7 @@ impl Layout for Packed<PolygonElem> {
// Only create a path if there are more than zero points.
if points.is_empty() {
return Ok(Fragment::frame(frame));
return Ok(frame);
}
// Prepare fill and stroke.
@ -171,7 +171,6 @@ impl Layout for Packed<PolygonElem> {
let shape = Shape { geometry: Geometry::Path(path), stroke, fill };
frame.push(Point::zero(), FrameItem::Shape(shape, self.span()));
Ok(Fragment::frame(frame))
Ok(frame)
}
}

View File

@ -4,8 +4,8 @@ use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{elem, Content, Packed, Resolve, Smart, StyleChain};
use crate::layout::{
Abs, Axes, Corner, Corners, Fragment, Frame, FrameItem, Layout, Length, Point, Ratio,
Regions, Rel, Sides, Size,
Abs, Axes, Corner, Corners, Frame, FrameItem, LayoutMultiple, LayoutSingle, Length,
Point, Ratio, Regions, Rel, Sides, Size,
};
use crate::syntax::Span;
use crate::util::Get;
@ -24,7 +24,7 @@ use crate::visualize::{FixedStroke, Paint, Path, Stroke};
/// to fit the content.
/// ]
/// ```
#[elem(title = "Rectangle", Layout)]
#[elem(title = "Rectangle", LayoutSingle)]
pub struct RectElem {
/// The rectangle's width, relative to its parent container.
pub width: Smart<Rel<Length>>,
@ -131,14 +131,14 @@ pub struct RectElem {
pub body: Option<Content>,
}
impl Layout for Packed<RectElem> {
impl LayoutSingle for Packed<RectElem> {
#[typst_macros::time(name = "rect", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
layout(
engine,
styles,
@ -169,7 +169,7 @@ impl Layout for Packed<RectElem> {
/// sized to fit.
/// ]
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct SquareElem {
/// The square's side length. This is mutually exclusive with `width` and
/// `height`.
@ -237,14 +237,14 @@ pub struct SquareElem {
pub body: Option<Content>,
}
impl Layout for Packed<SquareElem> {
impl LayoutSingle for Packed<SquareElem> {
#[typst_macros::time(name = "square", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
layout(
engine,
styles,
@ -276,7 +276,7 @@ impl Layout for Packed<SquareElem> {
/// to fit the content.
/// ]
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct EllipseElem {
/// The ellipse's width, relative to its parent container.
pub width: Smart<Rel<Length>>,
@ -315,14 +315,14 @@ pub struct EllipseElem {
pub body: Option<Content>,
}
impl Layout for Packed<EllipseElem> {
impl LayoutSingle for Packed<EllipseElem> {
#[typst_macros::time(name = "ellipse", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
layout(
engine,
styles,
@ -354,7 +354,7 @@ impl Layout for Packed<EllipseElem> {
/// sized to fit.
/// ]
/// ```
#[elem(Layout)]
#[elem(LayoutSingle)]
pub struct CircleElem {
/// The circle's radius. This is mutually exclusive with `width` and
/// `height`.
@ -418,14 +418,14 @@ pub struct CircleElem {
pub body: Option<Content>,
}
impl Layout for Packed<CircleElem> {
impl LayoutSingle for Packed<CircleElem> {
#[typst_macros::time(name = "circle", span = self.span())]
fn layout(
&self,
engine: &mut Engine,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
layout(
engine,
styles,
@ -458,7 +458,7 @@ fn layout(
outset: Sides<Rel<Abs>>,
radius: Corners<Rel<Abs>>,
span: Span,
) -> SourceResult<Fragment> {
) -> SourceResult<Frame> {
let resolved = sizing
.zip_map(regions.base(), |s, r| s.map(|v| v.resolve(styles).relative_to(r)));
@ -523,7 +523,7 @@ fn layout(
}
}
Ok(Fragment::frame(frame))
Ok(frame)
}
/// A category of shape.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 58 KiB