From 8a88f71cb11565c1a78bd57f02a8df17cb2bf7a0 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 23 Nov 2021 22:04:08 +0100 Subject: [PATCH] Transformations --- Cargo.toml | 2 +- src/export/pdf.rs | 650 ++++++++++++++++----------------- src/frame.rs | 64 ++-- src/geom/mod.rs | 2 + src/geom/point.rs | 18 + src/geom/relative.rs | 10 + src/geom/transform.rs | 73 ++++ src/layout/mod.rs | 30 +- src/library/image.rs | 18 +- src/library/mod.rs | 8 +- src/library/par.rs | 2 +- src/library/placed.rs | 5 +- src/library/shape.rs | 21 +- src/library/sized.rs | 10 +- src/library/transform.rs | 66 +++- tests/ref/layout/move.png | Bin 693 -> 0 bytes tests/ref/layout/transform.png | Bin 0 -> 54558 bytes tests/ref/text/links.png | Bin 9303 -> 10708 bytes tests/typ/layout/move.typ | 11 - tests/typ/layout/transform.typ | 49 +++ tests/typ/text/links.typ | 6 + tests/typeset.rs | 17 +- 22 files changed, 620 insertions(+), 442 deletions(-) create mode 100644 src/geom/transform.rs delete mode 100644 tests/ref/layout/move.png create mode 100644 tests/ref/layout/transform.png delete mode 100644 tests/typ/layout/move.typ create mode 100644 tests/typ/layout/transform.typ diff --git a/Cargo.toml b/Cargo.toml index bec1306fa..88a15742b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ fxhash = "0.2.1" image = { version = "0.23", default-features = false, features = ["png", "jpeg"] } itertools = "0.10" miniz_oxide = "0.4" -pdf-writer = { git = "https://github.com/typst/pdf-writer", rev = "f446079" } +pdf-writer = { git = "https://github.com/typst/pdf-writer", rev = "27b207a" } rustybuzz = "0.4" serde = { version = "1", features = ["derive", "rc"] } ttf-parser = "0.12" diff --git a/src/export/pdf.rs b/src/export/pdf.rs index b12ee7716..7de34905c 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -15,7 +15,7 @@ use ttf_parser::{name_id, GlyphId, Tag}; use super::subset; use crate::font::{find_name, FaceId, FontStore}; use crate::frame::{Element, Frame, Geometry, Group, Shape, Stroke, Text}; -use crate::geom::{self, Color, Em, Length, Paint, Size}; +use crate::geom::{self, Color, Em, Length, Paint, Point, Size, Transform}; use crate::image::{Image, ImageId, ImageStore}; use crate::Context; @@ -27,144 +27,63 @@ use crate::Context; /// /// Returns the raw bytes making up the PDF file. pub fn pdf(ctx: &Context, frames: &[Rc]) -> Vec { - PdfExporter::new(ctx, frames).write() + PdfExporter::new(ctx).export(frames) } +/// An exporter for a whole PDF document. struct PdfExporter<'a> { - writer: PdfWriter, - refs: Refs, - frames: &'a [Rc], fonts: &'a FontStore, images: &'a ImageStore, - font_map: Remapper, + writer: PdfWriter, + alloc: Ref, + pages: Vec, + face_map: Remapper, + face_refs: Vec, + glyph_sets: HashMap>, image_map: Remapper, - glyphs: HashMap>, + image_refs: Vec, } impl<'a> PdfExporter<'a> { - fn new(ctx: &'a Context, frames: &'a [Rc]) -> Self { - let mut font_map = Remapper::new(); - let mut image_map = Remapper::new(); - let mut glyphs = HashMap::>::new(); - let mut alpha_masks = 0; - - for frame in frames { - for (_, element) in frame.elements() { - match *element { - Element::Text(ref text) => { - font_map.insert(text.face_id); - let set = glyphs.entry(text.face_id).or_default(); - set.extend(text.glyphs.iter().map(|g| g.id)); - } - Element::Image(id, _) => { - let img = ctx.images.get(id); - if img.buf.color().has_alpha() { - alpha_masks += 1; - } - image_map.insert(id); - } - _ => {} - } - } - } - + fn new(ctx: &'a Context) -> Self { Self { - writer: PdfWriter::new(), - refs: Refs::new(frames.len(), font_map.len(), image_map.len(), alpha_masks), - frames, fonts: &ctx.fonts, images: &ctx.images, - glyphs, - font_map, - image_map, + writer: PdfWriter::new(), + alloc: Ref::new(1), + pages: vec![], + face_map: Remapper::new(), + face_refs: vec![], + glyph_sets: HashMap::new(), + image_map: Remapper::new(), + image_refs: vec![], } } - fn write(mut self) -> Vec { - self.write_structure(); - self.write_pages(); + fn export(mut self, frames: &[Rc]) -> Vec { + self.build_pages(frames); self.write_fonts(); self.write_images(); - self.writer.finish(self.refs.catalog) + self.write_structure() } - fn write_structure(&mut self) { - // The document catalog. - self.writer.catalog(self.refs.catalog).pages(self.refs.page_tree); - - // The root page tree. - let mut pages = self.writer.pages(self.refs.page_tree); - pages.kids(self.refs.pages()); - - let mut resources = pages.resources(); - let mut fonts = resources.fonts(); - for (refs, f) in self.refs.fonts().zip(self.font_map.pdf_indices()) { - let name = format_eco!("F{}", f); - fonts.pair(Name(name.as_bytes()), refs.type0_font); + fn build_pages(&mut self, frames: &[Rc]) { + for frame in frames { + let page = PageExporter::new(self).export(frame); + self.pages.push(page); } - - fonts.finish(); - - let mut images = resources.x_objects(); - for (id, im) in self.refs.images().zip(self.image_map.pdf_indices()) { - let name = format_eco!("Im{}", im); - images.pair(Name(name.as_bytes()), id); - } - - images.finish(); - resources.finish(); - pages.finish(); - - // The page objects (non-root nodes in the page tree). - for ((page_id, content_id), page) in - self.refs.pages().zip(self.refs.contents()).zip(self.frames) - { - let w = page.size.w.to_f32(); - let h = page.size.h.to_f32(); - - let mut page_writer = self.writer.page(page_id); - page_writer - .parent(self.refs.page_tree) - .media_box(Rect::new(0.0, 0.0, w, h)); - - let mut annotations = page_writer.annotations(); - for (pos, element) in page.elements() { - if let Element::Link(href, size) = element { - let x = pos.x.to_f32(); - let y = (page.size.h - pos.y).to_f32(); - let w = size.w.to_f32(); - let h = size.h.to_f32(); - - annotations - .push() - .subtype(AnnotationType::Link) - .rect(Rect::new(x, y - h, x + w, y)) - .action() - .action_type(ActionType::Uri) - .uri(Str(href.as_bytes())); - } - } - - annotations.finish(); - page_writer.contents(content_id); - } - } - - fn write_pages(&mut self) { - for (id, page) in self.refs.contents().zip(self.frames) { - self.write_page(id, page); - } - } - - fn write_page(&mut self, id: Ref, page: &'a Frame) { - let writer = PageExporter::new(self); - let content = writer.write(page); - self.writer.stream(id, &deflate(&content)).filter(Filter::FlateDecode); } fn write_fonts(&mut self) { - for (refs, face_id) in self.refs.fonts().zip(self.font_map.layout_indices()) { - let glyphs = &self.glyphs[&face_id]; + for face_id in self.face_map.layout_indices() { + let type0_ref = self.alloc.bump(); + let cid_ref = self.alloc.bump(); + let descriptor_ref = self.alloc.bump(); + let cmap_ref = self.alloc.bump(); + let data_ref = self.alloc.bump(); + self.face_refs.push(type0_ref); + + let glyphs = &self.glyph_sets[&face_id]; let face = self.fonts.get(face_id); let ttf = face.ttf(); @@ -182,11 +101,11 @@ impl<'a> PdfExporter<'a> { // Write the base font object referencing the CID font. self.writer - .type0_font(refs.type0_font) + .type0_font(type0_ref) .base_font(base_font) .encoding_predefined(Name(b"Identity-H")) - .descendant_font(refs.cid_font) - .to_unicode(refs.cmap); + .descendant_font(cid_ref) + .to_unicode(cmap_ref); // Check for the presence of CFF outlines to select the correct // CID-Font subtype. @@ -200,10 +119,10 @@ impl<'a> PdfExporter<'a> { // Write the CID font referencing the font descriptor. self.writer - .cid_font(refs.cid_font, subtype) + .cid_font(cid_ref, subtype) .base_font(base_font) .system_info(system_info) - .font_descriptor(refs.font_descriptor) + .font_descriptor(descriptor_ref) .cid_to_gid_map_predefined(Name(b"Identity")) .widths() .individual(0, { @@ -237,7 +156,7 @@ impl<'a> PdfExporter<'a> { // Write the font descriptor (contains metrics about the font). self.writer - .font_descriptor(refs.font_descriptor) + .font_descriptor(descriptor_ref) .font_name(base_font) .font_flags(flags) .font_bbox(bbox) @@ -246,7 +165,7 @@ impl<'a> PdfExporter<'a> { .descent(descender) .cap_height(cap_height) .stem_v(stem_v) - .font_file2(refs.data); + .font_file2(data_ref); // Compute a reverse mapping from glyphs to unicode. let cmap = { @@ -275,7 +194,7 @@ impl<'a> PdfExporter<'a> { // Write the /ToUnicode character map, which maps glyph ids back to // unicode codepoints to enable copying out of the PDF. self.writer - .cmap(refs.cmap, &deflate(&cmap.finish())) + .cmap(cmap_ref, &deflate(&cmap.finish())) .filter(Filter::FlateDecode); // Subset and write the face's bytes. @@ -283,21 +202,23 @@ impl<'a> PdfExporter<'a> { let subsetted = subset(buffer, face.index(), glyphs); let data = subsetted.as_deref().unwrap_or(buffer); self.writer - .stream(refs.data, &deflate(data)) + .stream(data_ref, &deflate(data)) .filter(Filter::FlateDecode); } } fn write_images(&mut self) { - let mut masks_seen = 0; + for image_id in self.image_map.layout_indices() { + let image_ref = self.alloc.bump(); + self.image_refs.push(image_ref); - for (id, image_id) in self.refs.images().zip(self.image_map.layout_indices()) { let img = self.images.get(image_id); - let (width, height) = img.buf.dimensions(); + let width = img.width(); + let height = img.height(); // Add the primary image. if let Ok((data, filter, color_space)) = encode_image(img) { - let mut image = self.writer.image(id, &data); + let mut image = self.writer.image(image_ref, &data); image.filter(filter); image.width(width as i32); image.height(height as i32); @@ -308,23 +229,21 @@ impl<'a> PdfExporter<'a> { // this image has an alpha channel. if img.buf.color().has_alpha() { let (alpha_data, alpha_filter) = encode_alpha(img); - let mask_id = self.refs.alpha_mask(masks_seen); - image.s_mask(mask_id); + let mask_ref = self.alloc.bump(); + image.s_mask(mask_ref); image.finish(); - let mut mask = self.writer.image(mask_id, &alpha_data); + let mut mask = self.writer.image(mask_ref, &alpha_data); mask.filter(alpha_filter); mask.width(width as i32); mask.height(height as i32); mask.color_space(ColorSpace::DeviceGray); mask.bits_per_component(8); - - masks_seen += 1; } } else { // TODO: Warn that image could not be encoded. self.writer - .image(id, &[]) + .image(image_ref, &[]) .width(0) .height(0) .color_space(ColorSpace::DeviceGray) @@ -332,117 +251,180 @@ impl<'a> PdfExporter<'a> { } } } + + fn write_structure(mut self) -> Vec { + // The root page tree. + let page_tree_ref = self.alloc.bump(); + + // The page objects (non-root nodes in the page tree). + let mut page_refs = vec![]; + for page in self.pages { + let page_id = self.alloc.bump(); + let content_id = self.alloc.bump(); + page_refs.push(page_id); + + let mut page_writer = self.writer.page(page_id); + page_writer.parent(page_tree_ref); + + let w = page.size.w.to_f32(); + let h = page.size.h.to_f32(); + page_writer.media_box(Rect::new(0.0, 0.0, w, h)); + page_writer.contents(content_id); + + let mut annotations = page_writer.annotations(); + for (url, rect) in page.links { + annotations + .push() + .subtype(AnnotationType::Link) + .rect(rect) + .action() + .action_type(ActionType::Uri) + .uri(Str(url.as_bytes())); + } + + annotations.finish(); + page_writer.finish(); + + self.writer + .stream(content_id, &deflate(&page.content.finish())) + .filter(Filter::FlateDecode); + } + + let mut pages = self.writer.pages(page_tree_ref); + pages.kids(page_refs); + + let mut resources = pages.resources(); + let mut fonts = resources.fonts(); + for (font_ref, f) in self.face_map.pdf_indices(&self.face_refs) { + let name = format_eco!("F{}", f); + fonts.pair(Name(name.as_bytes()), font_ref); + } + + fonts.finish(); + + let mut images = resources.x_objects(); + for (image_ref, im) in self.image_map.pdf_indices(&self.image_refs) { + let name = format_eco!("Im{}", im); + images.pair(Name(name.as_bytes()), image_ref); + } + + images.finish(); + resources.finish(); + pages.finish(); + + // The document catalog. + let catalog_ref = self.alloc.bump(); + self.writer.catalog(catalog_ref).pages(page_tree_ref); + self.writer.finish(catalog_ref) + } } -/// A writer for the contents of a single page. +/// An exporter for the contents of a single PDF page. struct PageExporter<'a> { fonts: &'a FontStore, - font_map: &'a Remapper, - image_map: &'a Remapper, + font_map: &'a mut Remapper, + image_map: &'a mut Remapper, + glyphs: &'a mut HashMap>, + bottom: f32, content: Content, - in_text_state: bool, - face_id: Option, - font_size: Length, - font_fill: Option, + links: Vec<(String, Rect)>, + state: State, + saves: Vec, +} + +/// Data for an exported page. +struct Page { + size: Size, + content: Content, + links: Vec<(String, Rect)>, +} + +/// A simulated graphics state used to deduplicate graphics state changes and +/// keep track of the current transformation matrix for link annotations. +#[derive(Debug, Default, Clone)] +struct State { + transform: Transform, + fill: Option, + stroke: Option, + font: Option<(FaceId, Length)>, } impl<'a> PageExporter<'a> { - /// Create a new page exporter. - fn new(exporter: &'a PdfExporter) -> Self { + fn new(exporter: &'a mut PdfExporter) -> Self { Self { fonts: exporter.fonts, - font_map: &exporter.font_map, - image_map: &exporter.image_map, + font_map: &mut exporter.face_map, + image_map: &mut exporter.image_map, + glyphs: &mut exporter.glyph_sets, + bottom: 0.0, content: Content::new(), - in_text_state: false, - face_id: None, - font_size: Length::zero(), - font_fill: None, + links: vec![], + state: State::default(), + saves: vec![], } } - /// Write the page frame into the content stream. - fn write(mut self, frame: &Frame) -> Vec { - self.write_frame(0.0, frame.size.h.to_f32(), frame); - self.content.finish() + fn export(mut self, frame: &Frame) -> Page { + // Make the coordinate system start at the top-left. + self.bottom = frame.size.h.to_f32(); + self.content.transform([1.0, 0.0, 0.0, -1.0, 0.0, self.bottom]); + self.write_frame(&frame); + Page { + size: frame.size, + content: self.content, + links: self.links, + } } - /// Write a frame into the content stream. - fn write_frame(&mut self, x: f32, y: f32, frame: &Frame) { - for (offset, element) in &frame.elements { - // Make sure the content stream is in the correct state. - match element { - Element::Text(_) if !self.in_text_state => { - self.content.begin_text(); - self.in_text_state = true; - } - - Element::Shape(_) | Element::Image(..) if self.in_text_state => { - self.content.end_text(); - self.in_text_state = false; - } - - _ => {} - } - - let x = x + offset.x.to_f32(); - let y = y - offset.y.to_f32(); - + fn write_frame(&mut self, frame: &Frame) { + for &(pos, ref element) in &frame.elements { + let x = pos.x.to_f32(); + let y = pos.y.to_f32(); match *element { - Element::Group(ref group) => self.write_group(x, y, group), + Element::Group(ref group) => self.write_group(pos, group), Element::Text(ref text) => self.write_text(x, y, text), Element::Shape(ref shape) => self.write_shape(x, y, shape), Element::Image(id, size) => self.write_image(x, y, id, size), - Element::Link(_, _) => {} + Element::Link(ref url, size) => self.write_link(pos, url, size), } } - - if self.in_text_state { - self.content.end_text(); - } } - fn write_group(&mut self, x: f32, y: f32, group: &Group) { + fn write_group(&mut self, pos: Point, group: &Group) { + let translation = Transform::translation(pos.x, pos.y); + + self.save_state(); + self.transform(translation.pre_concat(group.transform)); + if group.clips { let w = group.frame.size.w.to_f32(); let h = group.frame.size.h.to_f32(); - self.content.save_state(); - self.content.move_to(x, y); - self.content.line_to(x + w, y); - self.content.line_to(x + w, y - h); - self.content.line_to(x, y - h); + self.content.move_to(0.0, 0.0); + self.content.line_to(w, 0.0); + self.content.line_to(w, h); + self.content.line_to(0.0, h); self.content.clip_nonzero(); self.content.end_path(); } - self.write_frame(x, y, &group.frame); - - if group.clips { - self.content.restore_state(); - } + self.write_frame(&group.frame); + self.restore_state(); } - /// Write a glyph run into the content stream. fn write_text(&mut self, x: f32, y: f32, text: &Text) { - if self.font_fill != Some(text.fill) { - self.write_fill(text.fill); - self.font_fill = Some(text.fill); - } + self.glyphs + .entry(text.face_id) + .or_default() + .extend(text.glyphs.iter().map(|g| g.id)); - // Then, also check if we need to issue a font switching - // action. - if self.face_id != Some(text.face_id) || self.font_size != text.size { - self.face_id = Some(text.face_id); - self.font_size = text.size; - - let name = format_eco!("F{}", self.font_map.map(text.face_id)); - self.content.set_font(Name(name.as_bytes()), text.size.to_f32()); - } + self.content.begin_text(); + self.set_font(text.face_id, text.size); + self.set_fill(text.fill); let face = self.fonts.get(text.face_id); // Position the text. - self.content.set_text_matrix([1.0, 0.0, 0.0, 1.0, x, y]); + self.content.set_text_matrix([1.0, 0.0, 0.0, -1.0, x, y]); let mut positioned = self.content.show_positioned(); let mut items = positioned.items(); @@ -476,9 +458,12 @@ impl<'a> PageExporter<'a> { if !encoded.is_empty() { items.show(Str(&encoded)); } + + items.finish(); + positioned.finish(); + self.content.end_text(); } - /// Write a geometrical shape into the content stream. fn write_shape(&mut self, x: f32, y: f32, shape: &Shape) { if shape.fill.is_none() && shape.stroke.is_none() { return; @@ -489,7 +474,7 @@ impl<'a> PageExporter<'a> { let w = size.w.to_f32(); let h = size.h.to_f32(); if w > 0.0 && h > 0.0 { - self.content.rect(x, y - h, w, h); + self.content.rect(x, y, w, h); } } Geometry::Ellipse(size) => { @@ -500,21 +485,19 @@ impl<'a> PageExporter<'a> { let dx = target.x.to_f32(); let dy = target.y.to_f32(); self.content.move_to(x, y); - self.content.line_to(x + dx, y - dy); + self.content.line_to(x + dx, y + dy); } Geometry::Path(ref path) => { self.write_path(x, y, path); } } - self.content.save_state(); - if let Some(fill) = shape.fill { - self.write_fill(fill); + self.set_fill(fill); } if let Some(stroke) = shape.stroke { - self.write_stroke(stroke); + self.set_stroke(stroke); } match (shape.fill, shape.stroke) { @@ -523,69 +506,124 @@ impl<'a> PageExporter<'a> { (None, Some(_)) => self.content.stroke(), (Some(_), Some(_)) => self.content.fill_nonzero_and_stroke(), }; - - self.content.restore_state(); } - /// Write an image into the content stream. - fn write_image(&mut self, x: f32, y: f32, id: ImageId, size: Size) { - let name = format!("Im{}", self.image_map.map(id)); - let w = size.w.to_f32(); - let h = size.h.to_f32(); - self.content.save_state(); - self.content.concat_matrix([w, 0.0, 0.0, h, x, y - h]); - self.content.x_object(Name(name.as_bytes())); - self.content.restore_state(); - } - - /// Write a path into a content stream. fn write_path(&mut self, x: f32, y: f32, path: &geom::Path) { for elem in &path.0 { match elem { geom::PathElement::MoveTo(p) => { - self.content.move_to(x + p.x.to_f32(), y - p.y.to_f32()) + self.content.move_to(x + p.x.to_f32(), y + p.y.to_f32()) } geom::PathElement::LineTo(p) => { - self.content.line_to(x + p.x.to_f32(), y - p.y.to_f32()) + self.content.line_to(x + p.x.to_f32(), y + p.y.to_f32()) } geom::PathElement::CubicTo(p1, p2, p3) => self.content.cubic_to( x + p1.x.to_f32(), - y - p1.y.to_f32(), + y + p1.y.to_f32(), x + p2.x.to_f32(), - y - p2.y.to_f32(), + y + p2.y.to_f32(), x + p3.x.to_f32(), - y - p3.y.to_f32(), + y + p3.y.to_f32(), ), geom::PathElement::ClosePath => self.content.close_path(), }; } } - /// Write a fill change into a content stream. - fn write_fill(&mut self, fill: Paint) { - let Paint::Solid(Color::Rgba(c)) = fill; - self.content.set_fill_rgb( - c.r as f32 / 255.0, - c.g as f32 / 255.0, - c.b as f32 / 255.0, - ); + fn write_image(&mut self, x: f32, y: f32, id: ImageId, size: Size) { + self.image_map.insert(id); + let name = format_eco!("Im{}", self.image_map.map(id)); + let w = size.w.to_f32(); + let h = size.h.to_f32(); + self.content.save_state(); + self.content.transform([w, 0.0, 0.0, -h, x, y + h]); + self.content.x_object(Name(name.as_bytes())); + self.content.restore_state(); } - /// Write a stroke change into a content stream. - fn write_stroke(&mut self, stroke: Stroke) { - let Paint::Solid(Color::Rgba(c)) = stroke.paint; - self.content.set_stroke_rgb( - c.r as f32 / 255.0, - c.g as f32 / 255.0, - c.b as f32 / 255.0, - ); - self.content.set_line_width(stroke.thickness.to_f32()); + fn write_link(&mut self, pos: Point, url: &str, size: Size) { + let mut min_x = Length::inf(); + let mut min_y = Length::inf(); + let mut max_x = -Length::inf(); + let mut max_y = -Length::inf(); + + // Compute the bounding box of the transformed link. + for point in [ + pos, + pos + Point::with_x(size.w), + pos + Point::with_y(size.h), + pos + size.to_point(), + ] { + let t = point.transform(self.state.transform); + min_x.set_min(t.x); + min_y.set_min(t.y); + max_x.set_max(t.x); + max_y.set_max(t.y); + } + + let x1 = min_x.to_f32(); + let x2 = max_x.to_f32(); + let y1 = self.bottom - max_y.to_f32(); + let y2 = self.bottom - min_y.to_f32(); + let rect = Rect::new(x1, y1, x2, y2); + self.links.push((url.to_string(), rect)); + } + + fn save_state(&mut self) { + self.saves.push(self.state.clone()); + self.content.save_state(); + } + + fn restore_state(&mut self) { + self.content.restore_state(); + self.state = self.saves.pop().expect("missing state save"); + } + + fn transform(&mut self, transform: Transform) { + let Transform { sx, ky, kx, sy, tx, ty } = transform; + self.state.transform = self.state.transform.pre_concat(transform); + self.content.transform([ + sx.get() as f32, + ky.get() as f32, + kx.get() as f32, + sy.get() as f32, + tx.to_f32(), + ty.to_f32(), + ]); + } + + fn set_font(&mut self, face_id: FaceId, size: Length) { + if self.state.font != Some((face_id, size)) { + self.font_map.insert(face_id); + let name = format_eco!("F{}", self.font_map.map(face_id)); + self.content.set_font(Name(name.as_bytes()), size.to_f32()); + } + } + + fn set_fill(&mut self, fill: Paint) { + if self.state.fill != Some(fill) { + let Paint::Solid(Color::Rgba(c)) = fill; + self.content.set_fill_rgb( + c.r as f32 / 255.0, + c.g as f32 / 255.0, + c.b as f32 / 255.0, + ); + } + } + + fn set_stroke(&mut self, stroke: Stroke) { + if self.state.stroke != Some(stroke) { + let Paint::Solid(Color::Rgba(c)) = stroke.paint; + self.content.set_stroke_rgb( + c.r as f32 / 255.0, + c.g as f32 / 255.0, + c.b as f32 / 255.0, + ); + self.content.set_line_width(stroke.thickness.to_f32()); + } } } -/// The compression level for the deflating. -const DEFLATE_LEVEL: u8 = 6; - /// Encode an image with a suitable filter. /// /// Skips the alpha channel as that's encoded separately. @@ -637,86 +675,11 @@ fn encode_alpha(img: &Image) -> (Vec, Filter) { /// Compress data with the DEFLATE algorithm. fn deflate(data: &[u8]) -> Vec { - miniz_oxide::deflate::compress_to_vec_zlib(data, DEFLATE_LEVEL) + const COMPRESSION_LEVEL: u8 = 6; + miniz_oxide::deflate::compress_to_vec_zlib(data, COMPRESSION_LEVEL) } -/// We need to know exactly which indirect reference id will be used for which -/// objects up-front to correctly declare the document catalogue, page tree and -/// so on. These offsets are computed in the beginning and stored here. -struct Refs { - catalog: Ref, - page_tree: Ref, - pages_start: i32, - contents_start: i32, - fonts_start: i32, - images_start: i32, - alpha_masks_start: i32, - end: i32, -} - -struct FontRefs { - type0_font: Ref, - cid_font: Ref, - font_descriptor: Ref, - cmap: Ref, - data: Ref, -} - -impl Refs { - const OBJECTS_PER_FONT: usize = 5; - - fn new(pages: usize, fonts: usize, images: usize, alpha_masks: usize) -> Self { - let catalog = 1; - let page_tree = catalog + 1; - let pages_start = page_tree + 1; - let contents_start = pages_start + pages as i32; - let fonts_start = contents_start + pages as i32; - let images_start = fonts_start + (Self::OBJECTS_PER_FONT * fonts) as i32; - let alpha_masks_start = images_start + images as i32; - let end = alpha_masks_start + alpha_masks as i32; - - Self { - catalog: Ref::new(catalog), - page_tree: Ref::new(page_tree), - pages_start, - contents_start, - fonts_start, - images_start, - alpha_masks_start, - end, - } - } - - fn pages(&self) -> impl Iterator { - (self.pages_start .. self.contents_start).map(Ref::new) - } - - fn contents(&self) -> impl Iterator { - (self.contents_start .. self.images_start).map(Ref::new) - } - - fn fonts(&self) -> impl Iterator { - (self.fonts_start .. self.images_start) - .step_by(Self::OBJECTS_PER_FONT) - .map(|id| FontRefs { - type0_font: Ref::new(id), - cid_font: Ref::new(id + 1), - font_descriptor: Ref::new(id + 2), - cmap: Ref::new(id + 3), - data: Ref::new(id + 4), - }) - } - - fn images(&self) -> impl Iterator { - (self.images_start .. self.end).map(Ref::new) - } - - fn alpha_mask(&self, i: usize) -> Ref { - Ref::new(self.alpha_masks_start + i as i32) - } -} - -/// Used to assign new, consecutive PDF-internal indices to things. +/// Assigns new, consecutive PDF-internal indices to things. struct Remapper { /// Forwards from the old indices to the new pdf indices. to_pdf: HashMap, @@ -735,10 +698,6 @@ where } } - fn len(&self) -> usize { - self.to_layout.len() - } - fn insert(&mut self, index: Index) { let to_layout = &mut self.to_layout; self.to_pdf.entry(index).or_insert_with(|| { @@ -752,8 +711,11 @@ where self.to_pdf[&index] } - fn pdf_indices(&self) -> impl Iterator { - 0 .. self.to_pdf.len() + fn pdf_indices<'a>( + &'a self, + refs: &'a [Ref], + ) -> impl Iterator + 'a { + refs.iter().copied().zip(0 .. self.to_pdf.len()) } fn layout_indices(&self) -> impl Iterator + '_ { @@ -784,3 +746,17 @@ impl EmExt for Em { 1000.0 * self.get() as f32 } } + +/// Additional methods for [`Ref`]. +trait RefExt { + /// Bump the reference up by one and return the previous one. + fn bump(&mut self) -> Self; +} + +impl RefExt for Ref { + fn bump(&mut self) -> Self { + let prev = *self; + *self = Self::new(prev.get() + 1); + prev + } +} diff --git a/src/frame.rs b/src/frame.rs index 7862e0054..5b1c36ce1 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; use crate::font::FaceId; -use crate::geom::{Em, Length, Paint, Path, Point, Size}; +use crate::geom::{Em, Length, Paint, Path, Point, Size, Transform}; use crate::image::ImageId; /// A finished layout with elements at fixed positions. @@ -40,8 +40,7 @@ impl Frame { /// Add a group element. pub fn push_frame(&mut self, pos: Point, frame: Rc) { - self.elements - .push((pos, Element::Group(Group { frame, clips: false }))) + self.elements.push((pos, Element::Group(Group::new(frame)))); } /// Add all elements of another frame, placing them relative to the given @@ -62,11 +61,6 @@ impl Frame { *point += offset; } } - - /// An iterator over all non-frame elements in this and nested frames. - pub fn elements(&self) -> Elements { - Elements { stack: vec![(0, Point::zero(), self)] } - } } impl Debug for Frame { @@ -87,35 +81,6 @@ impl Debug for Frame { } } -/// An iterator over all elements in a frame, alongside with their positions. -pub struct Elements<'a> { - stack: Vec<(usize, Point, &'a Frame)>, -} - -impl<'a> Iterator for Elements<'a> { - type Item = (Point, &'a Element); - - fn next(&mut self) -> Option { - let (cursor, offset, frame) = self.stack.last_mut()?; - if let Some((pos, e)) = frame.elements.get(*cursor) { - if let Element::Group(g) = e { - let new_offset = *offset + *pos; - self.stack.push((0, new_offset, g.frame.as_ref())); - self.next() - } else { - *cursor += 1; - Some((*offset + *pos, e)) - } - } else { - self.stack.pop(); - if let Some((cursor, _, _)) = self.stack.last_mut() { - *cursor += 1; - } - self.next() - } - } -} - /// The building block frames are composed of. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Element { @@ -136,10 +101,35 @@ pub enum Element { pub struct Group { /// The group's frame. pub frame: Rc, + /// A transformation to apply to the group. + pub transform: Transform, /// Whether the frame should be a clipping boundary. pub clips: bool, } +impl Group { + /// Create a new group with default settings. + pub fn new(frame: Rc) -> Self { + Self { + frame, + transform: Transform::identity(), + clips: false, + } + } + + /// Set the group's transform. + pub fn transform(mut self, transform: Transform) -> Self { + self.transform = transform; + self + } + + /// Set whether the group should be a clipping boundary. + pub fn clips(mut self, clips: bool) -> Self { + self.clips = clips; + self + } +} + /// A run of shaped text. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Text { diff --git a/src/geom/mod.rs b/src/geom/mod.rs index c763e8fa8..b0c75d25c 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -18,6 +18,7 @@ mod scalar; mod sides; mod size; mod spec; +mod transform; pub use align::*; pub use angle::*; @@ -35,6 +36,7 @@ pub use scalar::*; pub use sides::*; pub use size::*; pub use spec::*; +pub use transform::*; use std::cmp::Ordering; use std::f64::consts::PI; diff --git a/src/geom/point.rs b/src/geom/point.rs index 7c11e81bd..49e3018a6 100644 --- a/src/geom/point.rs +++ b/src/geom/point.rs @@ -25,6 +25,16 @@ impl Point { Self { x: value, y: value } } + /// Create a new point with y set to zero. + pub const fn with_x(x: Length) -> Self { + Self { x, y: Length::zero() } + } + + /// Create a new point with x set to zero. + pub const fn with_y(y: Length) -> Self { + Self { x: Length::zero(), y } + } + /// Convert to the generic representation. pub const fn to_gen(self, block: SpecAxis) -> Gen { match block { @@ -32,6 +42,14 @@ impl Point { SpecAxis::Vertical => Gen::new(self.x, self.y), } } + + /// Transform the point with the given transformation. + pub fn transform(self, transform: Transform) -> Self { + Self::new( + transform.sx.resolve(self.x) + transform.kx.resolve(self.y) + transform.tx, + transform.ky.resolve(self.x) + transform.sy.resolve(self.y) + transform.ty, + ) + } } impl Get for Point { diff --git a/src/geom/relative.rs b/src/geom/relative.rs index 463c5d46e..c894f4a5e 100644 --- a/src/geom/relative.rs +++ b/src/geom/relative.rs @@ -5,6 +5,7 @@ use super::*; /// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the /// corresponding [literal](crate::syntax::ast::LitKind::Percent). #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] pub struct Relative(Scalar); impl Relative { @@ -73,6 +74,14 @@ impl Add for Relative { sub_impl!(Relative - Relative -> Relative); +impl Mul for Relative { + type Output = Self; + + fn mul(self, other: Self) -> Self { + Self(self.0 * other.0) + } +} + impl Mul for Relative { type Output = Self; @@ -107,5 +116,6 @@ impl Div for Relative { assign_impl!(Relative += Relative); assign_impl!(Relative -= Relative); +assign_impl!(Relative *= Relative); assign_impl!(Relative *= f64); assign_impl!(Relative /= f64); diff --git a/src/geom/transform.rs b/src/geom/transform.rs new file mode 100644 index 000000000..ca44667b7 --- /dev/null +++ b/src/geom/transform.rs @@ -0,0 +1,73 @@ +use super::*; + +/// A scale-skew-translate transformation. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Transform { + pub sx: Relative, + pub ky: Relative, + pub kx: Relative, + pub sy: Relative, + pub tx: Length, + pub ty: Length, +} + +impl Transform { + /// The identity transformation. + pub const fn identity() -> Self { + Self { + sx: Relative::one(), + ky: Relative::zero(), + kx: Relative::zero(), + sy: Relative::one(), + tx: Length::zero(), + ty: Length::zero(), + } + } + + /// A translation transform. + pub const fn translation(tx: Length, ty: Length) -> Self { + Self { tx, ty, ..Self::identity() } + } + + /// A scaling transform. + pub const fn scaling(sx: Relative, sy: Relative) -> Self { + Self { sx, sy, ..Self::identity() } + } + + /// A rotation transform. + pub fn rotation(angle: Angle) -> Self { + let v = angle.to_rad(); + let cos = Relative::new(v.cos()); + let sin = Relative::new(v.sin()); + Self { + sx: cos, + ky: sin, + kx: -sin, + sy: cos, + ..Self::default() + } + } + + /// Whether this is the identity transformation. + pub fn is_identity(&self) -> bool { + *self == Self::identity() + } + + /// Pre-concatenate another transformation. + pub fn pre_concat(&self, prev: Self) -> Self { + Transform { + sx: self.sx * prev.sx + self.kx * prev.ky, + ky: self.ky * prev.sx + self.sy * prev.ky, + kx: self.sx * prev.kx + self.kx * prev.sy, + sy: self.ky * prev.kx + self.sy * prev.sy, + tx: self.sx.resolve(prev.tx) + self.kx.resolve(prev.ty) + self.tx, + ty: self.ky.resolve(prev.tx) + self.sy.resolve(prev.ty) + self.ty, + } + } +} + +impl Default for Transform { + fn default() -> Self { + Self::identity() + } +} diff --git a/src/layout/mod.rs b/src/layout/mod.rs index be4e994cd..a491789a9 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -17,9 +17,9 @@ use std::rc::Rc; use crate::font::FontStore; use crate::frame::Frame; -use crate::geom::{Align, Linear, Sides, Spec}; +use crate::geom::{Align, Linear, Point, Sides, Spec, Transform}; use crate::image::ImageStore; -use crate::library::{AlignNode, DocumentNode, MoveNode, PadNode, SizedNode}; +use crate::library::{AlignNode, DocumentNode, PadNode, SizedNode, TransformNode}; use crate::Context; /// Layout a document node into a collection of frames. @@ -121,15 +121,6 @@ impl PackedNode { } } - /// Move this node's contents without affecting layout. - pub fn moved(self, offset: Spec>) -> Self { - if offset.any(Option::is_some) { - MoveNode { child: self, offset }.pack() - } else { - self - } - } - /// Pad this node at the sides. pub fn padded(self, padding: Sides) -> Self { if !padding.left.is_zero() @@ -142,6 +133,23 @@ impl PackedNode { self } } + + /// Transform this node's contents without affecting layout. + pub fn moved(self, offset: Point) -> Self { + self.transformed( + Transform::translation(offset.x, offset.y), + Spec::new(Align::Left, Align::Top), + ) + } + + /// Transform this node's contents without affecting layout. + pub fn transformed(self, transform: Transform, origin: Spec) -> Self { + if !transform.is_identity() { + TransformNode { child: self, transform, origin }.pack() + } else { + self + } + } } impl Layout for PackedNode { diff --git a/src/library/image.rs b/src/library/image.rs index a53eacc57..178226199 100644 --- a/src/library/image.rs +++ b/src/library/image.rs @@ -7,7 +7,8 @@ use crate::image::ImageId; /// `image`: An image. pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult { let path = args.expect::>("path to image file")?; - let sizing = Spec::new(args.named("width")?, args.named("height")?); + let width = args.named("width")?; + let height = args.named("height")?; let fit = args.named("fit")?.unwrap_or_default(); // Load the image. @@ -20,7 +21,7 @@ pub fn image(ctx: &mut EvalContext, args: &mut Args) -> TypResult { })?; Ok(Value::Template(Template::from_inline(move |_| { - ImageNode { id, fit }.pack().sized(sizing) + ImageNode { id, fit }.pack().sized(Spec::new(width, height)) }))) } @@ -81,13 +82,12 @@ impl Layout for ImageNode { // Create a clipping group if the image mode is `cover`. if self.fit == ImageFit::Cover { - let group = Group { - frame: Rc::new(frame), - clips: self.fit == ImageFit::Cover, - }; - - frame = Frame::new(canvas, canvas.h); - frame.push(Point::zero(), Element::Group(group)); + let mut wrapper = Frame::new(canvas, canvas.h); + wrapper.push( + Point::zero(), + Element::Group(Group::new(Rc::new(frame)).clips(true)), + ); + frame = wrapper; } let mut cts = Constraints::new(regions.expand); diff --git a/src/library/mod.rs b/src/library/mod.rs index 9e7f6f28d..4d730a7ec 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -76,12 +76,14 @@ pub fn new() -> Scope { std.def_func("box", box_); std.def_func("block", block); std.def_func("flow", flow); + std.def_func("stack", stack); + std.def_func("grid", grid); + std.def_func("pad", pad); std.def_func("align", align); std.def_func("place", place); std.def_func("move", move_); - std.def_func("stack", stack); - std.def_func("pad", pad); - std.def_func("grid", grid); + std.def_func("scale", scale); + std.def_func("rotate", rotate); // Elements. std.def_func("image", image); diff --git a/src/library/par.rs b/src/library/par.rs index 46dc304a4..7f3f1088b 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -628,7 +628,7 @@ impl<'a> LineStack<'a> { for line in self.lines.drain(..) { let frame = line.build(ctx, self.size.w); - let pos = Point::new(Length::zero(), offset); + let pos = Point::with_y(offset); if first { output.baseline = pos.y + frame.baseline; first = false; diff --git a/src/library/placed.rs b/src/library/placed.rs index e2c2e9e8d..4f1c5b85e 100644 --- a/src/library/placed.rs +++ b/src/library/placed.rs @@ -3,11 +3,12 @@ use super::prelude::*; /// `place`: Place content at an absolute position. pub fn place(_: &mut EvalContext, args: &mut Args) -> TypResult { let aligns = args.find().unwrap_or(Spec::new(Some(Align::Left), None)); - let offset = Spec::new(args.named("dx")?, args.named("dy")?); + let tx = args.named("dx")?.unwrap_or_default(); + let ty = args.named("dy")?.unwrap_or_default(); let body: Template = args.expect("body")?; Ok(Value::Template(Template::from_block(move |style| { PlacedNode { - child: body.pack(style).moved(offset).aligned(aligns), + child: body.pack(style).moved(Point::new(tx, ty)).aligned(aligns), } }))) } diff --git a/src/library/shape.rs b/src/library/shape.rs index 061b4d252..5d3504d04 100644 --- a/src/library/shape.rs +++ b/src/library/shape.rs @@ -5,8 +5,9 @@ use crate::util::RcExt; /// `rect`: A rectangle with optional content. pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult { - let sizing = Spec::new(args.named("width")?, args.named("height")?); - shape_impl(args, ShapeKind::Rect, sizing) + let width = args.named("width")?; + let height = args.named("height")?; + shape_impl(args, ShapeKind::Rect, width, height) } /// `square`: A square with optional content. @@ -20,14 +21,14 @@ pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult { None => args.named("height")?, size => size, }; - let sizing = Spec::new(width, height); - shape_impl(args, ShapeKind::Square, sizing) + shape_impl(args, ShapeKind::Square, width, height) } /// `ellipse`: An ellipse with optional content. pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult { - let sizing = Spec::new(args.named("width")?, args.named("height")?); - shape_impl(args, ShapeKind::Ellipse, sizing) + let width = args.named("width")?; + let height = args.named("height")?; + shape_impl(args, ShapeKind::Ellipse, width, height) } /// `circle`: A circle with optional content. @@ -41,14 +42,14 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult { None => args.named("height")?, diameter => diameter, }; - let sizing = Spec::new(width, height); - shape_impl(args, ShapeKind::Circle, sizing) + shape_impl(args, ShapeKind::Circle, width, height) } fn shape_impl( args: &mut Args, kind: ShapeKind, - sizing: Spec>, + width: Option, + height: Option, ) -> TypResult { // The default appearance of a shape. let default = Stroke { @@ -80,7 +81,7 @@ fn shape_impl( child: body.as_ref().map(|body| body.pack(style).padded(padding)), } .pack() - .sized(sizing) + .sized(Spec::new(width, height)) }))) } diff --git a/src/library/sized.rs b/src/library/sized.rs index 8d69afacb..d137c51ee 100644 --- a/src/library/sized.rs +++ b/src/library/sized.rs @@ -2,19 +2,21 @@ use super::prelude::*; /// `box`: Size content and place it into a paragraph. pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult { - let sizing = Spec::new(args.named("width")?, args.named("height")?); + let width = args.named("width")?; + let height = args.named("height")?; let body: Template = args.find().unwrap_or_default(); Ok(Value::Template(Template::from_inline(move |style| { - body.pack(style).sized(sizing) + body.pack(style).sized(Spec::new(width, height)) }))) } /// `block`: Size content and place it into the flow. pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult { - let sizing = Spec::new(args.named("width")?, args.named("height")?); + let width = args.named("width")?; + let height = args.named("height")?; let body: Template = args.find().unwrap_or_default(); Ok(Value::Template(Template::from_block(move |style| { - body.pack(style).sized(sizing) + body.pack(style).sized(Spec::new(width, height)) }))) } diff --git a/src/library/transform.rs b/src/library/transform.rs index 7553bef2e..8d1c6132c 100644 --- a/src/library/transform.rs +++ b/src/library/transform.rs @@ -1,24 +1,54 @@ use super::prelude::*; +use crate::geom::Transform; /// `move`: Move content without affecting layout. pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult { - let offset = Spec::new(args.named("x")?, args.named("y")?); + let tx = args.named("x")?.unwrap_or_default(); + let ty = args.named("y")?.unwrap_or_default(); + let transform = Transform::translation(tx, ty); + transform_impl(args, transform) +} + +/// `scale`: Scale content without affecting layout. +pub fn scale(_: &mut EvalContext, args: &mut Args) -> TypResult { + let all = args.find(); + let sx = args.named("x")?.or(all).unwrap_or(Relative::one()); + let sy = args.named("y")?.or(all).unwrap_or(Relative::one()); + let transform = Transform::scaling(sx, sy); + transform_impl(args, transform) +} + +/// `rotate`: Rotate content without affecting layout. +pub fn rotate(_: &mut EvalContext, args: &mut Args) -> TypResult { + let angle = args.expect("angle")?; + let transform = Transform::rotation(angle); + transform_impl(args, transform) +} + +fn transform_impl(args: &mut Args, transform: Transform) -> TypResult { let body: Template = args.expect("body")?; + let origin = args + .named("origin")? + .unwrap_or(Spec::splat(None)) + .unwrap_or(Spec::new(Align::Center, Align::Horizon)); + Ok(Value::Template(Template::from_inline(move |style| { - body.pack(style).moved(offset) + body.pack(style).transformed(transform, origin) }))) } -/// A node that moves its child without affecting layout. +/// A node that transforms its child without affecting layout. #[derive(Debug, Hash)] -pub struct MoveNode { - /// The node whose contents should be moved. +pub struct TransformNode { + /// The node whose contents should be transformed. pub child: PackedNode, - /// How much to move the contents. - pub offset: Spec>, + /// Transformation to apply to the contents. + pub transform: Transform, + /// The origin of the transformation. + pub origin: Spec, } -impl Layout for MoveNode { +impl Layout for TransformNode { fn layout( &self, ctx: &mut LayoutContext, @@ -26,13 +56,19 @@ impl Layout for MoveNode { ) -> Vec>> { let mut frames = self.child.layout(ctx, regions); - for (Constrained { item: frame, .. }, (_, base)) in - frames.iter_mut().zip(regions.iter()) - { - Rc::make_mut(frame).translate(Point::new( - self.offset.x.map(|x| x.resolve(base.w)).unwrap_or_default(), - self.offset.y.map(|y| y.resolve(base.h)).unwrap_or_default(), - )); + for Constrained { item: frame, .. } in frames.iter_mut() { + let x = self.origin.x.resolve(frame.size.w); + let y = self.origin.y.resolve(frame.size.h); + let transform = Transform::translation(x, y) + .pre_concat(self.transform) + .pre_concat(Transform::translation(-x, -y)); + + let mut wrapper = Frame::new(frame.size, frame.baseline); + wrapper.push( + Point::zero(), + Element::Group(Group::new(std::mem::take(frame)).transform(transform)), + ); + *frame = Rc::new(wrapper); } frames diff --git a/tests/ref/layout/move.png b/tests/ref/layout/move.png deleted file mode 100644 index dc2e7ab3ef8ceaa3cd4fe2078c50df22ced49416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 693 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/ref/text/links.png b/tests/ref/text/links.png index c4aeec06ec6199956db88fd81ff105fd119c098a..18154a068d106326b87d5a7716b7fc119b722206 100644 GIT binary patch delta 10219 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 sk::Transform { + let Transform { sx, ky, kx, sy, tx, ty } = transform; + sk::Transform::from_row( + sx.get() as _, + ky.get() as _, + kx.get() as _, + sy.get() as _, + tx.to_f32(), + ty.to_f32(), + ) +} + fn convert_typst_paint(paint: Paint) -> sk::Paint<'static> { let Paint::Solid(Color::Rgba(c)) = paint; let mut paint = sk::Paint::default();