From 3c22c9f31914727f665ce10d6db9dac39a26eacb Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 29 Nov 2023 16:28:30 +0100 Subject: [PATCH] Pattern improvements --- crates/typst-pdf/src/pattern.rs | 8 +- crates/typst-render/src/lib.rs | 7 +- crates/typst-svg/src/lib.rs | 4 +- crates/typst/src/visualize/pattern.rs | 135 ++++++++++++-------------- 4 files changed, 72 insertions(+), 82 deletions(-) diff --git a/crates/typst-pdf/src/pattern.rs b/crates/typst-pdf/src/pattern.rs index 7b9e27192..965ce370a 100644 --- a/crates/typst-pdf/src/pattern.rs +++ b/crates/typst-pdf/src/pattern.rs @@ -24,11 +24,11 @@ pub(crate) fn write_patterns(ctx: &mut PdfContext) { .bbox(Rect::new( 0.0, 0.0, - pattern.size_abs().x.to_pt() as _, - pattern.size_abs().y.to_pt() as _, + pattern.size().x.to_pt() as _, + pattern.size().y.to_pt() as _, )) - .x_step((pattern.size_abs().x + pattern.spacing_abs().x).to_pt() as _) - .y_step((pattern.size_abs().y + pattern.spacing_abs().y).to_pt() as _); + .x_step((pattern.size().x + pattern.spacing().x).to_pt() as _) + .y_step((pattern.size().y + pattern.spacing().y).to_pt() as _); let mut resources_map = tiling_pattern.resources(); diff --git a/crates/typst-render/src/lib.rs b/crates/typst-render/src/lib.rs index 5c1b8482e..79ec75b89 100644 --- a/crates/typst-render/src/lib.rs +++ b/crates/typst-render/src/lib.rs @@ -855,8 +855,7 @@ impl<'a> PatternSampler<'a> { Self { pixmap, - size: (pattern.size_abs() + pattern.spacing_abs()) - * state.pixel_per_pt as f64, + size: (pattern.size() + pattern.spacing()) * state.pixel_per_pt as f64, transform_to_parent: fill_transform, pixel_per_pt: state.pixel_per_pt, } @@ -994,7 +993,7 @@ fn to_sk_paint<'a>( } fn render_pattern_frame(state: &State, pattern: &Pattern) -> sk::Pixmap { - let size = pattern.size_abs() + pattern.spacing_abs(); + let size = pattern.size() + pattern.spacing(); let mut canvas = sk::Pixmap::new( (size.x.to_f32() * state.pixel_per_pt).round() as u32, (size.y.to_f32() * state.pixel_per_pt).round() as u32, @@ -1003,7 +1002,7 @@ fn render_pattern_frame(state: &State, pattern: &Pattern) -> sk::Pixmap { // Render the pattern into a new canvas. let ts = sk::Transform::from_scale(state.pixel_per_pt, state.pixel_per_pt); - let temp_state = State::new(pattern.size_abs(), ts, state.pixel_per_pt); + let temp_state = State::new(pattern.size(), ts, state.pixel_per_pt); render_frame(&mut canvas, temp_state, pattern.frame()); canvas } diff --git a/crates/typst-svg/src/lib.rs b/crates/typst-svg/src/lib.rs index 29e423106..04a24ebfa 100644 --- a/crates/typst-svg/src/lib.rs +++ b/crates/typst-svg/src/lib.rs @@ -606,7 +606,7 @@ impl SVGRenderer { } fn push_pattern(&mut self, pattern: &Pattern, size: Size, ts: Transform) -> Id { - let pattern_size = pattern.size_abs() + pattern.spacing_abs(); + let pattern_size = pattern.size() + pattern.spacing(); // Unfortunately due to a limitation of `xmlwriter`, we need to // render the frame twice: once to allocate all of the resources // that it needs and once to actually render it. @@ -1031,7 +1031,7 @@ impl SVGRenderer { for (id, pattern) in self.patterns.iter().map(|(i, p)| (i, p.clone())).collect::>() { - let size = pattern.size_abs() + pattern.spacing_abs(); + let size = pattern.size() + pattern.spacing(); self.xml.start_element("pattern"); self.xml.write_attribute("id", &id); self.xml.write_attribute("width", &size.x.to_pt()); diff --git a/crates/typst/src/visualize/pattern.rs b/crates/typst/src/visualize/pattern.rs index 87cae4e5f..01dc8ffa3 100644 --- a/crates/typst/src/visualize/pattern.rs +++ b/crates/typst/src/visualize/pattern.rs @@ -6,8 +6,8 @@ use ecow::{eco_format, EcoString}; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; -use crate::foundations::{func, scope, ty, Content, Repr, Smart, StyleChain}; -use crate::layout::{Abs, Axes, Em, Frame, Layout, Length, Regions, Size}; +use crate::foundations::{func, repr, scope, ty, Content, Smart, StyleChain}; +use crate::layout::{Abs, Axes, Frame, Layout, Length, Regions, Size}; use crate::syntax::{Span, Spanned}; use crate::util::Numeric; use crate::visualize::RelativeTo; @@ -16,24 +16,20 @@ use crate::World; /// A repeating pattern fill. /// /// Typst supports the most common pattern type of tiled patterns, where a -/// pattern is repeated in a grid-like fashion. The pattern is defined by a -/// body and a tile size. The tile size is the size of each cell of the pattern. -/// The body is the content of each cell of the pattern. The pattern is -/// repeated in a grid-like fashion covering the entire area of the element -/// being filled. You can also specify a spacing between the cells of the -/// pattern, which is defined by a horizontal and vertical spacing. The spacing -/// is the distance between the edges of adjacent cells of the pattern. The default -/// spacing is zero. +/// pattern is repeated in a grid-like fashion, covering the entire area of an +/// element that is filled or stroked. The pattern is defined by a tile size and +/// a body defining the content of each cell. You can also add horizontal or +/// vertical spacing between the cells of the patterng. /// /// # Examples /// /// ```example /// #let pat = pattern(size: (30pt, 30pt))[ -/// #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) -/// #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) +/// #place(line(start: (0%, 0%), end: (100%, 100%))) +/// #place(line(start: (0%, 100%), end: (100%, 0%))) /// ] /// -/// #rect(fill: pat, width: 100%, height: 100%, stroke: 1pt) +/// #rect(fill: pat, width: 100%, height: 60pt, stroke: 1pt) /// ``` /// /// Patterns are also supported on text, but only when setting the @@ -46,7 +42,11 @@ use crate::World; /// #let pat = pattern( /// size: (30pt, 30pt), /// relative: "parent", -/// square(size: 30pt, fill: gradient.conic(..color.map.rainbow)) +/// square( +/// size: 30pt, +/// fill: gradient +/// .conic(..color.map.rainbow), +/// ) /// ) /// /// #set text(fill: pat) @@ -64,14 +64,22 @@ use crate::World; /// size: (30pt, 30pt), /// spacing: (10pt, 10pt), /// relative: "parent", -/// square(size: 30pt, fill: gradient.conic(..color.map.rainbow)) +/// square( +/// size: 30pt, +/// fill: gradient +/// .conic(..color.map.rainbow), +/// ), /// ) /// -/// #rect(width: 100%, height: 100%, fill: pat) +/// #rect( +/// width: 100%, +/// height: 60pt, +/// fill: pat, +/// ) /// ``` /// /// # Relativeness -/// The location of the starting point of the pattern is dependant on the +/// The location of the starting point of the pattern is dependent on the /// dimensions of a container. This container can either be the shape they /// are painted on, or the closest surrounding container. This is controlled by /// the `relative` argument of a pattern constructor. By default, patterns are @@ -87,14 +95,12 @@ use crate::World; /// [`rotate`]($rotate) will not affect the parent of a gradient, but a /// [`grid`]($grid) will. #[ty(scope)] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Pattern(Arc); +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct Pattern(Arc); /// Internal representation of [`Pattern`]. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -struct PatternRepr { - /// The body of the pattern - body: Prehashed, +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +struct Repr { /// The pattern's rendered content. frame: Prehashed, /// The pattern's tile size. @@ -113,10 +119,17 @@ impl Pattern { /// #let pat = pattern( /// size: (20pt, 20pt), /// relative: "parent", - /// place(dx: 5pt, dy: 5pt, rotate(45deg, square(size: 5pt, fill: black))) + /// place( + /// dx: 5pt, + /// dy: 5pt, + /// rotate(45deg, square( + /// size: 5pt, + /// fill: black, + /// )), + /// ), /// ) /// - /// #rect(width: 100%, height: 100%, fill: pat) + /// #rect(width: 100%, height: 60pt, fill: pat) /// ``` #[func(constructor)] pub fn construct( @@ -192,38 +205,13 @@ impl Pattern { frame.set_size(size); } - Ok(Self(Arc::new(PatternRepr { + Ok(Self(Arc::new(Repr { size: frame.size(), - body: Prehashed::new(body), frame: Prehashed::new(frame), spacing: spacing.v.map(|l| l.abs), relative, }))) } - - /// Returns the content of an individual tile of the pattern. - #[func] - pub fn body(&self) -> Content { - self.0.body.clone().into_inner() - } - - /// Returns the size of an individual tile of the pattern. - #[func] - pub fn size(&self) -> Axes { - self.0.size.map(|l| Length { abs: l, em: Em::zero() }) - } - - /// Returns the spacing between tiles of the pattern. - #[func] - pub fn spacing(&self) -> Axes { - self.0.spacing.map(|l| Length { abs: l, em: Em::zero() }) - } - - /// Returns the relative placement of the pattern. - #[func] - pub fn relative(&self) -> Smart { - self.0.relative - } } impl Pattern { @@ -232,7 +220,7 @@ impl Pattern { if let Some(this) = Arc::get_mut(&mut self.0) { this.relative = Smart::Custom(relative); } else { - self.0 = Arc::new(PatternRepr { + self.0 = Arc::new(Repr { relative: Smart::Custom(relative), ..self.0.as_ref().clone() }); @@ -241,6 +229,26 @@ impl Pattern { self } + /// Return the frame of the pattern. + pub fn frame(&self) -> &Frame { + &self.0.frame + } + + /// Return the size of the pattern in absolute units. + pub fn size(&self) -> Size { + self.0.size + } + + /// Return the spacing of the pattern in absolute units. + pub fn spacing(&self) -> Size { + self.0.spacing + } + + /// Returns the relative placement of the pattern. + pub fn relative(&self) -> Smart { + self.0.relative + } + /// Returns the relative placement of the pattern. pub fn unwrap_relative(&self, on_text: bool) -> RelativeTo { self.0.relative.unwrap_or_else(|| { @@ -251,29 +259,14 @@ impl Pattern { } }) } - - /// Return the size of the pattern in absolute units. - pub fn size_abs(&self) -> Size { - self.0.size - } - - /// Return the spacing of the pattern in absolute units. - pub fn spacing_abs(&self) -> Size { - self.0.spacing - } - - /// Return the frame of the pattern. - pub fn frame(&self) -> &Frame { - &self.0.frame - } } -impl Repr for Pattern { +impl repr::Repr for Pattern { fn repr(&self) -> EcoString { let mut out = eco_format!("pattern(({}, {})", self.0.size.x.repr(), self.0.size.y.repr()); - if self.spacing() != Axes::splat(Length::zero()) { + if self.0.spacing.is_zero() { out.push_str(", spacing: ("); out.push_str(&self.0.spacing.x.repr()); out.push_str(", "); @@ -281,9 +274,7 @@ impl Repr for Pattern { out.push(')'); } - out.push_str(", "); - out.push_str(&self.0.body.repr()); - out.push(')'); + out.push_str(", ..)"); out }