Handle metadata application where styles are managed
This commit is contained in:
parent
fe56fb29fa
commit
50741209a8
crates/typst/src
introspection
layout
math
visualize
@ -58,6 +58,15 @@ pub fn define(global: &mut Scope) {
|
||||
pub struct MetaElem {
|
||||
/// Metadata that should be attached to all elements affected by this style
|
||||
/// property.
|
||||
///
|
||||
/// This must be accessed and applied to all frames produced by elements
|
||||
/// that manually handle styles (because their children can have varying
|
||||
/// styles). This currently includes flow, par, and equation.
|
||||
///
|
||||
/// Other elements don't manually need to handle it because their parents
|
||||
/// that result from realization will take care of it and the metadata can
|
||||
/// only apply to them as a whole, not part of it (because they don't manage
|
||||
/// styles).
|
||||
#[fold]
|
||||
pub data: SmallVec<[Meta; 1]>,
|
||||
}
|
||||
|
@ -172,7 +172,6 @@ impl Layout for Packed<BoxElem> {
|
||||
}
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(styles, false);
|
||||
frame.set_kind(FrameKind::Hard);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
@ -454,7 +453,6 @@ impl Layout for Packed<BlockElem> {
|
||||
// Apply metadata.
|
||||
for frame in &mut frames {
|
||||
frame.set_kind(FrameKind::Hard);
|
||||
frame.meta(styles, false);
|
||||
}
|
||||
|
||||
Ok(Fragment::frames(frames))
|
||||
|
@ -71,14 +71,7 @@ impl Layout for Packed<FlowElem> {
|
||||
let layoutable = child.with::<dyn Layout>().unwrap();
|
||||
layouter.layout_single(engine, layoutable, styles)?;
|
||||
} else if child.is::<MetaElem>() {
|
||||
let mut frame = Frame::soft(Size::zero());
|
||||
frame.meta(styles, true);
|
||||
layouter.items.push(FlowItem::Frame {
|
||||
frame,
|
||||
align: Axes::splat(FixedAlignment::Start),
|
||||
sticky: true,
|
||||
movable: false,
|
||||
});
|
||||
layouter.layout_meta(styles);
|
||||
} else if let Some(placed) = child.to_packed::<PlaceElem>() {
|
||||
layouter.layout_placed(engine, placed, styles)?;
|
||||
} else if child.can::<dyn Layout>() {
|
||||
@ -297,7 +290,8 @@ impl<'a> FlowLayouter<'a> {
|
||||
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 frame = content.layout(engine, styles, pod)?.into_frame();
|
||||
let mut frame = content.layout(engine, styles, pod)?.into_frame();
|
||||
frame.meta(styles, false);
|
||||
self.layout_item(
|
||||
engine,
|
||||
FlowItem::Frame { frame, align, sticky, movable: true },
|
||||
@ -306,6 +300,18 @@ 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,
|
||||
@ -321,7 +327,8 @@ impl<'a> FlowLayouter<'a> {
|
||||
align.x().unwrap_or_default().resolve(styles)
|
||||
});
|
||||
let y_align = alignment.map(|align| align.y().map(VAlignment::fix));
|
||||
let frame = placed.layout(engine, styles, self.regions)?.into_frame();
|
||||
let mut frame = placed.layout(engine, styles, self.regions)?.into_frame();
|
||||
frame.meta(styles, false);
|
||||
let item = FlowItem::Placed { frame, x_align, y_align, delta, float, clearance };
|
||||
self.layout_item(engine, item)
|
||||
}
|
||||
@ -361,7 +368,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
let sticky = BlockElem::sticky_in(styles);
|
||||
let fragment = block.layout(engine, styles, self.regions)?;
|
||||
|
||||
for (i, frame) in fragment.into_iter().enumerate() {
|
||||
for (i, mut frame) in fragment.into_iter().enumerate() {
|
||||
// Find footnotes in the frame.
|
||||
if self.root {
|
||||
find_footnotes(&mut notes, &frame);
|
||||
@ -371,8 +378,11 @@ impl<'a> FlowLayouter<'a> {
|
||||
self.finish_region(engine, false)?;
|
||||
}
|
||||
|
||||
let item = FlowItem::Frame { frame, align, sticky, movable: false };
|
||||
self.layout_item(engine, item)?;
|
||||
frame.meta(styles, false);
|
||||
self.layout_item(
|
||||
engine,
|
||||
FlowItem::Frame { frame, align, sticky, movable: false },
|
||||
)?;
|
||||
}
|
||||
|
||||
self.try_handle_footnotes(engine, notes)?;
|
||||
|
@ -289,20 +289,32 @@ impl Frame {
|
||||
/// Attach metadata from an iterator.
|
||||
pub fn meta_iter(&mut self, iter: impl IntoIterator<Item = Meta>) {
|
||||
let mut hide = false;
|
||||
for meta in iter {
|
||||
let size = self.size;
|
||||
self.prepend_multiple(iter.into_iter().filter_map(|meta| {
|
||||
if matches!(meta, Meta::Hide) {
|
||||
hide = true;
|
||||
None
|
||||
} else {
|
||||
self.prepend(Point::zero(), FrameItem::Meta(meta, self.size));
|
||||
Some((Point::zero(), FrameItem::Meta(meta, size)))
|
||||
}
|
||||
}
|
||||
}));
|
||||
if hide {
|
||||
Arc::make_mut(&mut self.items).retain(|(_, item)| {
|
||||
matches!(item, FrameItem::Group(_) | FrameItem::Meta(Meta::Elem(_), _))
|
||||
});
|
||||
self.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/// Hide all content in the frame, but keep metadata.
|
||||
pub fn hide(&mut self) {
|
||||
Arc::make_mut(&mut self.items).retain_mut(|(_, item)| match item {
|
||||
FrameItem::Group(group) => {
|
||||
group.frame.hide();
|
||||
!group.frame.is_empty()
|
||||
}
|
||||
FrameItem::Meta(Meta::Elem(_), _) => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
/// Add a background fill.
|
||||
pub fn fill(&mut self, fill: Paint) {
|
||||
self.prepend(
|
||||
|
@ -570,13 +570,8 @@ impl<'a> GridLayouter<'a> {
|
||||
}
|
||||
|
||||
self.finish_region(engine)?;
|
||||
|
||||
self.render_fills_strokes()?;
|
||||
|
||||
for frame in &mut self.finished {
|
||||
frame.meta(self.styles, false);
|
||||
}
|
||||
|
||||
Ok(Fragment::frames(self.finished))
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,11 @@ fn collect<'a>(
|
||||
Segment::Text(full.len() - prev)
|
||||
} else if let Some(elem) = child.to_packed::<EquationElem>() {
|
||||
let pod = Regions::one(region, Axes::splat(false));
|
||||
let items = elem.layout_inline(engine, styles, pod)?;
|
||||
let mut items = elem.layout_inline(engine, styles, pod)?;
|
||||
for item in &mut items {
|
||||
let MathParItem::Frame(frame) = item else { continue };
|
||||
frame.meta(styles, false);
|
||||
}
|
||||
full.extend(items.iter().map(MathParItem::text));
|
||||
Segment::Equation(elem, items)
|
||||
} else if let Some(elem) = child.to_packed::<BoxElem>() {
|
||||
@ -591,6 +595,7 @@ fn prepare<'a>(
|
||||
} else {
|
||||
let pod = Regions::one(region, Axes::splat(false));
|
||||
let mut frame = elem.layout(engine, styles, pod)?.into_frame();
|
||||
frame.meta(styles, false);
|
||||
frame.translate(Point::with_y(TextElem::baseline_in(styles)));
|
||||
items.push(Item::Frame(frame));
|
||||
}
|
||||
@ -1315,6 +1320,7 @@ fn commit(
|
||||
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();
|
||||
frame.meta(*styles, false);
|
||||
frame.translate(Point::with_y(TextElem::baseline_in(*styles)));
|
||||
push(&mut offset, frame);
|
||||
} else {
|
||||
@ -1322,8 +1328,9 @@ fn commit(
|
||||
}
|
||||
}
|
||||
Item::Text(shaped) => {
|
||||
let frame =
|
||||
let mut frame =
|
||||
shaped.build(engine, justification_ratio, extra_justification);
|
||||
frame.meta(shaped.styles, false);
|
||||
push(&mut offset, frame);
|
||||
}
|
||||
Item::Frame(frame) | Item::Meta(frame) => {
|
||||
|
@ -322,9 +322,6 @@ impl<'a> ShapedText<'a> {
|
||||
offset += width;
|
||||
}
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(self.styles, false);
|
||||
|
||||
frame
|
||||
}
|
||||
|
||||
|
@ -188,9 +188,6 @@ impl Packed<EquationElem> {
|
||||
let descent = bottom_edge.max(frame.descent() - slack);
|
||||
frame.translate(Point::with_y(ascent - frame.baseline()));
|
||||
frame.size_mut().y = ascent + descent;
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(styles, false);
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
@ -251,9 +248,6 @@ impl Layout for Packed<EquationElem> {
|
||||
frame.push_frame(Point::new(x, y), counter)
|
||||
}
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(styles, false);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
}
|
||||
}
|
||||
|
@ -236,13 +236,9 @@ impl Layout for Packed<ImageElem> {
|
||||
|
||||
// Create a clipping group if only part of the image should be visible.
|
||||
if fit == ImageFit::Cover && !target.fits(fitted) {
|
||||
frame.meta(styles, false);
|
||||
frame.clip(Path::rect(frame.size()));
|
||||
}
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(styles, false);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +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()));
|
||||
frame.meta(styles, false);
|
||||
Ok(Fragment::frame(frame))
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
frame.meta(styles, false);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
}
|
||||
|
@ -523,9 +523,6 @@ fn layout(
|
||||
}
|
||||
}
|
||||
|
||||
// Apply metadata.
|
||||
frame.meta(styles, false);
|
||||
|
||||
Ok(Fragment::frame(frame))
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user