Move Arc into Frame

This commit is contained in:
Laurenz 2022-06-12 17:45:52 +02:00
parent 6e3b1a2c80
commit 7660978ee5
25 changed files with 156 additions and 235 deletions

View File

@ -4,7 +4,6 @@ use std::cmp::Eq;
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::Hash; use std::hash::Hash;
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba}; use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba};
use pdf_writer::types::{ use pdf_writer::types::{
@ -34,7 +33,7 @@ use crate::Context;
/// included in the PDF. /// included in the PDF.
/// ///
/// Returns the raw bytes making up the PDF file. /// Returns the raw bytes making up the PDF file.
pub fn pdf(ctx: &Context, frames: &[Arc<Frame>]) -> Vec<u8> { pub fn pdf(ctx: &Context, frames: &[Frame]) -> Vec<u8> {
PdfExporter::new(ctx).export(frames) PdfExporter::new(ctx).export(frames)
} }
@ -84,7 +83,7 @@ impl<'a> PdfExporter<'a> {
} }
} }
fn export(mut self, frames: &[Arc<Frame>]) -> Vec<u8> { fn export(mut self, frames: &[Frame]) -> Vec<u8> {
self.build_pages(frames); self.build_pages(frames);
self.write_fonts(); self.write_fonts();
self.write_images(); self.write_images();
@ -100,7 +99,7 @@ impl<'a> PdfExporter<'a> {
self.writer.finish() self.writer.finish()
} }
fn build_pages(&mut self, frames: &[Arc<Frame>]) { fn build_pages(&mut self, frames: &[Frame]) {
for frame in frames { for frame in frames {
let page_id = self.alloc.bump(); let page_id = self.alloc.bump();
self.page_refs.push(page_id); self.page_refs.push(page_id);

View File

@ -11,7 +11,7 @@ use crate::geom::{
}; };
use crate::image::ImageId; use crate::image::ImageId;
use crate::library::text::Lang; use crate::library::text::Lang;
use crate::util::{EcoString, MaybeShared}; use crate::util::EcoString;
/// A finished layout with elements at fixed positions. /// A finished layout with elements at fixed positions.
#[derive(Default, Clone, Eq, PartialEq)] #[derive(Default, Clone, Eq, PartialEq)]
@ -24,7 +24,7 @@ pub struct Frame {
/// The semantic role of the frame. /// The semantic role of the frame.
role: Option<Role>, role: Option<Role>,
/// The elements composing this layout. /// The elements composing this layout.
elements: Vec<(Point, Element)>, elements: Arc<Vec<(Point, Element)>>,
} }
/// Accessors and setters. /// Accessors and setters.
@ -39,7 +39,7 @@ impl Frame {
size, size,
baseline: None, baseline: None,
role: None, role: None,
elements: vec![], elements: Arc::new(vec![]),
} }
} }
@ -92,7 +92,7 @@ impl Frame {
/// Recover the text inside of the frame and its children. /// Recover the text inside of the frame and its children.
pub fn text(&self) -> EcoString { pub fn text(&self) -> EcoString {
let mut text = EcoString::new(); let mut text = EcoString::new();
for (_, element) in &self.elements { for (_, element) in self.elements() {
match element { match element {
Element::Text(content) => { Element::Text(content) => {
for glyph in &content.glyphs { for glyph in &content.glyphs {
@ -117,7 +117,19 @@ impl Frame {
/// Add an element at a position in the foreground. /// Add an element at a position in the foreground.
pub fn push(&mut self, pos: Point, element: Element) { pub fn push(&mut self, pos: Point, element: Element) {
self.elements.push((pos, element)); Arc::make_mut(&mut self.elements).push((pos, element));
}
/// Add a frame.
///
/// Automatically decides whether to inline the frame or to include it as a
/// group based on the number of elements in the frame.
pub fn push_frame(&mut self, pos: Point, frame: Frame) {
if self.should_inline(&frame) {
self.inline(self.layer(), pos, frame);
} else {
self.push(pos, Element::Group(Group::new(frame)));
}
} }
/// Insert an element at the given layer in the frame. /// Insert an element at the given layer in the frame.
@ -125,51 +137,72 @@ impl Frame {
/// This panics if the layer is greater than the number of layers present. /// This panics if the layer is greater than the number of layers present.
#[track_caller] #[track_caller]
pub fn insert(&mut self, layer: usize, pos: Point, element: Element) { pub fn insert(&mut self, layer: usize, pos: Point, element: Element) {
self.elements.insert(layer, (pos, element)); Arc::make_mut(&mut self.elements).insert(layer, (pos, element));
}
/// Add a frame.
///
/// Automatically decides whether to inline the frame or to include it as a
/// group based on the number of elements in the frame.
pub fn push_frame(&mut self, pos: Point, frame: impl FrameRepr) {
if (self.elements.is_empty() || frame.as_ref().is_light())
&& frame.as_ref().role().map_or(true, Role::is_weak)
{
frame.inline(self, self.layer(), pos);
} else {
self.elements.push((pos, Element::Group(Group::new(frame.share()))));
}
} }
/// Add an element at a position in the background. /// Add an element at a position in the background.
pub fn prepend(&mut self, pos: Point, element: Element) { pub fn prepend(&mut self, pos: Point, element: Element) {
self.elements.insert(0, (pos, element)); Arc::make_mut(&mut self.elements).insert(0, (pos, element));
} }
/// Add multiple elements at a position in the background. /// Add multiple elements at a position in the background.
pub fn prepend_multiple<I>(&mut self, insert: I) pub fn prepend_multiple<I>(&mut self, elements: I)
where where
I: IntoIterator<Item = (Point, Element)>, I: IntoIterator<Item = (Point, Element)>,
{ {
self.elements.splice(0 .. 0, insert); Arc::make_mut(&mut self.elements).splice(0 .. 0, elements);
} }
/// Add a frame at a position in the background. /// Add a frame at a position in the background.
pub fn prepend_frame(&mut self, pos: Point, frame: impl FrameRepr) { pub fn prepend_frame(&mut self, pos: Point, frame: Frame) {
if (self.elements.is_empty() || frame.as_ref().is_light()) if self.should_inline(&frame) {
&& frame.as_ref().role().map_or(true, Role::is_weak) self.inline(0, pos, frame);
{
frame.inline(self, 0, pos);
} else { } else {
self.elements self.prepend(pos, Element::Group(Group::new(frame)));
.insert(0, (pos, Element::Group(Group::new(frame.share()))));
} }
} }
/// Whether the frame has comparatively few elements. /// Whether the given frame should be inlined.
fn is_light(&self) -> bool { pub fn should_inline(&self, frame: &Frame) -> bool {
self.elements.len() <= 5 (self.elements.is_empty() || frame.elements.len() <= 5)
&& frame.role().map_or(true, |role| role.is_weak())
}
/// Inline a frame at the given layer.
pub fn inline(&mut self, layer: usize, pos: Point, frame: Frame) {
// Try to just reuse the elements.
if pos.is_zero() && self.elements.is_empty() {
self.elements = frame.elements;
return;
}
// Try to copy the elements without adjusting the positioned.
// Also try to reuse the elements if the Arc isn't shared.
let range = layer .. layer;
if pos.is_zero() {
let sink = Arc::make_mut(&mut self.elements);
match Arc::try_unwrap(frame.elements) {
Ok(elements) => {
sink.splice(range, elements);
}
Err(arc) => {
sink.splice(range, arc.iter().cloned());
}
}
return;
}
// We must adjust the element positioned.
// But still try to reuse the elements if the Arc isn't shared.
let sink = Arc::make_mut(&mut self.elements);
match Arc::try_unwrap(frame.elements) {
Ok(elements) => {
sink.splice(range, elements.into_iter().map(|(p, e)| (p + pos, e)));
}
Err(arc) => {
sink.splice(range, arc.iter().cloned().map(|(p, e)| (p + pos, e)));
}
}
} }
} }
@ -177,7 +210,7 @@ impl Frame {
impl Frame { impl Frame {
/// Remove all elements from the frame. /// Remove all elements from the frame.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.elements.clear(); self.elements = Arc::new(vec![]);
} }
/// Resize the frame to a new size, distributing new space according to the /// Resize the frame to a new size, distributing new space according to the
@ -199,7 +232,7 @@ impl Frame {
if let Some(baseline) = &mut self.baseline { if let Some(baseline) = &mut self.baseline {
*baseline += offset.y; *baseline += offset.y;
} }
for (point, _) in &mut self.elements { for (point, _) in Arc::make_mut(&mut self.elements) {
*point += offset; *point += offset;
} }
} }
@ -207,7 +240,7 @@ impl Frame {
/// Apply the given role to the frame if it doesn't already have one. /// Apply the given role to the frame if it doesn't already have one.
pub fn apply_role(&mut self, role: Role) { pub fn apply_role(&mut self, role: Role) {
if self.role.map_or(true, Role::is_weak) { if self.role.map_or(true, |prev| prev.is_weak() && !role.is_weak()) {
self.role = Some(role); self.role = Some(role);
} }
} }
@ -232,8 +265,9 @@ impl Frame {
where where
F: FnOnce(&mut Group), F: FnOnce(&mut Group),
{ {
let mut wrapper = Frame { elements: vec![], ..*self }; let mut wrapper = Frame::new(self.size);
let mut group = Group::new(Arc::new(std::mem::take(self))); wrapper.baseline = self.baseline;
let mut group = Group::new(std::mem::take(self));
f(&mut group); f(&mut group);
wrapper.push(Point::zero(), Element::Group(group)); wrapper.push(Point::zero(), Element::Group(group));
*self = wrapper; *self = wrapper;
@ -252,76 +286,6 @@ impl Debug for Frame {
} }
} }
impl AsRef<Frame> for Frame {
fn as_ref(&self) -> &Frame {
self
}
}
/// A representational form of a frame (owned, shared or maybe shared).
pub trait FrameRepr: AsRef<Frame> {
/// Transform into a shared representation.
fn share(self) -> Arc<Frame>;
/// Inline `self` into the sink frame.
fn inline(self, sink: &mut Frame, layer: usize, offset: Point);
}
impl FrameRepr for Frame {
fn share(self) -> Arc<Frame> {
Arc::new(self)
}
fn inline(self, sink: &mut Frame, layer: usize, offset: Point) {
if offset.is_zero() {
if sink.elements.is_empty() {
sink.elements = self.elements;
} else {
sink.elements.splice(layer .. layer, self.elements);
}
} else {
sink.elements.splice(
layer .. layer,
self.elements.into_iter().map(|(p, e)| (p + offset, e)),
);
}
}
}
impl FrameRepr for Arc<Frame> {
fn share(self) -> Arc<Frame> {
self
}
fn inline(self, sink: &mut Frame, layer: usize, offset: Point) {
match Arc::try_unwrap(self) {
Ok(frame) => frame.inline(sink, layer, offset),
Err(rc) => {
sink.elements.splice(
layer .. layer,
rc.elements.iter().cloned().map(|(p, e)| (p + offset, e)),
);
}
}
}
}
impl FrameRepr for MaybeShared<Frame> {
fn share(self) -> Arc<Frame> {
match self {
Self::Owned(owned) => owned.share(),
Self::Shared(shared) => shared.share(),
}
}
fn inline(self, sink: &mut Frame, layer: usize, offset: Point) {
match self {
Self::Owned(owned) => owned.inline(sink, layer, offset),
Self::Shared(shared) => shared.inline(sink, layer, offset),
}
}
}
/// The building block frames are composed of. /// The building block frames are composed of.
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub enum Element { pub enum Element {
@ -357,7 +321,7 @@ impl Debug for Element {
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct Group { pub struct Group {
/// The group's frame. /// The group's frame.
pub frame: Arc<Frame>, pub frame: Frame,
/// A transformation to apply to the group. /// A transformation to apply to the group.
pub transform: Transform, pub transform: Transform,
/// Whether the frame should be a clipping boundary. /// Whether the frame should be a clipping boundary.
@ -366,7 +330,7 @@ pub struct Group {
impl Group { impl Group {
/// Create a new group with default settings. /// Create a new group with default settings.
pub fn new(frame: Arc<Frame>) -> Self { pub fn new(frame: Frame) -> Self {
Self { Self {
frame, frame,
transform: Transform::identity(), transform: Transform::identity(),

View File

@ -72,7 +72,7 @@ use crate::source::{SourceId, SourceStore};
/// Returns either a vector of frames representing individual pages or /// Returns either a vector of frames representing individual pages or
/// diagnostics in the form of a vector of error message with file and span /// diagnostics in the form of a vector of error message with file and span
/// information. /// information.
pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult<Vec<Arc<Frame>>> { pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult<Vec<Frame>> {
let module = eval::evaluate(ctx, id, vec![])?; let module = eval::evaluate(ctx, id, vec![])?;
model::layout(ctx, &module.content) model::layout(ctx, &module.content)
} }

View File

@ -17,12 +17,12 @@ impl Layout for HideNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut frames = self.0.layout(ctx, regions, styles)?; let mut frames = self.0.layout(ctx, regions, styles)?;
// Clear the frames. // Clear the frames.
for frame in &mut frames { for frame in &mut frames {
Arc::make_mut(frame).clear(); frame.clear();
} }
Ok(frames) Ok(frames)

View File

@ -38,7 +38,7 @@ impl Layout for ImageNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let img = ctx.images.get(self.0); let img = ctx.images.get(self.0);
let pxw = img.width() as f64; let pxw = img.width() as f64;
let pxh = img.height() as f64; let pxh = img.height() as f64;
@ -90,7 +90,7 @@ impl Layout for ImageNode {
frame.link(url.clone()); frame.link(url.clone());
} }
Ok(vec![Arc::new(frame)]) Ok(vec![frame])
} }
} }

View File

@ -43,7 +43,7 @@ impl Layout for LineNode {
_: &mut Context, _: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let stroke = styles.get(Self::STROKE).unwrap_or_default(); let stroke = styles.get(Self::STROKE).unwrap_or_default();
let origin = self let origin = self
@ -64,7 +64,7 @@ impl Layout for LineNode {
let shape = Geometry::Line(delta.to_point()).stroked(stroke); let shape = Geometry::Line(delta.to_point()).stroked(stroke);
frame.push(origin.to_point(), Element::Shape(shape)); frame.push(origin.to_point(), Element::Shape(shape));
Ok(vec![Arc::new(frame)]) Ok(vec![frame])
} }
} }

View File

@ -79,7 +79,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut frames; let mut frames;
if let Some(child) = &self.0 { if let Some(child) = &self.0 {
let mut inset = styles.get(Self::INSET); let mut inset = styles.get(Self::INSET);
@ -94,7 +94,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
frames = child.layout(ctx, &pod, styles)?; frames = child.layout(ctx, &pod, styles)?;
for frame in frames.iter_mut() { for frame in frames.iter_mut() {
Arc::make_mut(frame).apply_role(Role::GenericBlock); frame.apply_role(Role::GenericBlock);
} }
// Relayout with full expansion into square region to make sure // Relayout with full expansion into square region to make sure
@ -131,10 +131,10 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
size = regions.expand.select(regions.first, size); size = regions.expand.select(regions.first, size);
} }
frames = vec![Arc::new(Frame::new(size))]; frames = vec![Frame::new(size)];
} }
let frame = Arc::make_mut(&mut frames[0]); let frame = &mut frames[0];
// Add fill and/or stroke. // Add fill and/or stroke.
let fill = styles.get(Self::FILL); let fill = styles.get(Self::FILL);

View File

@ -28,13 +28,13 @@ impl Layout for MoveNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut frames = self.child.layout(ctx, regions, styles)?; let mut frames = self.child.layout(ctx, regions, styles)?;
let delta = self.delta.resolve(styles); let delta = self.delta.resolve(styles);
for frame in &mut frames { for frame in &mut frames {
let delta = delta.zip(frame.size()).map(|(d, s)| d.relative_to(s)); let delta = delta.zip(frame.size()).map(|(d, s)| d.relative_to(s));
Arc::make_mut(frame).translate(delta.to_point()); frame.translate(delta.to_point());
} }
Ok(frames) Ok(frames)
@ -89,7 +89,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
let mut frames = self.child.layout(ctx, regions, styles)?; let mut frames = self.child.layout(ctx, regions, styles)?;
@ -99,7 +99,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
.pre_concat(self.transform) .pre_concat(self.transform)
.pre_concat(Transform::translate(-x, -y)); .pre_concat(Transform::translate(-x, -y));
Arc::make_mut(frame).transform(transform); frame.transform(transform);
} }
Ok(frames) Ok(frames)

View File

@ -31,7 +31,7 @@ impl Layout for AlignNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// The child only needs to expand along an axis if there's no alignment. // The child only needs to expand along an axis if there's no alignment.
let mut pod = regions.clone(); let mut pod = regions.clone();
pod.expand &= self.aligns.map_is_none(); pod.expand &= self.aligns.map_is_none();
@ -53,7 +53,7 @@ impl Layout for AlignNode {
.map(|align| align.resolve(styles)) .map(|align| align.resolve(styles))
.unwrap_or(Spec::new(Align::Left, Align::Top)); .unwrap_or(Spec::new(Align::Left, Align::Top));
Arc::make_mut(frame).resize(target, aligns); frame.resize(target, aligns);
} }
Ok(frames) Ok(frames)

View File

@ -31,7 +31,7 @@ impl Layout for ColumnsNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Separating the infinite space into infinite columns does not make // Separating the infinite space into infinite columns does not make
// much sense. // much sense.
if !regions.first.x.is_finite() { if !regions.first.x.is_finite() {
@ -94,7 +94,7 @@ impl Layout for ColumnsNode {
cursor += width + gutter; cursor += width + gutter;
} }
finished.push(Arc::new(output)); finished.push(output);
} }
Ok(finished) Ok(finished)

View File

@ -28,7 +28,7 @@ impl Layout for FlowNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut layouter = FlowLayouter::new(regions); let mut layouter = FlowLayouter::new(regions);
for (child, map) in self.0.iter() { for (child, map) in self.0.iter() {
@ -92,7 +92,7 @@ pub struct FlowLayouter {
/// Spacing and layouted nodes. /// Spacing and layouted nodes.
items: Vec<FlowItem>, items: Vec<FlowItem>,
/// Finished frames for previous regions. /// Finished frames for previous regions.
finished: Vec<Arc<Frame>>, finished: Vec<Frame>,
} }
/// A prepared item in a flow layout. /// A prepared item in a flow layout.
@ -102,9 +102,9 @@ enum FlowItem {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fraction), Fractional(Fraction),
/// A frame for a layouted child node and how to align it. /// A frame for a layouted child node and how to align it.
Frame(Arc<Frame>, Spec<Align>), Frame(Frame, Spec<Align>),
/// An absolutely placed frame. /// An absolutely placed frame.
Placed(Arc<Frame>), Placed(Frame),
} }
impl FlowLayouter { impl FlowLayouter {
@ -184,9 +184,7 @@ impl FlowLayouter {
let len = frames.len(); let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() { for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role. // Set the generic block role.
if frame.role().map_or(true, Role::is_weak) { frame.apply_role(Role::GenericBlock);
Arc::make_mut(&mut frame).apply_role(Role::GenericBlock);
}
// Grow our size, shrink the region and save the frame for later. // Grow our size, shrink the region and save the frame for later.
let size = frame.size(); let size = frame.size();
@ -248,11 +246,11 @@ impl FlowLayouter {
self.full = self.regions.first; self.full = self.regions.first;
self.used = Size::zero(); self.used = Size::zero();
self.fr = Fraction::zero(); self.fr = Fraction::zero();
self.finished.push(Arc::new(output)); self.finished.push(output);
} }
/// Finish layouting and return the resulting frames. /// Finish layouting and return the resulting frames.
pub fn finish(mut self) -> Vec<Arc<Frame>> { pub fn finish(mut self) -> Vec<Frame> {
if self.expand.y { if self.expand.y {
while self.regions.backlog.len() > 0 { while self.regions.backlog.len() > 0 {
self.finish_region(); self.finish_region();

View File

@ -36,7 +36,7 @@ impl Layout for GridNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Prepare grid layout by unifying content and gutter tracks. // Prepare grid layout by unifying content and gutter tracks.
let layouter = GridLayouter::new( let layouter = GridLayouter::new(
ctx, ctx,
@ -116,7 +116,7 @@ pub struct GridLayouter<'a> {
/// The sum of fractions in the current region. /// The sum of fractions in the current region.
fr: Fraction, fr: Fraction,
/// Frames for finished regions. /// Frames for finished regions.
finished: Vec<Arc<Frame>>, finished: Vec<Frame>,
} }
/// Produced by initial row layout, auto and relative rows are already finished, /// Produced by initial row layout, auto and relative rows are already finished,
@ -203,7 +203,7 @@ impl<'a> GridLayouter<'a> {
} }
/// Determines the columns sizes and then layouts the grid row-by-row. /// Determines the columns sizes and then layouts the grid row-by-row.
pub fn layout(mut self) -> TypResult<Vec<Arc<Frame>>> { pub fn layout(mut self) -> TypResult<Vec<Frame>> {
self.ctx.pins.freeze(); self.ctx.pins.freeze();
self.measure_columns()?; self.measure_columns()?;
self.ctx.pins.unfreeze(); self.ctx.pins.unfreeze();
@ -567,7 +567,7 @@ impl<'a> GridLayouter<'a> {
pos.y += height; pos.y += height;
} }
self.finished.push(Arc::new(output)); self.finished.push(output);
self.regions.next(); self.regions.next();
self.full = self.regions.first.y; self.full = self.regions.first.y;
self.used.y = Length::zero(); self.used.y = Length::zero();

View File

@ -31,7 +31,7 @@ impl Layout for PadNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Layout child into padded regions. // Layout child into padded regions.
let padding = self.padding.resolve(styles); let padding = self.padding.resolve(styles);
let pod = regions.map(|size| shrink(size, padding)); let pod = regions.map(|size| shrink(size, padding));
@ -45,7 +45,6 @@ impl Layout for PadNode {
let offset = Point::new(padding.left, padding.top); let offset = Point::new(padding.left, padding.top);
// Grow the frame and translate everything in the frame inwards. // Grow the frame and translate everything in the frame inwards.
let frame = Arc::make_mut(frame);
frame.set_size(padded); frame.set_size(padded);
frame.translate(offset); frame.translate(offset);
} }

View File

@ -60,7 +60,7 @@ impl PageNode {
ctx: &mut Context, ctx: &mut Context,
mut page: usize, mut page: usize,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// When one of the lengths is infinite the page fits its content along // When one of the lengths is infinite the page fits its content along
// that axis. // that axis.
let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());
@ -129,12 +129,12 @@ impl PageNode {
if let Some(content) = marginal.resolve(ctx, page)? { if let Some(content) = marginal.resolve(ctx, page)? {
let pod = Regions::one(area, area, Spec::splat(true)); let pod = Regions::one(area, area, Spec::splat(true));
let mut sub = content.layout(ctx, &pod, styles)?.remove(0); let mut sub = content.layout(ctx, &pod, styles)?.remove(0);
Arc::make_mut(&mut sub).apply_role(role); sub.apply_role(role);
if role == Role::Background { if role == Role::Background {
Arc::make_mut(frame).prepend_frame(pos, sub); frame.prepend_frame(pos, sub);
} else { } else {
Arc::make_mut(frame).push_frame(pos, sub); frame.push_frame(pos, sub);
} }
} }
} }

View File

@ -24,7 +24,7 @@ impl Layout for PlaceNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let out_of_flow = self.out_of_flow(); let out_of_flow = self.out_of_flow();
// The pod is the base area of the region because for absolute // The pod is the base area of the region because for absolute
@ -41,7 +41,7 @@ impl Layout for PlaceNode {
// space in our parent. Otherwise, respect the expand settings. // space in our parent. Otherwise, respect the expand settings.
let frame = &mut frames[0]; let frame = &mut frames[0];
let target = regions.expand.select(regions.first, Size::zero()); let target = regions.expand.select(regions.first, Size::zero());
Arc::make_mut(frame).resize(target, Align::LEFT_TOP); frame.resize(target, Align::LEFT_TOP);
Ok(frames) Ok(frames)
} }

View File

@ -30,7 +30,7 @@ impl Layout for StackNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut layouter = StackLayouter::new(self.dir, regions, styles); let mut layouter = StackLayouter::new(self.dir, regions, styles);
// Spacing to insert before the next node. // Spacing to insert before the next node.
@ -107,7 +107,7 @@ pub struct StackLayouter<'a> {
/// fractional spacing. /// fractional spacing.
items: Vec<StackItem>, items: Vec<StackItem>,
/// Finished frames for previous regions. /// Finished frames for previous regions.
finished: Vec<Arc<Frame>>, finished: Vec<Frame>,
} }
/// A prepared item in a stack layout. /// A prepared item in a stack layout.
@ -117,7 +117,7 @@ enum StackItem {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fraction), Fractional(Fraction),
/// A frame for a layouted child node. /// A frame for a layouted child node.
Frame(Arc<Frame>, Align), Frame(Frame, Align),
} }
impl<'a> StackLayouter<'a> { impl<'a> StackLayouter<'a> {
@ -196,9 +196,7 @@ impl<'a> StackLayouter<'a> {
let len = frames.len(); let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() { for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role. // Set the generic block role.
if frame.role().map_or(true, Role::is_weak) { frame.apply_role(Role::GenericBlock);
Arc::make_mut(&mut frame).apply_role(Role::GenericBlock);
}
// Grow our size, shrink the region and save the frame for later. // Grow our size, shrink the region and save the frame for later.
let size = frame.size().to_gen(self.axis); let size = frame.size().to_gen(self.axis);
@ -268,11 +266,11 @@ impl<'a> StackLayouter<'a> {
self.full = self.regions.first; self.full = self.regions.first;
self.used = Gen::zero(); self.used = Gen::zero();
self.fr = Fraction::zero(); self.fr = Fraction::zero();
self.finished.push(Arc::new(output)); self.finished.push(output);
} }
/// Finish layouting and return the resulting frames. /// Finish layouting and return the resulting frames.
pub fn finish(mut self) -> Vec<Arc<Frame>> { pub fn finish(mut self) -> Vec<Frame> {
self.finish_region(); self.finish_region();
self.finished self.finished
} }

View File

@ -25,7 +25,7 @@ impl Layout for RexNode {
ctx: &mut Context, ctx: &mut Context,
_: &Regions, _: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Load the font. // Load the font.
let span = self.tex.span; let span = self.tex.span;
let face_id = ctx let face_id = ctx
@ -80,7 +80,7 @@ impl Layout for RexNode {
// Render into the frame. // Render into the frame.
renderer.render(&layout, &mut backend); renderer.render(&layout, &mut backend);
Ok(vec![Arc::new(backend.frame)]) Ok(vec![backend.frame])
} }
} }

View File

@ -7,11 +7,7 @@ pub struct DocNode(pub StyleVec<PageNode>);
impl DocNode { impl DocNode {
/// Layout the document into a sequence of frames, one per page. /// Layout the document into a sequence of frames, one per page.
pub fn layout( pub fn layout(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Vec<Frame>> {
&self,
ctx: &mut Context,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
let mut frames = vec![]; let mut frames = vec![];
for (page, map) in self.0.iter() { for (page, map) in self.0.iter() {
let number = 1 + frames.len(); let number = 1 + frames.len();

View File

@ -1,5 +1,4 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc;
use unicode_bidi::{BidiInfo, Level}; use unicode_bidi::{BidiInfo, Level};
use unicode_script::{Script, UnicodeScript}; use unicode_script::{Script, UnicodeScript};
@ -9,7 +8,7 @@ use super::{shape, Lang, Quoter, Quotes, RepeatNode, ShapedText, TextNode};
use crate::font::FontStore; use crate::font::FontStore;
use crate::library::layout::Spacing; use crate::library::layout::Spacing;
use crate::library::prelude::*; use crate::library::prelude::*;
use crate::util::{EcoString, MaybeShared}; use crate::util::EcoString;
/// Arrange text, spacing and inline-level nodes into a paragraph. /// Arrange text, spacing and inline-level nodes into a paragraph.
#[derive(Hash)] #[derive(Hash)]
@ -71,7 +70,7 @@ impl Layout for ParNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Collect all text into one string for BiDi analysis. // Collect all text into one string for BiDi analysis.
let (text, segments) = collect(self, &styles); let (text, segments) = collect(self, &styles);
@ -305,7 +304,7 @@ enum Item<'a> {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fraction), Fractional(Fraction),
/// A layouted child node. /// A layouted child node.
Frame(Arc<Frame>), Frame(Frame),
/// A repeating node. /// A repeating node.
Repeat(&'a RepeatNode, StyleChain<'a>), Repeat(&'a RepeatNode, StyleChain<'a>),
/// A pin identified by index. /// A pin identified by index.
@ -551,16 +550,9 @@ fn prepare<'a>(
} else { } else {
let size = Size::new(regions.first.x, regions.base.y); let size = Size::new(regions.first.x, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::splat(false)); let pod = Regions::one(size, regions.base, Spec::splat(false));
let mut frame = node.layout(ctx, &pod, styles)?.remove(0); let mut frame = node.layout(ctx, &pod, styles)?.remove(0);
let shift = styles.get(TextNode::BASELINE); frame.translate(Point::with_y(styles.get(TextNode::BASELINE)));
frame.apply_role(Role::GenericInline);
if !shift.is_zero() || frame.role().map_or(true, Role::is_weak) {
let frame = Arc::make_mut(&mut frame);
frame.translate(Point::with_y(shift));
frame.apply_role(Role::GenericInline);
}
items.push(Item::Frame(frame)); items.push(Item::Frame(frame));
} }
} }
@ -1053,7 +1045,7 @@ fn stack(
ctx: &mut Context, ctx: &mut Context,
lines: &[Line], lines: &[Line],
regions: &Regions, regions: &Regions,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// Determine the paragraph's width: Full width of the region if we // Determine the paragraph's width: Full width of the region if we
// should expand or there's fractional spacing, fit-to-width otherwise. // should expand or there's fractional spacing, fit-to-width otherwise.
let mut width = regions.first.x; let mut width = regions.first.x;
@ -1074,7 +1066,7 @@ fn stack(
let height = frame.size().y; let height = frame.size().y;
while !regions.first.y.fits(height) && !regions.in_last() { while !regions.first.y.fits(height) && !regions.in_last() {
finished.push(Arc::new(output)); finished.push(output);
output = Frame::new(Size::with_x(width)); output = Frame::new(Size::with_x(width));
output.apply_role(Role::Paragraph); output.apply_role(Role::Paragraph);
regions.next(); regions.next();
@ -1093,7 +1085,7 @@ fn stack(
first = false; first = false;
} }
finished.push(Arc::new(output)); finished.push(output);
Ok(finished) Ok(finished)
} }
@ -1155,7 +1147,7 @@ fn commit(
// Build the frames and determine the height and baseline. // Build the frames and determine the height and baseline.
let mut frames = vec![]; let mut frames = vec![];
for item in reordered { for item in reordered {
let mut push = |offset: &mut Length, frame: MaybeShared<Frame>| { let mut push = |offset: &mut Length, frame: Frame| {
let width = frame.width(); let width = frame.width();
top.set_max(frame.baseline()); top.set_max(frame.baseline());
bottom.set_max(frame.size().y - frame.baseline()); bottom.set_max(frame.size().y - frame.baseline());
@ -1172,10 +1164,10 @@ fn commit(
} }
Item::Text(shaped) => { Item::Text(shaped) => {
let frame = shaped.build(&mut ctx.fonts, justification); let frame = shaped.build(&mut ctx.fonts, justification);
push(&mut offset, MaybeShared::Owned(frame)); push(&mut offset, frame);
} }
Item::Frame(frame) => { Item::Frame(frame) => {
push(&mut offset, MaybeShared::Shared(frame.clone())); push(&mut offset, frame.clone());
} }
Item::Repeat(node, styles) => { Item::Repeat(node, styles) => {
let before = offset; let before = offset;
@ -1192,7 +1184,7 @@ fn commit(
} }
if width > Length::zero() { if width > Length::zero() {
for _ in 0 .. (count as usize).min(1000) { for _ in 0 .. (count as usize).min(1000) {
push(&mut offset, MaybeShared::Shared(frame.clone())); push(&mut offset, frame.clone());
offset += apart; offset += apart;
} }
} }
@ -1201,7 +1193,7 @@ fn commit(
Item::Pin(idx) => { Item::Pin(idx) => {
let mut frame = Frame::new(Size::zero()); let mut frame = Frame::new(Size::zero());
frame.push(Point::zero(), Element::Pin(*idx)); frame.push(Point::zero(), Element::Pin(*idx));
push(&mut offset, MaybeShared::Owned(frame)); push(&mut offset, frame);
} }
} }
} }

View File

@ -17,7 +17,7 @@ impl Layout for RepeatNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// The actual repeating happens directly in the paragraph. // The actual repeating happens directly in the paragraph.
self.0.layout(ctx, regions, styles) self.0.layout(ctx, regions, styles)
} }

View File

@ -22,7 +22,7 @@ use crate::util::EcoString;
/// Layout content into a collection of pages. /// Layout content into a collection of pages.
/// ///
/// Relayouts until all pinned locations are converged. /// Relayouts until all pinned locations are converged.
pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Arc<Frame>>> { pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Frame>> {
let mut pass = 0; let mut pass = 0;
let mut frames; let mut frames;
@ -46,7 +46,7 @@ pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Arc<Frame>>
} }
/// Layout content into a collection of pages once. /// Layout content into a collection of pages once.
fn layout_once(ctx: &mut Context, content: &Content) -> TypResult<Vec<Arc<Frame>>> { fn layout_once(ctx: &mut Context, content: &Content) -> TypResult<Vec<Frame>> {
let copy = ctx.config.styles.clone(); let copy = ctx.config.styles.clone();
let styles = StyleChain::with_root(&copy); let styles = StyleChain::with_root(&copy);
let scratch = Scratch::default(); let scratch = Scratch::default();
@ -263,7 +263,7 @@ impl Layout for Content {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let scratch = Scratch::default(); let scratch = Scratch::default();
let mut builder = Builder::new(ctx, &scratch, false); let mut builder = Builder::new(ctx, &scratch, false);
builder.accept(self, styles)?; builder.accept(self, styles)?;

View File

@ -28,7 +28,7 @@ pub trait Layout: 'static {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>>; ) -> TypResult<Vec<Frame>>;
/// Convert to a packed node. /// Convert to a packed node.
fn pack(self) -> LayoutNode fn pack(self) -> LayoutNode
@ -222,7 +222,7 @@ impl Layout for LayoutNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let prev = ctx.pins.dirty.replace(false); let prev = ctx.pins.dirty.replace(false);
let (result, at, fresh, dirty) = crate::memo::memoized( let (result, at, fresh, dirty) = crate::memo::memoized(
@ -238,7 +238,7 @@ impl Layout for LayoutNode {
if let Some(role) = styles.role() { if let Some(role) = styles.role() {
result = result.map(|mut frames| { result = result.map(|mut frames| {
for frame in frames.iter_mut() { for frame in frames.iter_mut() {
Arc::make_mut(frame).apply_role(role); frame.apply_role(role);
} }
frames frames
}); });
@ -319,10 +319,10 @@ impl Layout for EmptyNode {
_: &mut Context, _: &mut Context,
regions: &Regions, regions: &Regions,
_: StyleChain, _: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
Ok(vec![Arc::new(Frame::new( Ok(vec![Frame::new(
regions.expand.select(regions.first, Size::zero()), regions.expand.select(regions.first, Size::zero()),
))]) )])
} }
} }
@ -341,7 +341,7 @@ impl Layout for SizedNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
// The "pod" is the region into which the child will be layouted. // The "pod" is the region into which the child will be layouted.
let pod = { let pod = {
// Resolve the sizing to a concrete size. // Resolve the sizing to a concrete size.
@ -367,7 +367,7 @@ impl Layout for SizedNode {
// Ensure frame size matches regions size if expansion is on. // Ensure frame size matches regions size if expansion is on.
let frame = &mut frames[0]; let frame = &mut frames[0];
let target = regions.expand.select(regions.first, frame.size()); let target = regions.expand.select(regions.first, frame.size());
Arc::make_mut(frame).resize(target, Align::LEFT_TOP); frame.resize(target, Align::LEFT_TOP);
Ok(frames) Ok(frames)
} }
@ -388,11 +388,11 @@ impl Layout for FillNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut frames = self.child.layout(ctx, regions, styles)?; let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames { for frame in &mut frames {
let shape = Geometry::Rect(frame.size()).filled(self.fill); let shape = Geometry::Rect(frame.size()).filled(self.fill);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); frame.prepend(Point::zero(), Element::Shape(shape));
} }
Ok(frames) Ok(frames)
} }
@ -413,11 +413,11 @@ impl Layout for StrokeNode {
ctx: &mut Context, ctx: &mut Context,
regions: &Regions, regions: &Regions,
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Frame>> {
let mut frames = self.child.layout(ctx, regions, styles)?; let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames { for frame in &mut frames {
let shape = Geometry::Rect(frame.size()).stroked(self.stroke); let shape = Geometry::Rect(frame.size()).stroked(self.stroke);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); frame.prepend(Point::zero(), Element::Shape(shape));
} }
Ok(frames) Ok(frames)
} }

View File

@ -272,7 +272,7 @@ impl PinBoard {
} }
/// Locate all pins in the frames. /// Locate all pins in the frames.
pub fn locate(&mut self, frames: &[Arc<Frame>]) { pub fn locate(&mut self, frames: &[Frame]) {
let mut flow = 0; let mut flow = 0;
for (i, frame) in frames.iter().enumerate() { for (i, frame) in frames.iter().enumerate() {
locate_in_frame( locate_in_frame(

View File

@ -12,7 +12,7 @@ pub use prehashed::Prehashed;
use std::any::TypeId; use std::any::TypeId;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::ops::{Deref, Range}; use std::ops::Range;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
@ -64,31 +64,6 @@ impl Debug for ReadableTypeId {
} }
} }
/// Either owned or shared.
pub enum MaybeShared<T> {
/// Owned data.
Owned(T),
/// Shared data.
Shared(Arc<T>),
}
impl<T> AsRef<T> for MaybeShared<T> {
fn as_ref(&self) -> &T {
self
}
}
impl<T> Deref for MaybeShared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(owned) => owned,
Self::Shared(shared) => shared,
}
}
}
/// Extra methods for [`str`]. /// Extra methods for [`str`].
pub trait StrExt { pub trait StrExt {
/// The number of code units this string would use if it was encoded in /// The number of code units this string would use if it was encoded in

View File

@ -286,7 +286,7 @@ fn test_part(
line: usize, line: usize,
print: &PrintConfig, print: &PrintConfig,
rng: &mut LinearShift, rng: &mut LinearShift,
) -> (bool, bool, Vec<Arc<Frame>>) { ) -> (bool, bool, Vec<Frame>) {
let mut ok = true; let mut ok = true;
let id = ctx.sources.provide(src_path, src); let id = ctx.sources.provide(src_path, src);
@ -532,7 +532,7 @@ fn test_spans_impl(node: &SyntaxNode, within: Range<u64>) -> bool {
} }
/// Draw all frames into one image with padding in between. /// Draw all frames into one image with padding in between.
fn render(ctx: &mut Context, frames: &[Arc<Frame>]) -> sk::Pixmap { fn render(ctx: &mut Context, frames: &[Frame]) -> sk::Pixmap {
let pixel_per_pt = 2.0; let pixel_per_pt = 2.0;
let pixmaps: Vec<_> = frames let pixmaps: Vec<_> = frames
.iter() .iter()