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::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<Frame>]) -> Vec<u8> {
pub fn pdf(ctx: &Context, frames: &[Frame]) -> Vec<u8> {
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.write_fonts();
self.write_images();
@ -100,7 +99,7 @@ impl<'a> PdfExporter<'a> {
self.writer.finish()
}
fn build_pages(&mut self, frames: &[Arc<Frame>]) {
fn build_pages(&mut self, frames: &[Frame]) {
for frame in frames {
let page_id = self.alloc.bump();
self.page_refs.push(page_id);

View File

@ -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<Role>,
/// The elements composing this layout.
elements: Vec<(Point, Element)>,
elements: Arc<Vec<(Point, Element)>>,
}
/// 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<I>(&mut self, insert: I)
pub fn prepend_multiple<I>(&mut self, elements: I)
where
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.
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<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.
#[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<Frame>,
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<Frame>) -> Self {
pub fn new(frame: Frame) -> Self {
Self {
frame,
transform: Transform::identity(),

View File

@ -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<Vec<Arc<Frame>>> {
pub fn typeset(ctx: &mut Context, id: SourceId) -> TypResult<Vec<Frame>> {
let module = eval::evaluate(ctx, id, vec![])?;
model::layout(ctx, &module.content)
}

View File

@ -17,12 +17,12 @@ impl Layout for HideNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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)

View File

@ -38,7 +38,7 @@ impl Layout for ImageNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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])
}
}

View File

@ -43,7 +43,7 @@ impl Layout for LineNode {
_: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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])
}
}

View File

@ -79,7 +79,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
let mut frames;
if let Some(child) = &self.0 {
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)?;
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<const S: ShapeKind> Layout for ShapeNode<S> {
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);

View File

@ -28,13 +28,13 @@ impl Layout for MoveNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<const T: TransformKind> Layout for TransformNode<T> {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<const T: TransformKind> Layout for TransformNode<T> {
.pre_concat(self.transform)
.pre_concat(Transform::translate(-x, -y));
Arc::make_mut(frame).transform(transform);
frame.transform(transform);
}
Ok(frames)

View File

@ -31,7 +31,7 @@ impl Layout for AlignNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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)

View File

@ -31,7 +31,7 @@ impl Layout for ColumnsNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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)

View File

@ -28,7 +28,7 @@ impl Layout for FlowNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<FlowItem>,
/// Finished frames for previous regions.
finished: Vec<Arc<Frame>>,
finished: Vec<Frame>,
}
/// 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<Frame>, Spec<Align>),
Frame(Frame, Spec<Align>),
/// An absolutely placed frame.
Placed(Arc<Frame>),
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<Arc<Frame>> {
pub fn finish(mut self) -> Vec<Frame> {
if self.expand.y {
while self.regions.backlog.len() > 0 {
self.finish_region();

View File

@ -36,7 +36,7 @@ impl Layout for GridNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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<Arc<Frame>>,
finished: Vec<Frame>,
}
/// 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<Vec<Arc<Frame>>> {
pub fn layout(mut self) -> TypResult<Vec<Frame>> {
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();

View File

@ -31,7 +31,7 @@ impl Layout for PadNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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);
}

View File

@ -60,7 +60,7 @@ impl PageNode {
ctx: &mut Context,
mut page: usize,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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);
}
}
}

View File

@ -24,7 +24,7 @@ impl Layout for PlaceNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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)
}

View File

@ -30,7 +30,7 @@ impl Layout for StackNode {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<StackItem>,
/// Finished frames for previous regions.
finished: Vec<Arc<Frame>>,
finished: Vec<Frame>,
}
/// 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<Frame>, 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<Arc<Frame>> {
pub fn finish(mut self) -> Vec<Frame> {
self.finish_region();
self.finished
}

View File

@ -25,7 +25,7 @@ impl Layout for RexNode {
ctx: &mut Context,
_: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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])
}
}

View File

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

View File

@ -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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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(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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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<Frame>| {
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);
}
}
}

View File

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

View File

@ -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<Vec<Arc<Frame>>> {
pub fn layout(ctx: &mut Context, content: &Content) -> TypResult<Vec<Frame>> {
let mut pass = 0;
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.
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 styles = StyleChain::with_root(&copy);
let scratch = Scratch::default();
@ -263,7 +263,7 @@ impl Layout for Content {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
let scratch = Scratch::default();
let mut builder = Builder::new(ctx, &scratch, false);
builder.accept(self, styles)?;

View File

@ -28,7 +28,7 @@ pub trait Layout: 'static {
ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>>;
) -> TypResult<Vec<Frame>>;
/// 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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<Vec<Arc<Frame>>> {
Ok(vec![Arc::new(Frame::new(
) -> TypResult<Vec<Frame>> {
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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
// 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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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<Vec<Arc<Frame>>> {
) -> TypResult<Vec<Frame>> {
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)
}

View File

@ -272,7 +272,7 @@ impl PinBoard {
}
/// 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;
for (i, frame) in frames.iter().enumerate() {
locate_in_frame(

View File

@ -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<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`].
pub trait StrExt {
/// 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,
print: &PrintConfig,
rng: &mut LinearShift,
) -> (bool, bool, Vec<Arc<Frame>>) {
) -> (bool, bool, Vec<Frame>) {
let mut ok = true;
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.
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 pixmaps: Vec<_> = frames
.iter()