diff --git a/src/export/pdf.rs b/src/export/pdf.rs index cc84dbc3c..3063bf4c8 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -4,7 +4,6 @@ use std::cmp::Eq; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::Hash; use std::io::Cursor; -use std::sync::Arc; use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba}; use pdf_writer::types::{ @@ -34,7 +33,7 @@ use crate::Context; /// included in the PDF. /// /// Returns the raw bytes making up the PDF file. -pub fn pdf(ctx: &Context, frames: &[Arc]) -> Vec { +pub fn pdf(ctx: &Context, frames: &[Frame]) -> Vec { PdfExporter::new(ctx).export(frames) } @@ -84,7 +83,7 @@ impl<'a> PdfExporter<'a> { } } - fn export(mut self, frames: &[Arc]) -> Vec { + fn export(mut self, frames: &[Frame]) -> Vec { self.build_pages(frames); self.write_fonts(); self.write_images(); @@ -100,7 +99,7 @@ impl<'a> PdfExporter<'a> { self.writer.finish() } - fn build_pages(&mut self, frames: &[Arc]) { + fn build_pages(&mut self, frames: &[Frame]) { for frame in frames { let page_id = self.alloc.bump(); self.page_refs.push(page_id); diff --git a/src/frame.rs b/src/frame.rs index 628d8c5b9..6855e7ac2 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -11,7 +11,7 @@ use crate::geom::{ }; use crate::image::ImageId; use crate::library::text::Lang; -use crate::util::{EcoString, MaybeShared}; +use crate::util::EcoString; /// A finished layout with elements at fixed positions. #[derive(Default, Clone, Eq, PartialEq)] @@ -24,7 +24,7 @@ pub struct Frame { /// The semantic role of the frame. role: Option, /// The elements composing this layout. - elements: Vec<(Point, Element)>, + elements: Arc>, } /// Accessors and setters. @@ -39,7 +39,7 @@ impl Frame { size, baseline: 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. pub fn text(&self) -> EcoString { let mut text = EcoString::new(); - for (_, element) in &self.elements { + for (_, element) in self.elements() { match element { Element::Text(content) => { for glyph in &content.glyphs { @@ -117,7 +117,19 @@ impl Frame { /// Add an element at a position in the foreground. 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. @@ -125,51 +137,72 @@ impl Frame { /// This panics if the layer is greater than the number of layers present. #[track_caller] pub fn insert(&mut self, layer: usize, pos: Point, element: Element) { - 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())))); - } + Arc::make_mut(&mut self.elements).insert(layer, (pos, element)); } /// Add an element at a position in the background. 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. - pub fn prepend_multiple(&mut self, insert: I) + pub fn prepend_multiple(&mut self, elements: I) where I: IntoIterator, { - 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. - pub fn prepend_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, 0, pos); + pub fn prepend_frame(&mut self, pos: Point, frame: Frame) { + if self.should_inline(&frame) { + self.inline(0, pos, frame); } else { - self.elements - .insert(0, (pos, Element::Group(Group::new(frame.share())))); + self.prepend(pos, Element::Group(Group::new(frame))); } } - /// Whether the frame has comparatively few elements. - fn is_light(&self) -> bool { - self.elements.len() <= 5 + /// Whether the given frame should be inlined. + pub fn should_inline(&self, frame: &Frame) -> bool { + (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 { /// Remove all elements from the frame. 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 @@ -199,7 +232,7 @@ impl Frame { if let Some(baseline) = &mut self.baseline { *baseline += offset.y; } - for (point, _) in &mut self.elements { + for (point, _) in Arc::make_mut(&mut self.elements) { *point += offset; } } @@ -207,7 +240,7 @@ impl Frame { /// Apply the given role to the frame if it doesn't already have one. 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); } } @@ -232,8 +265,9 @@ impl Frame { where F: FnOnce(&mut Group), { - let mut wrapper = Frame { elements: vec![], ..*self }; - let mut group = Group::new(Arc::new(std::mem::take(self))); + let mut wrapper = Frame::new(self.size); + wrapper.baseline = self.baseline; + let mut group = Group::new(std::mem::take(self)); f(&mut group); wrapper.push(Point::zero(), Element::Group(group)); *self = wrapper; @@ -252,76 +286,6 @@ impl Debug for Frame { } } -impl AsRef for Frame { - fn as_ref(&self) -> &Frame { - self - } -} - -/// A representational form of a frame (owned, shared or maybe shared). -pub trait FrameRepr: AsRef { - /// Transform into a shared representation. - fn share(self) -> Arc; - - /// Inline `self` into the sink frame. - fn inline(self, sink: &mut Frame, layer: usize, offset: Point); -} - -impl FrameRepr for Frame { - fn share(self) -> Arc { - 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 { - fn share(self) -> Arc { - 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 { - fn share(self) -> Arc { - 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. #[derive(Clone, Eq, PartialEq)] pub enum Element { @@ -357,7 +321,7 @@ impl Debug for Element { #[derive(Clone, Eq, PartialEq)] pub struct Group { /// The group's frame. - pub frame: Arc, + pub frame: Frame, /// A transformation to apply to the group. pub transform: Transform, /// Whether the frame should be a clipping boundary. @@ -366,7 +330,7 @@ pub struct Group { impl Group { /// Create a new group with default settings. - pub fn new(frame: Arc) -> Self { + pub fn new(frame: Frame) -> Self { Self { frame, transform: Transform::identity(), diff --git a/src/lib.rs b/src/lib.rs index f9416463f..25a41c358 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ use crate::source::{SourceId, SourceStore}; /// Returns either a vector of frames representing individual pages or /// diagnostics in the form of a vector of error message with file and span /// information. -pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult>> { +pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult> { let module = eval::evaluate(ctx, id, vec![])?; model::layout(ctx, &module.content) } diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs index c969ef760..0ed02d1b9 100644 --- a/src/library/graphics/hide.rs +++ b/src/library/graphics/hide.rs @@ -17,12 +17,12 @@ impl Layout for HideNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut frames = self.0.layout(ctx, regions, styles)?; // Clear the frames. for frame in &mut frames { - Arc::make_mut(frame).clear(); + frame.clear(); } Ok(frames) diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs index d0bcfa446..1781eb8aa 100644 --- a/src/library/graphics/image.rs +++ b/src/library/graphics/image.rs @@ -38,7 +38,7 @@ impl Layout for ImageNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let img = ctx.images.get(self.0); let pxw = img.width() as f64; let pxh = img.height() as f64; @@ -90,7 +90,7 @@ impl Layout for ImageNode { frame.link(url.clone()); } - Ok(vec![Arc::new(frame)]) + Ok(vec![frame]) } } diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs index 8e5ceae12..15c54f460 100644 --- a/src/library/graphics/line.rs +++ b/src/library/graphics/line.rs @@ -43,7 +43,7 @@ impl Layout for LineNode { _: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let stroke = styles.get(Self::STROKE).unwrap_or_default(); let origin = self @@ -64,7 +64,7 @@ impl Layout for LineNode { let shape = Geometry::Line(delta.to_point()).stroked(stroke); frame.push(origin.to_point(), Element::Shape(shape)); - Ok(vec![Arc::new(frame)]) + Ok(vec![frame]) } } diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index 6c315c24f..bf5818155 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -79,7 +79,7 @@ impl Layout for ShapeNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut frames; if let Some(child) = &self.0 { let mut inset = styles.get(Self::INSET); @@ -94,7 +94,7 @@ impl Layout for ShapeNode { frames = child.layout(ctx, &pod, styles)?; 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 @@ -131,10 +131,10 @@ impl Layout for ShapeNode { 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. let fill = styles.get(Self::FILL); diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs index 7176a683d..2a0149bc8 100644 --- a/src/library/graphics/transform.rs +++ b/src/library/graphics/transform.rs @@ -28,13 +28,13 @@ impl Layout for MoveNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut frames = self.child.layout(ctx, regions, styles)?; let delta = self.delta.resolve(styles); for frame in &mut frames { 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) @@ -89,7 +89,7 @@ impl Layout for TransformNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let mut frames = self.child.layout(ctx, regions, styles)?; @@ -99,7 +99,7 @@ impl Layout for TransformNode { .pre_concat(self.transform) .pre_concat(Transform::translate(-x, -y)); - Arc::make_mut(frame).transform(transform); + frame.transform(transform); } Ok(frames) diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs index c5adcf9f9..e7a27c045 100644 --- a/src/library/layout/align.rs +++ b/src/library/layout/align.rs @@ -31,7 +31,7 @@ impl Layout for AlignNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // The child only needs to expand along an axis if there's no alignment. let mut pod = regions.clone(); pod.expand &= self.aligns.map_is_none(); @@ -53,7 +53,7 @@ impl Layout for AlignNode { .map(|align| align.resolve(styles)) .unwrap_or(Spec::new(Align::Left, Align::Top)); - Arc::make_mut(frame).resize(target, aligns); + frame.resize(target, aligns); } Ok(frames) diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs index b9e308f2a..33ceab867 100644 --- a/src/library/layout/columns.rs +++ b/src/library/layout/columns.rs @@ -31,7 +31,7 @@ impl Layout for ColumnsNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // Separating the infinite space into infinite columns does not make // much sense. if !regions.first.x.is_finite() { @@ -94,7 +94,7 @@ impl Layout for ColumnsNode { cursor += width + gutter; } - finished.push(Arc::new(output)); + finished.push(output); } Ok(finished) diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs index b6844f552..c6d2999e5 100644 --- a/src/library/layout/flow.rs +++ b/src/library/layout/flow.rs @@ -28,7 +28,7 @@ impl Layout for FlowNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut layouter = FlowLayouter::new(regions); for (child, map) in self.0.iter() { @@ -92,7 +92,7 @@ pub struct FlowLayouter { /// Spacing and layouted nodes. items: Vec, /// Finished frames for previous regions. - finished: Vec>, + finished: Vec, } /// A prepared item in a flow layout. @@ -102,9 +102,9 @@ enum FlowItem { /// Fractional spacing between other items. Fractional(Fraction), /// A frame for a layouted child node and how to align it. - Frame(Arc, Spec), + Frame(Frame, Spec), /// An absolutely placed frame. - Placed(Arc), + Placed(Frame), } impl FlowLayouter { @@ -184,9 +184,7 @@ impl FlowLayouter { let len = frames.len(); for (i, mut frame) in frames.into_iter().enumerate() { // Set the generic block role. - if frame.role().map_or(true, Role::is_weak) { - Arc::make_mut(&mut frame).apply_role(Role::GenericBlock); - } + frame.apply_role(Role::GenericBlock); // Grow our size, shrink the region and save the frame for later. let size = frame.size(); @@ -248,11 +246,11 @@ impl FlowLayouter { self.full = self.regions.first; self.used = Size::zero(); self.fr = Fraction::zero(); - self.finished.push(Arc::new(output)); + self.finished.push(output); } /// Finish layouting and return the resulting frames. - pub fn finish(mut self) -> Vec> { + pub fn finish(mut self) -> Vec { if self.expand.y { while self.regions.backlog.len() > 0 { self.finish_region(); diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs index c04913a1c..c02662a61 100644 --- a/src/library/layout/grid.rs +++ b/src/library/layout/grid.rs @@ -36,7 +36,7 @@ impl Layout for GridNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // Prepare grid layout by unifying content and gutter tracks. let layouter = GridLayouter::new( ctx, @@ -116,7 +116,7 @@ pub struct GridLayouter<'a> { /// The sum of fractions in the current region. fr: Fraction, /// Frames for finished regions. - finished: Vec>, + finished: Vec, } /// 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. - pub fn layout(mut self) -> TypResult>> { + pub fn layout(mut self) -> TypResult> { self.ctx.pins.freeze(); self.measure_columns()?; self.ctx.pins.unfreeze(); @@ -567,7 +567,7 @@ impl<'a> GridLayouter<'a> { pos.y += height; } - self.finished.push(Arc::new(output)); + self.finished.push(output); self.regions.next(); self.full = self.regions.first.y; self.used.y = Length::zero(); diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs index 29a72588f..dfd425bd1 100644 --- a/src/library/layout/pad.rs +++ b/src/library/layout/pad.rs @@ -31,7 +31,7 @@ impl Layout for PadNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // Layout child into padded regions. let padding = self.padding.resolve(styles); let pod = regions.map(|size| shrink(size, padding)); @@ -45,7 +45,6 @@ impl Layout for PadNode { let offset = Point::new(padding.left, padding.top); // Grow the frame and translate everything in the frame inwards. - let frame = Arc::make_mut(frame); frame.set_size(padded); frame.translate(offset); } diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index e22bb4f7a..e2f414ab4 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -60,7 +60,7 @@ impl PageNode { ctx: &mut Context, mut page: usize, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // When one of the lengths is infinite the page fits its content along // that axis. let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); @@ -129,12 +129,12 @@ impl PageNode { if let Some(content) = marginal.resolve(ctx, page)? { let pod = Regions::one(area, area, Spec::splat(true)); 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 { - Arc::make_mut(frame).prepend_frame(pos, sub); + frame.prepend_frame(pos, sub); } else { - Arc::make_mut(frame).push_frame(pos, sub); + frame.push_frame(pos, sub); } } } diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs index 408ca1290..67e46d3bd 100644 --- a/src/library/layout/place.rs +++ b/src/library/layout/place.rs @@ -24,7 +24,7 @@ impl Layout for PlaceNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let out_of_flow = self.out_of_flow(); // 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. let frame = &mut frames[0]; 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) } diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs index 5d3e17865..b1268404a 100644 --- a/src/library/layout/stack.rs +++ b/src/library/layout/stack.rs @@ -30,7 +30,7 @@ impl Layout for StackNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut layouter = StackLayouter::new(self.dir, regions, styles); // Spacing to insert before the next node. @@ -107,7 +107,7 @@ pub struct StackLayouter<'a> { /// fractional spacing. items: Vec, /// Finished frames for previous regions. - finished: Vec>, + finished: Vec, } /// A prepared item in a stack layout. @@ -117,7 +117,7 @@ enum StackItem { /// Fractional spacing between other items. Fractional(Fraction), /// A frame for a layouted child node. - Frame(Arc, Align), + Frame(Frame, Align), } impl<'a> StackLayouter<'a> { @@ -196,9 +196,7 @@ impl<'a> StackLayouter<'a> { let len = frames.len(); for (i, mut frame) in frames.into_iter().enumerate() { // Set the generic block role. - if frame.role().map_or(true, Role::is_weak) { - Arc::make_mut(&mut frame).apply_role(Role::GenericBlock); - } + frame.apply_role(Role::GenericBlock); // Grow our size, shrink the region and save the frame for later. let size = frame.size().to_gen(self.axis); @@ -268,11 +266,11 @@ impl<'a> StackLayouter<'a> { self.full = self.regions.first; self.used = Gen::zero(); self.fr = Fraction::zero(); - self.finished.push(Arc::new(output)); + self.finished.push(output); } /// Finish layouting and return the resulting frames. - pub fn finish(mut self) -> Vec> { + pub fn finish(mut self) -> Vec { self.finish_region(); self.finished } diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs index 930829dec..a8dbd764c 100644 --- a/src/library/math/rex.rs +++ b/src/library/math/rex.rs @@ -25,7 +25,7 @@ impl Layout for RexNode { ctx: &mut Context, _: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // Load the font. let span = self.tex.span; let face_id = ctx @@ -80,7 +80,7 @@ impl Layout for RexNode { // Render into the frame. renderer.render(&layout, &mut backend); - Ok(vec![Arc::new(backend.frame)]) + Ok(vec![backend.frame]) } } diff --git a/src/library/structure/doc.rs b/src/library/structure/doc.rs index d3fc0b391..80472e243 100644 --- a/src/library/structure/doc.rs +++ b/src/library/structure/doc.rs @@ -7,11 +7,7 @@ pub struct DocNode(pub StyleVec); impl DocNode { /// Layout the document into a sequence of frames, one per page. - pub fn layout( - &self, - ctx: &mut Context, - styles: StyleChain, - ) -> TypResult>> { + pub fn layout(&self, ctx: &mut Context, styles: StyleChain) -> TypResult> { let mut frames = vec![]; for (page, map) in self.0.iter() { let number = 1 + frames.len(); diff --git a/src/library/text/par.rs b/src/library/text/par.rs index 7a656a30e..e40131638 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -1,5 +1,4 @@ use std::cmp::Ordering; -use std::sync::Arc; use unicode_bidi::{BidiInfo, Level}; use unicode_script::{Script, UnicodeScript}; @@ -9,7 +8,7 @@ use super::{shape, Lang, Quoter, Quotes, RepeatNode, ShapedText, TextNode}; use crate::font::FontStore; use crate::library::layout::Spacing; use crate::library::prelude::*; -use crate::util::{EcoString, MaybeShared}; +use crate::util::EcoString; /// Arrange text, spacing and inline-level nodes into a paragraph. #[derive(Hash)] @@ -71,7 +70,7 @@ impl Layout for ParNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // Collect all text into one string for BiDi analysis. let (text, segments) = collect(self, &styles); @@ -305,7 +304,7 @@ enum Item<'a> { /// Fractional spacing between other items. Fractional(Fraction), /// A layouted child node. - Frame(Arc), + Frame(Frame), /// A repeating node. Repeat(&'a RepeatNode, StyleChain<'a>), /// A pin identified by index. @@ -551,16 +550,9 @@ fn prepare<'a>( } else { let size = Size::new(regions.first.x, regions.base.y); let pod = Regions::one(size, regions.base, Spec::splat(false)); - let mut frame = node.layout(ctx, &pod, styles)?.remove(0); - let shift = styles.get(TextNode::BASELINE); - - 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); - } - + frame.translate(Point::with_y(styles.get(TextNode::BASELINE))); + frame.apply_role(Role::GenericInline); items.push(Item::Frame(frame)); } } @@ -1053,7 +1045,7 @@ fn stack( ctx: &mut Context, lines: &[Line], regions: &Regions, -) -> TypResult>> { +) -> TypResult> { // Determine the paragraph's width: Full width of the region if we // should expand or there's fractional spacing, fit-to-width otherwise. let mut width = regions.first.x; @@ -1074,7 +1066,7 @@ fn stack( let height = frame.size().y; 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.apply_role(Role::Paragraph); regions.next(); @@ -1093,7 +1085,7 @@ fn stack( first = false; } - finished.push(Arc::new(output)); + finished.push(output); Ok(finished) } @@ -1155,7 +1147,7 @@ fn commit( // Build the frames and determine the height and baseline. let mut frames = vec![]; for item in reordered { - let mut push = |offset: &mut Length, frame: MaybeShared| { + let mut push = |offset: &mut Length, frame: Frame| { let width = frame.width(); top.set_max(frame.baseline()); bottom.set_max(frame.size().y - frame.baseline()); @@ -1172,10 +1164,10 @@ fn commit( } Item::Text(shaped) => { let frame = shaped.build(&mut ctx.fonts, justification); - push(&mut offset, MaybeShared::Owned(frame)); + push(&mut offset, frame); } Item::Frame(frame) => { - push(&mut offset, MaybeShared::Shared(frame.clone())); + push(&mut offset, frame.clone()); } Item::Repeat(node, styles) => { let before = offset; @@ -1192,7 +1184,7 @@ fn commit( } if width > Length::zero() { for _ in 0 .. (count as usize).min(1000) { - push(&mut offset, MaybeShared::Shared(frame.clone())); + push(&mut offset, frame.clone()); offset += apart; } } @@ -1201,7 +1193,7 @@ fn commit( Item::Pin(idx) => { let mut frame = Frame::new(Size::zero()); frame.push(Point::zero(), Element::Pin(*idx)); - push(&mut offset, MaybeShared::Owned(frame)); + push(&mut offset, frame); } } } diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs index 9ee8286b6..a3e83ac7f 100644 --- a/src/library/text/repeat.rs +++ b/src/library/text/repeat.rs @@ -17,7 +17,7 @@ impl Layout for RepeatNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // The actual repeating happens directly in the paragraph. self.0.layout(ctx, regions, styles) } diff --git a/src/model/content.rs b/src/model/content.rs index 3e27c02fd..d2af4595d 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -22,7 +22,7 @@ use crate::util::EcoString; /// Layout content into a collection of pages. /// /// Relayouts until all pinned locations are converged. -pub fn layout(ctx: &mut Context, content: &Content) -> TypResult>> { +pub fn layout(ctx: &mut Context, content: &Content) -> TypResult> { let mut pass = 0; let mut frames; @@ -46,7 +46,7 @@ pub fn layout(ctx: &mut Context, content: &Content) -> TypResult> } /// Layout content into a collection of pages once. -fn layout_once(ctx: &mut Context, content: &Content) -> TypResult>> { +fn layout_once(ctx: &mut Context, content: &Content) -> TypResult> { let copy = ctx.config.styles.clone(); let styles = StyleChain::with_root(©); let scratch = Scratch::default(); @@ -263,7 +263,7 @@ impl Layout for Content { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let scratch = Scratch::default(); let mut builder = Builder::new(ctx, &scratch, false); builder.accept(self, styles)?; diff --git a/src/model/layout.rs b/src/model/layout.rs index c971197aa..22797b482 100644 --- a/src/model/layout.rs +++ b/src/model/layout.rs @@ -28,7 +28,7 @@ pub trait Layout: 'static { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>>; + ) -> TypResult>; /// Convert to a packed node. fn pack(self) -> LayoutNode @@ -222,7 +222,7 @@ impl Layout for LayoutNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let prev = ctx.pins.dirty.replace(false); let (result, at, fresh, dirty) = crate::memo::memoized( @@ -238,7 +238,7 @@ impl Layout for LayoutNode { if let Some(role) = styles.role() { result = result.map(|mut frames| { for frame in frames.iter_mut() { - Arc::make_mut(frame).apply_role(role); + frame.apply_role(role); } frames }); @@ -319,10 +319,10 @@ impl Layout for EmptyNode { _: &mut Context, regions: &Regions, _: StyleChain, - ) -> TypResult>> { - Ok(vec![Arc::new(Frame::new( + ) -> TypResult> { + Ok(vec![Frame::new( regions.expand.select(regions.first, Size::zero()), - ))]) + )]) } } @@ -341,7 +341,7 @@ impl Layout for SizedNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { // The "pod" is the region into which the child will be layouted. let pod = { // 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. let frame = &mut frames[0]; 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) } @@ -388,11 +388,11 @@ impl Layout for FillNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut frames = self.child.layout(ctx, regions, styles)?; for frame in &mut frames { 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) } @@ -413,11 +413,11 @@ impl Layout for StrokeNode { ctx: &mut Context, regions: &Regions, styles: StyleChain, - ) -> TypResult>> { + ) -> TypResult> { let mut frames = self.child.layout(ctx, regions, styles)?; for frame in &mut frames { 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) } diff --git a/src/model/locate.rs b/src/model/locate.rs index bda12ae9a..f6432d434 100644 --- a/src/model/locate.rs +++ b/src/model/locate.rs @@ -272,7 +272,7 @@ impl PinBoard { } /// Locate all pins in the frames. - pub fn locate(&mut self, frames: &[Arc]) { + pub fn locate(&mut self, frames: &[Frame]) { let mut flow = 0; for (i, frame) in frames.iter().enumerate() { locate_in_frame( diff --git a/src/util/mod.rs b/src/util/mod.rs index f762d88d5..df3858d6b 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -12,7 +12,7 @@ pub use prehashed::Prehashed; use std::any::TypeId; use std::cmp::Ordering; use std::fmt::{self, Debug, Formatter}; -use std::ops::{Deref, Range}; +use std::ops::Range; use std::path::{Component, Path, PathBuf}; use std::sync::Arc; @@ -64,31 +64,6 @@ impl Debug for ReadableTypeId { } } -/// Either owned or shared. -pub enum MaybeShared { - /// Owned data. - Owned(T), - /// Shared data. - Shared(Arc), -} - -impl AsRef for MaybeShared { - fn as_ref(&self) -> &T { - self - } -} - -impl Deref for MaybeShared { - type Target = T; - - fn deref(&self) -> &Self::Target { - match self { - Self::Owned(owned) => owned, - Self::Shared(shared) => shared, - } - } -} - /// Extra methods for [`str`]. pub trait StrExt { /// The number of code units this string would use if it was encoded in diff --git a/tests/typeset.rs b/tests/typeset.rs index 341a04c0a..31068656d 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -286,7 +286,7 @@ fn test_part( line: usize, print: &PrintConfig, rng: &mut LinearShift, -) -> (bool, bool, Vec>) { +) -> (bool, bool, Vec) { let mut ok = true; let id = ctx.sources.provide(src_path, src); @@ -532,7 +532,7 @@ fn test_spans_impl(node: &SyntaxNode, within: Range) -> bool { } /// Draw all frames into one image with padding in between. -fn render(ctx: &mut Context, frames: &[Arc]) -> sk::Pixmap { +fn render(ctx: &mut Context, frames: &[Frame]) -> sk::Pixmap { let pixel_per_pt = 2.0; let pixmaps: Vec<_> = frames .iter()