Move Arc
into Frame
This commit is contained in:
parent
6e3b1a2c80
commit
7660978ee5
@ -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);
|
||||
|
184
src/frame.rs
184
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<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(),
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(©);
|
||||
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)?;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user