mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Ref count the frames
This commit is contained in:
parent
7db78d83be
commit
80a9b300d1
@ -27,7 +27,7 @@ image = { version = "0.23", default-features = false, features = ["png", "jpeg"]
|
|||||||
miniz_oxide = "0.3"
|
miniz_oxide = "0.3"
|
||||||
pdf-writer = { path = "../pdf-writer" }
|
pdf-writer = { path = "../pdf-writer" }
|
||||||
rustybuzz = { git = "https://github.com/laurmaedje/rustybuzz" }
|
rustybuzz = { git = "https://github.com/laurmaedje/rustybuzz" }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive", "rc"] }
|
||||||
ttf-parser = "0.12"
|
ttf-parser = "0.12"
|
||||||
unicode-bidi = "0.3.5"
|
unicode-bidi = "0.3.5"
|
||||||
unicode-xid = "0.2"
|
unicode-xid = "0.2"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use std::cmp::Eq;
|
use std::cmp::Eq;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba};
|
use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba};
|
||||||
use miniz_oxide::deflate;
|
use miniz_oxide::deflate;
|
||||||
@ -26,13 +27,13 @@ use crate::layout::{Element, Fill, Frame, Shape};
|
|||||||
/// can be included in the PDF.
|
/// can be included in the PDF.
|
||||||
///
|
///
|
||||||
/// Returns the raw bytes making up the PDF document.
|
/// Returns the raw bytes making up the PDF document.
|
||||||
pub fn pdf(cache: &Cache, frames: &[Frame]) -> Vec<u8> {
|
pub fn pdf(cache: &Cache, frames: &[Rc<Frame>]) -> Vec<u8> {
|
||||||
PdfExporter::new(cache, frames).write()
|
PdfExporter::new(cache, frames).write()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PdfExporter<'a> {
|
struct PdfExporter<'a> {
|
||||||
writer: PdfWriter,
|
writer: PdfWriter,
|
||||||
frames: &'a [Frame],
|
frames: &'a [Rc<Frame>],
|
||||||
cache: &'a Cache,
|
cache: &'a Cache,
|
||||||
refs: Refs,
|
refs: Refs,
|
||||||
fonts: Remapper<FaceId>,
|
fonts: Remapper<FaceId>,
|
||||||
@ -40,7 +41,7 @@ struct PdfExporter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PdfExporter<'a> {
|
impl<'a> PdfExporter<'a> {
|
||||||
fn new(cache: &'a Cache, frames: &'a [Frame]) -> Self {
|
fn new(cache: &'a Cache, frames: &'a [Rc<Frame>]) -> Self {
|
||||||
let mut writer = PdfWriter::new(1, 7);
|
let mut writer = PdfWriter::new(1, 7);
|
||||||
writer.set_indent(2);
|
writer.set_indent(2);
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ impl<'a> PdfExporter<'a> {
|
|||||||
let mut alpha_masks = 0;
|
let mut alpha_masks = 0;
|
||||||
|
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
for (_, element) in &frame.elements {
|
for (_, element) in frame.elements() {
|
||||||
match *element {
|
match *element {
|
||||||
Element::Text(ref shaped) => fonts.insert(shaped.face_id),
|
Element::Text(ref shaped) => fonts.insert(shaped.face_id),
|
||||||
Element::Geometry(_, _) => {}
|
Element::Geometry(_, _) => {}
|
||||||
@ -143,7 +144,7 @@ impl<'a> PdfExporter<'a> {
|
|||||||
let mut size = Length::zero();
|
let mut size = Length::zero();
|
||||||
let mut fill: Option<Fill> = None;
|
let mut fill: Option<Fill> = None;
|
||||||
|
|
||||||
for (pos, element) in &page.elements {
|
for (pos, element) in page.elements() {
|
||||||
let x = pos.x.to_pt() as f32;
|
let x = pos.x.to_pt() as f32;
|
||||||
let y = (page.size.height - pos.y).to_pt() as f32;
|
let y = (page.size.height - pos.y).to_pt() as f32;
|
||||||
|
|
||||||
@ -496,12 +497,12 @@ struct FontRefs {
|
|||||||
impl Refs {
|
impl Refs {
|
||||||
const OBJECTS_PER_FONT: usize = 5;
|
const OBJECTS_PER_FONT: usize = 5;
|
||||||
|
|
||||||
fn new(frames: usize, fonts: usize, images: usize, alpha_masks: usize) -> Self {
|
fn new(pages: usize, fonts: usize, images: usize, alpha_masks: usize) -> Self {
|
||||||
let catalog = 1;
|
let catalog = 1;
|
||||||
let page_tree = catalog + 1;
|
let page_tree = catalog + 1;
|
||||||
let pages_start = page_tree + 1;
|
let pages_start = page_tree + 1;
|
||||||
let contents_start = pages_start + frames as i32;
|
let contents_start = pages_start + pages as i32;
|
||||||
let fonts_start = contents_start + frames as i32;
|
let fonts_start = contents_start + pages as i32;
|
||||||
let images_start = fonts_start + (Self::OBJECTS_PER_FONT * fonts) as i32;
|
let images_start = fonts_start + (Self::OBJECTS_PER_FONT * fonts) as i32;
|
||||||
let alpha_masks_start = images_start + images as i32;
|
let alpha_masks_start = images_start + images as i32;
|
||||||
let end = alpha_masks_start + alpha_masks as i32;
|
let end = alpha_masks_start + alpha_masks as i32;
|
||||||
|
@ -23,10 +23,11 @@ impl Layout for BackgroundNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let mut frames = self.child.layout(ctx, regions);
|
let mut frames = self.child.layout(ctx, regions);
|
||||||
|
|
||||||
for frame in &mut frames {
|
for frame in &mut frames {
|
||||||
|
let mut new = Frame::new(frame.size, frame.baseline);
|
||||||
|
|
||||||
let (point, shape) = match self.shape {
|
let (point, shape) = match self.shape {
|
||||||
BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)),
|
BackgroundShape::Rect => (Point::zero(), Shape::Rect(frame.size)),
|
||||||
BackgroundShape::Ellipse => {
|
BackgroundShape::Ellipse => {
|
||||||
@ -35,9 +36,13 @@ impl Layout for BackgroundNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let element = Element::Geometry(shape, self.fill);
|
let element = Element::Geometry(shape, self.fill);
|
||||||
frame.item.elements.insert(0, (point, element));
|
new.push(point, element);
|
||||||
}
|
|
||||||
|
|
||||||
|
let prev = std::mem::take(&mut frame.item);
|
||||||
|
new.push_frame(Point::zero(), prev);
|
||||||
|
|
||||||
|
*Rc::make_mut(&mut frame.item) = new;
|
||||||
|
}
|
||||||
frames
|
frames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ impl Layout for FixedNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let Regions { current, base, .. } = regions;
|
let Regions { current, base, .. } = regions;
|
||||||
let mut constraints = Constraints::new(regions.expand);
|
let mut constraints = Constraints::new(regions.expand);
|
||||||
constraints.set_base_using_linears(Spec::new(self.width, self.height), ®ions);
|
constraints.set_base_using_linears(Spec::new(self.width, self.height), ®ions);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{Constrained, Constraints};
|
use super::{Constrained, Constraints};
|
||||||
@ -14,37 +16,93 @@ pub struct Frame {
|
|||||||
/// The baseline of the frame measured from the top.
|
/// The baseline of the frame measured from the top.
|
||||||
pub baseline: Length,
|
pub baseline: Length,
|
||||||
/// The elements composing this layout.
|
/// The elements composing this layout.
|
||||||
pub elements: Vec<(Point, Element)>,
|
children: Vec<(Point, Child)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over all elements in a frame, alongside with their positions.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ElementIter<'a> {
|
||||||
|
stack: Vec<(usize, Point, &'a Frame)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ElementIter<'a> {
|
||||||
|
type Item = (Point, &'a Element);
|
||||||
|
|
||||||
|
/// Get the next element, if any.
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let (cursor, offset, frame) = self.stack.last_mut()?;
|
||||||
|
match frame.children.get(*cursor) {
|
||||||
|
Some((pos, Child::Frame(f))) => {
|
||||||
|
let new_offset = *offset + *pos;
|
||||||
|
self.stack.push((0, new_offset, f.as_ref()));
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
Some((pos, Child::Element(e))) => {
|
||||||
|
*cursor += 1;
|
||||||
|
Some((*offset + *pos, e))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.stack.pop();
|
||||||
|
if let Some((cursor, _, _)) = self.stack.last_mut() {
|
||||||
|
*cursor += 1;
|
||||||
|
}
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
/// Create a new, empty frame.
|
/// Create a new, empty frame.
|
||||||
pub fn new(size: Size, baseline: Length) -> Self {
|
pub fn new(size: Size, baseline: Length) -> Self {
|
||||||
assert!(size.is_finite());
|
assert!(size.is_finite());
|
||||||
Self { size, baseline, elements: vec![] }
|
Self { size, baseline, children: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an element at a position.
|
/// Add an element at a position in the foreground.
|
||||||
pub fn push(&mut self, pos: Point, element: Element) {
|
pub fn push(&mut self, pos: Point, element: Element) {
|
||||||
self.elements.push((pos, element));
|
self.children.push((pos, Child::Element(element)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an element at a position in the background.
|
||||||
|
pub fn prepend(&mut self, pos: Point, element: Element) {
|
||||||
|
self.children.insert(0, (pos, Child::Element(element)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a frame element.
|
||||||
|
pub fn push_frame(&mut self, pos: Point, subframe: Rc<Self>) {
|
||||||
|
self.children.push((pos, Child::Frame(subframe)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add all elements of another frame, placing them relative to the given
|
/// Add all elements of another frame, placing them relative to the given
|
||||||
/// position.
|
/// position.
|
||||||
pub fn push_frame(&mut self, pos: Point, subframe: Self) {
|
pub fn merge_frame(&mut self, pos: Point, subframe: Self) {
|
||||||
if pos == Point::zero() && self.elements.is_empty() {
|
if pos == Point::zero() && self.children.is_empty() {
|
||||||
self.elements = subframe.elements;
|
self.children = subframe.children;
|
||||||
} else {
|
} else {
|
||||||
for (subpos, element) in subframe.elements {
|
for (subpos, child) in subframe.children {
|
||||||
self.push(pos + subpos, element);
|
self.children.push((pos + subpos, child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps the frame with constraints.
|
/// Wraps the frame with constraints.
|
||||||
pub fn constrain(self, constraints: Constraints) -> Constrained<Self> {
|
pub fn constrain(self, constraints: Constraints) -> Constrained<Rc<Self>> {
|
||||||
Constrained { item: self, constraints }
|
Constrained { item: Rc::new(self), constraints }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over all elements in the frame and its children.
|
||||||
|
pub fn elements(&self) -> ElementIter {
|
||||||
|
ElementIter { stack: vec![(0, Point::zero(), self)] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A frame can contain multiple children: elements or other frames, complete
|
||||||
|
/// with their children.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum Child {
|
||||||
|
Element(Element),
|
||||||
|
Frame(Rc<Frame>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The building block frames are composed of.
|
/// The building block frames are composed of.
|
||||||
|
@ -32,7 +32,7 @@ impl Layout for GridNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
// Prepare grid layout by unifying content and gutter tracks.
|
// Prepare grid layout by unifying content and gutter tracks.
|
||||||
let mut layouter = GridLayouter::new(self, regions.clone());
|
let mut layouter = GridLayouter::new(self, regions.clone());
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ struct GridLayouter<'a> {
|
|||||||
/// Constraints for the active region.
|
/// Constraints for the active region.
|
||||||
constraints: Constraints,
|
constraints: Constraints,
|
||||||
/// Frames for finished regions.
|
/// Frames for finished regions.
|
||||||
finished: Vec<Constrained<Frame>>,
|
finished: Vec<Constrained<Rc<Frame>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produced by initial row layout, auto and linear rows are already finished,
|
/// Produced by initial row layout, auto and linear rows are already finished,
|
||||||
@ -314,7 +314,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout the grid row-by-row.
|
/// Layout the grid row-by-row.
|
||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Frame>> {
|
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
for y in 0 .. self.rows.len() {
|
for y in 0 .. self.rows.len() {
|
||||||
match self.rows[y] {
|
match self.rows[y] {
|
||||||
TrackSizing::Auto => {
|
TrackSizing::Auto => {
|
||||||
@ -497,7 +497,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let main = frame.size.get(self.main);
|
let main = frame.size.get(self.main);
|
||||||
output.push_frame(pos.to_point(self.main), frame);
|
output.merge_frame(pos.to_point(self.main), frame);
|
||||||
pos.main += main;
|
pos.main += main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ impl LayoutCache {
|
|||||||
where
|
where
|
||||||
F: FnMut(usize) -> bool,
|
F: FnMut(usize) -> bool,
|
||||||
{
|
{
|
||||||
self.frames.retain(|_, b| f(b.level));
|
self.frames.retain(|_, entry| f(entry.level));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Amount of items in the cache.
|
/// Amount of items in the cache.
|
||||||
@ -39,14 +39,14 @@ impl LayoutCache {
|
|||||||
/// Cached frames from past layouting.
|
/// Cached frames from past layouting.
|
||||||
pub struct FramesEntry {
|
pub struct FramesEntry {
|
||||||
/// The cached frames for a node.
|
/// The cached frames for a node.
|
||||||
pub frames: Vec<Constrained<Frame>>,
|
pub frames: Vec<Constrained<Rc<Frame>>>,
|
||||||
/// How nested the frame was in the context is was originally appearing in.
|
/// How nested the frame was in the context is was originally appearing in.
|
||||||
pub level: usize,
|
pub level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FramesEntry {
|
impl FramesEntry {
|
||||||
/// Checks if the cached [`Frame`] is valid for the given regions.
|
/// Checks if the cached [`Frame`] is valid for the given regions.
|
||||||
pub fn check(&self, mut regions: Regions) -> Option<Vec<Constrained<Frame>>> {
|
pub fn check(&self, mut regions: Regions) -> Option<Vec<Constrained<Rc<Frame>>>> {
|
||||||
for (i, frame) in self.frames.iter().enumerate() {
|
for (i, frame) in self.frames.iter().enumerate() {
|
||||||
if (i != 0 && !regions.next()) || !frame.constraints.check(®ions) {
|
if (i != 0 && !regions.next()) || !frame.constraints.check(®ions) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -23,6 +23,7 @@ pub use stack::*;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use fxhash::FxHasher64;
|
use fxhash::FxHasher64;
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ use crate::geom::*;
|
|||||||
use crate::loading::Loader;
|
use crate::loading::Loader;
|
||||||
|
|
||||||
/// Layout a tree into a collection of frames.
|
/// Layout a tree into a collection of frames.
|
||||||
pub fn layout(loader: &mut dyn Loader, cache: &mut Cache, tree: &Tree) -> Vec<Frame> {
|
pub fn layout(loader: &mut dyn Loader, cache: &mut Cache, tree: &Tree) -> Vec<Rc<Frame>> {
|
||||||
tree.layout(&mut LayoutContext { loader, cache, level: 0 })
|
tree.layout(&mut LayoutContext { loader, cache, level: 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ pub struct Tree {
|
|||||||
|
|
||||||
impl Tree {
|
impl Tree {
|
||||||
/// Layout the tree into a collection of frames.
|
/// Layout the tree into a collection of frames.
|
||||||
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
|
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Rc<Frame>> {
|
||||||
self.runs.iter().flat_map(|run| run.layout(ctx)).collect()
|
self.runs.iter().flat_map(|run| run.layout(ctx)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,7 +62,7 @@ pub struct PageRun {
|
|||||||
|
|
||||||
impl PageRun {
|
impl PageRun {
|
||||||
/// Layout the page run.
|
/// Layout the page run.
|
||||||
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
|
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Rc<Frame>> {
|
||||||
// When one of the lengths is infinite the page fits its content along
|
// When one of the lengths is infinite the page fits its content along
|
||||||
// that axis.
|
// that axis.
|
||||||
let Size { width, height } = self.size;
|
let Size { width, height } = self.size;
|
||||||
@ -97,7 +98,7 @@ impl Layout for AnyNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
ctx.level += 1;
|
ctx.level += 1;
|
||||||
let frames = ctx
|
let frames = ctx
|
||||||
.cache
|
.cache
|
||||||
@ -179,7 +180,7 @@ pub trait Layout {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>>;
|
) -> Vec<Constrained<Rc<Frame>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The context for layouting.
|
/// The context for layouting.
|
||||||
@ -188,7 +189,7 @@ pub struct LayoutContext<'a> {
|
|||||||
pub loader: &'a mut dyn Loader,
|
pub loader: &'a mut dyn Loader,
|
||||||
/// A cache for loaded fonts and artifacts from past layouting.
|
/// A cache for loaded fonts and artifacts from past layouting.
|
||||||
pub cache: &'a mut Cache,
|
pub cache: &'a mut Cache,
|
||||||
/// How deeply nested is the current layout tree position.
|
/// How deeply nested the current layout tree position is.
|
||||||
pub level: usize,
|
pub level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,21 +14,19 @@ impl Layout for PadNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let mut regions = regions.map(|size| size - self.padding.resolve(size).size());
|
let mut regions = regions.map(|size| size - self.padding.resolve(size).size());
|
||||||
|
|
||||||
let mut frames = self.child.layout(ctx, ®ions);
|
let mut frames = self.child.layout(ctx, ®ions);
|
||||||
|
|
||||||
for frame in &mut frames {
|
for frame in &mut frames {
|
||||||
let padded = solve(self.padding, frame.size);
|
let padded = solve(self.padding, frame.size);
|
||||||
let padding = self.padding.resolve(padded);
|
let padding = self.padding.resolve(padded);
|
||||||
let origin = Point::new(padding.left, padding.top);
|
let origin = Point::new(padding.left, padding.top);
|
||||||
|
|
||||||
frame.item.size = padded;
|
let mut new = Frame::new(padded, frame.baseline + origin.y);
|
||||||
frame.item.baseline += origin.y;
|
let prev = std::mem::take(&mut frame.item);
|
||||||
|
new.push_frame(origin, prev);
|
||||||
for (point, _) in &mut frame.item.elements {
|
|
||||||
*point += origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.constraints.mutate(padding.size() * -1.0);
|
frame.constraints.mutate(padding.size() * -1.0);
|
||||||
|
|
||||||
@ -40,8 +38,8 @@ impl Layout for PadNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
regions.next();
|
regions.next();
|
||||||
|
*Rc::make_mut(&mut frame.item) = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
frames
|
frames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ impl Layout for ParNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
// Collect all text into one string used for BiDi analysis.
|
// Collect all text into one string used for BiDi analysis.
|
||||||
let text = self.collect_text();
|
let text = self.collect_text();
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
self,
|
self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: Regions,
|
regions: Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let mut stack = LineStack::new(self.line_spacing, regions);
|
let mut stack = LineStack::new(self.line_spacing, regions);
|
||||||
|
|
||||||
// The current line attempt.
|
// The current line attempt.
|
||||||
@ -277,7 +277,7 @@ enum ParItem<'a> {
|
|||||||
/// A shaped text run with consistent direction.
|
/// A shaped text run with consistent direction.
|
||||||
Text(ShapedText<'a>, Align),
|
Text(ShapedText<'a>, Align),
|
||||||
/// A layouted child node.
|
/// A layouted child node.
|
||||||
Frame(Frame, Align),
|
Frame(Rc<Frame>, Align),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParItem<'_> {
|
impl ParItem<'_> {
|
||||||
@ -306,7 +306,7 @@ struct LineStack<'a> {
|
|||||||
regions: Regions,
|
regions: Regions,
|
||||||
size: Size,
|
size: Size,
|
||||||
lines: Vec<LineLayout<'a>>,
|
lines: Vec<LineLayout<'a>>,
|
||||||
finished: Vec<Constrained<Frame>>,
|
finished: Vec<Constrained<Rc<Frame>>>,
|
||||||
constraints: Constraints,
|
constraints: Constraints,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ impl<'a> LineStack<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset += frame.size.height + self.line_spacing;
|
offset += frame.size.height + self.line_spacing;
|
||||||
output.push_frame(pos, frame);
|
output.merge_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finished.push(output.constrain(self.constraints));
|
self.finished.push(output.constrain(self.constraints));
|
||||||
@ -367,7 +367,7 @@ impl<'a> LineStack<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the last region and return the built frames.
|
/// Finish the last region and return the built frames.
|
||||||
fn finish(mut self, ctx: &LayoutContext) -> Vec<Constrained<Frame>> {
|
fn finish(mut self, ctx: &LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
self.finish_region(ctx);
|
self.finish_region(ctx);
|
||||||
self.finished
|
self.finished
|
||||||
}
|
}
|
||||||
@ -504,7 +504,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
}
|
}
|
||||||
ParItem::Text(ref shaped, align) => {
|
ParItem::Text(ref shaped, align) => {
|
||||||
ruler = ruler.max(align);
|
ruler = ruler.max(align);
|
||||||
shaped.build(ctx)
|
Rc::new(shaped.build(ctx))
|
||||||
}
|
}
|
||||||
ParItem::Frame(ref frame, align) => {
|
ParItem::Frame(ref frame, align) => {
|
||||||
ruler = ruler.max(align);
|
ruler = ruler.max(align);
|
||||||
|
@ -32,7 +32,7 @@ impl Layout for StackNode {
|
|||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
StackLayouter::new(self, regions.clone()).layout(ctx)
|
StackLayouter::new(self, regions.clone()).layout(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,9 +64,9 @@ struct StackLayouter<'a> {
|
|||||||
constraints: Constraints,
|
constraints: Constraints,
|
||||||
/// Offset, alignment and frame for all children that fit into the current
|
/// Offset, alignment and frame for all children that fit into the current
|
||||||
/// region. The exact positions are not known yet.
|
/// region. The exact positions are not known yet.
|
||||||
frames: Vec<(Length, Gen<Align>, Frame)>,
|
frames: Vec<(Length, Gen<Align>, Rc<Frame>)>,
|
||||||
/// Finished frames for previous regions.
|
/// Finished frames for previous regions.
|
||||||
finished: Vec<Constrained<Frame>>,
|
finished: Vec<Constrained<Rc<Frame>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StackLayouter<'a> {
|
impl<'a> StackLayouter<'a> {
|
||||||
@ -98,7 +98,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout all children.
|
/// Layout all children.
|
||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Frame>> {
|
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
for child in &self.stack.children {
|
for child in &self.stack.children {
|
||||||
match *child {
|
match *child {
|
||||||
StackChild::Spacing(amount) => self.space(amount),
|
StackChild::Spacing(amount) => self.space(amount),
|
||||||
@ -133,7 +133,7 @@ impl<'a> StackLayouter<'a> {
|
|||||||
|
|
||||||
/// Push a frame into the current or next fitting region, finishing regions
|
/// Push a frame into the current or next fitting region, finishing regions
|
||||||
/// if necessary.
|
/// if necessary.
|
||||||
fn push_frame(&mut self, frame: Frame, aligns: Gen<Align>) {
|
fn push_frame(&mut self, frame: Rc<Frame>, aligns: Gen<Align>) {
|
||||||
let size = frame.size.to_gen(self.main);
|
let size = frame.size.to_gen(self.main);
|
||||||
|
|
||||||
// Don't allow `Start` after `End` in the same region.
|
// Don't allow `Start` after `End` in the same region.
|
||||||
|
@ -83,7 +83,7 @@ pub fn typeset(
|
|||||||
src: &str,
|
src: &str,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
state: State,
|
state: State,
|
||||||
) -> Pass<Vec<Frame>> {
|
) -> Pass<Vec<Rc<Frame>>> {
|
||||||
let parsed = parse::parse(src);
|
let parsed = parse::parse(src);
|
||||||
let evaluated = eval::eval(loader, cache, path, Rc::new(parsed.output), scope);
|
let evaluated = eval::eval(loader, cache, path, Rc::new(parsed.output), scope);
|
||||||
let executed = exec::exec(&evaluated.output.template, state);
|
let executed = exec::exec(&evaluated.output.template, state);
|
||||||
|
@ -58,7 +58,7 @@ impl Layout for ImageNode {
|
|||||||
&self,
|
&self,
|
||||||
_: &mut LayoutContext,
|
_: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Frame>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let Regions { current, base, .. } = regions;
|
let Regions { current, base, .. } = regions;
|
||||||
let mut constraints = Constraints::new(regions.expand);
|
let mut constraints = Constraints::new(regions.expand);
|
||||||
constraints.set_base_using_linears(Spec::new(self.width, self.height), regions);
|
constraints.set_base_using_linears(Spec::new(self.width, self.height), regions);
|
||||||
|
@ -208,7 +208,7 @@ fn test_part(
|
|||||||
i: usize,
|
i: usize,
|
||||||
compare_ref: bool,
|
compare_ref: bool,
|
||||||
lines: u32,
|
lines: u32,
|
||||||
) -> (bool, bool, Vec<Frame>) {
|
) -> (bool, bool, Vec<Rc<Frame>>) {
|
||||||
let map = LineMap::new(src);
|
let map = LineMap::new(src);
|
||||||
let (local_compare_ref, ref_diags) = parse_metadata(src, &map);
|
let (local_compare_ref, ref_diags) = parse_metadata(src, &map);
|
||||||
let compare_ref = local_compare_ref.unwrap_or(compare_ref);
|
let compare_ref = local_compare_ref.unwrap_or(compare_ref);
|
||||||
@ -345,7 +345,7 @@ fn print_diag(diag: &Diag, map: &LineMap, lines: u32) {
|
|||||||
println!("{}: {}-{}: {}", diag.level, start, end, diag.message);
|
println!("{}: {}-{}: {}", diag.level, start, end, diag.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(cache: &Cache, frames: &[Frame], dpi: f32) -> Pixmap {
|
fn draw(cache: &Cache, frames: &[Rc<Frame>], dpi: f32) -> Pixmap {
|
||||||
let pad = Length::pt(5.0);
|
let pad = Length::pt(5.0);
|
||||||
|
|
||||||
let height = pad + frames.iter().map(|l| l.size.height + pad).sum::<Length>();
|
let height = pad + frames.iter().map(|l| l.size.height + pad).sum::<Length>();
|
||||||
@ -381,8 +381,8 @@ fn draw(cache: &Cache, frames: &[Frame], dpi: f32) -> Pixmap {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (pos, element) in &frame.elements {
|
for (pos, element) in frame.elements() {
|
||||||
let global = origin + *pos;
|
let global = origin + pos;
|
||||||
let x = global.x.to_pt() as f32;
|
let x = global.x.to_pt() as f32;
|
||||||
let y = global.y.to_pt() as f32;
|
let y = global.y.to_pt() as f32;
|
||||||
let ts = ts.pre_translate(x, y);
|
let ts = ts.pre_translate(x, y);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user