From 134638525516995d5947c5b3f98ffbc13784a143 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 17 Dec 2024 10:25:27 +0100 Subject: [PATCH] Rename `pattern` to `tiling` (#5590) --- crates/typst-layout/src/shapes.rs | 6 +- crates/typst-library/src/foundations/ops.rs | 4 +- crates/typst-library/src/foundations/value.rs | 16 +- .../src/introspection/locator.rs | 2 +- crates/typst-library/src/text/mod.rs | 2 +- crates/typst-library/src/visualize/mod.rs | 11 +- crates/typst-library/src/visualize/paint.rs | 28 +-- crates/typst-library/src/visualize/stroke.rs | 26 ++- .../src/visualize/{pattern.rs => tiling.rs} | 102 +++++------ crates/typst-pdf/src/color.rs | 4 +- crates/typst-pdf/src/content.rs | 14 +- crates/typst-pdf/src/lib.rs | 10 +- crates/typst-pdf/src/resources.rs | 44 ++--- .../typst-pdf/src/{pattern.rs => tiling.rs} | 34 ++-- crates/typst-render/src/paint.rs | 36 ++-- crates/typst-render/src/shape.rs | 8 +- crates/typst-render/src/text.rs | 8 +- crates/typst-svg/src/lib.rs | 28 +-- crates/typst-svg/src/paint.rs | 97 ++++++----- crates/typst-svg/src/shape.rs | 14 +- crates/typst-svg/src/text.rs | 2 +- crates/typst-syntax/src/ast.rs | 4 +- crates/typst-syntax/src/kind.rs | 2 +- crates/typst-syntax/src/parser.rs | 2 +- docs/changelog/0.10.0.md | 2 +- docs/changelog/0.11.1.md | 2 +- docs/guides/tables.md | 4 +- ...oke-pattern.png => grid-stroke-tiling.png} | Bin .../ref/{pattern-line.png => tiling-line.png} | Bin .../{pattern-lines.png => tiling-lines.png} | Bin tests/ref/tiling-pattern-compatibility.png | Bin 0 -> 125 bytes ...-parent.png => tiling-relative-parent.png} | Bin ...tive-self.png => tiling-relative-self.png} | Bin .../{pattern-small.png => tiling-small.png} | Bin ...gative.png => tiling-spacing-negative.png} | Bin ...sitive.png => tiling-spacing-positive.png} | Bin ...acing-zero.png => tiling-spacing-zero.png} | Bin ....png => tiling-stroke-relative-parent.png} | Bin .../{pattern-stroke.png => tiling-stroke.png} | Bin .../ref/{pattern-text.png => tiling-text.png} | Bin tests/suite/layout/grid/stroke.typ | 4 +- tests/suite/layout/table.typ | 2 +- tests/suite/text/font.typ | 6 +- tests/suite/visualize/gradient.typ | 2 +- tests/suite/visualize/pattern.typ | 159 ----------------- tests/suite/visualize/rect.typ | 2 +- tests/suite/visualize/tiling.typ | 163 ++++++++++++++++++ 47 files changed, 426 insertions(+), 424 deletions(-) rename crates/typst-library/src/visualize/{pattern.rs => tiling.rs} (71%) rename crates/typst-pdf/src/{pattern.rs => tiling.rs} (87%) rename tests/ref/{grid-stroke-pattern.png => grid-stroke-tiling.png} (100%) rename tests/ref/{pattern-line.png => tiling-line.png} (100%) rename tests/ref/{pattern-lines.png => tiling-lines.png} (100%) create mode 100644 tests/ref/tiling-pattern-compatibility.png rename tests/ref/{pattern-relative-parent.png => tiling-relative-parent.png} (100%) rename tests/ref/{pattern-relative-self.png => tiling-relative-self.png} (100%) rename tests/ref/{pattern-small.png => tiling-small.png} (100%) rename tests/ref/{pattern-spacing-negative.png => tiling-spacing-negative.png} (100%) rename tests/ref/{pattern-spacing-positive.png => tiling-spacing-positive.png} (100%) rename tests/ref/{pattern-spacing-zero.png => tiling-spacing-zero.png} (100%) rename tests/ref/{pattern-stroke-relative-parent.png => tiling-stroke-relative-parent.png} (100%) rename tests/ref/{pattern-stroke.png => tiling-stroke.png} (100%) rename tests/ref/{pattern-text.png => tiling-text.png} (100%) delete mode 100644 tests/suite/visualize/pattern.typ create mode 100644 tests/suite/visualize/tiling.typ diff --git a/crates/typst-layout/src/shapes.rs b/crates/typst-layout/src/shapes.rs index db9acece3..2044c917e 100644 --- a/crates/typst-layout/src/shapes.rs +++ b/crates/typst-layout/src/shapes.rs @@ -719,11 +719,7 @@ fn segment( false } - let solid = stroke - .dash - .as_ref() - .map(|pattern| pattern.array.is_empty()) - .unwrap_or(true); + let solid = stroke.dash.as_ref().map(|dash| dash.array.is_empty()).unwrap_or(true); let use_fill = solid && fill_corners(start, end, corners); let shape = if use_fill { diff --git a/crates/typst-library/src/foundations/ops.rs b/crates/typst-library/src/foundations/ops.rs index b41fce8d0..8d12966bf 100644 --- a/crates/typst-library/src/foundations/ops.rs +++ b/crates/typst-library/src/foundations/ops.rs @@ -144,8 +144,8 @@ pub fn add(lhs: Value, rhs: Value) -> HintedStrResult { | (Length(thickness), Gradient(gradient)) => { Stroke::from_pair(gradient, thickness).into_value() } - (Pattern(pattern), Length(thickness)) | (Length(thickness), Pattern(pattern)) => { - Stroke::from_pair(pattern, thickness).into_value() + (Tiling(tiling), Length(thickness)) | (Length(thickness), Tiling(tiling)) => { + Stroke::from_pair(tiling, thickness).into_value() } (Duration(a), Duration(b)) => Duration(a + b), diff --git a/crates/typst-library/src/foundations/value.rs b/crates/typst-library/src/foundations/value.rs index 538b4f1b8..eb0d6eedc 100644 --- a/crates/typst-library/src/foundations/value.rs +++ b/crates/typst-library/src/foundations/value.rs @@ -20,7 +20,7 @@ use crate::foundations::{ }; use crate::layout::{Abs, Angle, Em, Fr, Length, Ratio, Rel}; use crate::text::{RawContent, RawElem, TextElem}; -use crate::visualize::{Color, Gradient, Pattern}; +use crate::visualize::{Color, Gradient, Tiling}; /// A computational value. #[derive(Default, Clone)] @@ -50,8 +50,8 @@ pub enum Value { Color(Color), /// A gradient value: `gradient.linear(...)`. Gradient(Gradient), - /// A pattern fill: `pattern(...)`. - Pattern(Pattern), + /// A tiling fill: `tiling(...)`. + Tiling(Tiling), /// A symbol: `arrow.l`. Symbol(Symbol), /// A version. @@ -130,7 +130,7 @@ impl Value { Self::Fraction(_) => Type::of::(), Self::Color(_) => Type::of::(), Self::Gradient(_) => Type::of::(), - Self::Pattern(_) => Type::of::(), + Self::Tiling(_) => Type::of::(), Self::Symbol(_) => Type::of::(), Self::Version(_) => Type::of::(), Self::Str(_) => Type::of::(), @@ -244,7 +244,7 @@ impl Debug for Value { Self::Fraction(v) => Debug::fmt(v, f), Self::Color(v) => Debug::fmt(v, f), Self::Gradient(v) => Debug::fmt(v, f), - Self::Pattern(v) => Debug::fmt(v, f), + Self::Tiling(v) => Debug::fmt(v, f), Self::Symbol(v) => Debug::fmt(v, f), Self::Version(v) => Debug::fmt(v, f), Self::Str(v) => Debug::fmt(v, f), @@ -282,7 +282,7 @@ impl Repr for Value { Self::Fraction(v) => v.repr(), Self::Color(v) => v.repr(), Self::Gradient(v) => v.repr(), - Self::Pattern(v) => v.repr(), + Self::Tiling(v) => v.repr(), Self::Symbol(v) => v.repr(), Self::Version(v) => v.repr(), Self::Str(v) => v.repr(), @@ -333,7 +333,7 @@ impl Hash for Value { Self::Fraction(v) => v.hash(state), Self::Color(v) => v.hash(state), Self::Gradient(v) => v.hash(state), - Self::Pattern(v) => v.hash(state), + Self::Tiling(v) => v.hash(state), Self::Symbol(v) => v.hash(state), Self::Version(v) => v.hash(state), Self::Str(v) => v.hash(state), @@ -640,7 +640,7 @@ primitive! { Rel: "relative length", primitive! { Fr: "fraction", Fraction } primitive! { Color: "color", Color } primitive! { Gradient: "gradient", Gradient } -primitive! { Pattern: "pattern", Pattern } +primitive! { Tiling: "tiling", Tiling } primitive! { Symbol: "symbol", Symbol } primitive! { Version: "version", Version } primitive! { diff --git a/crates/typst-library/src/introspection/locator.rs b/crates/typst-library/src/introspection/locator.rs index a84cf1639..3ba3d6486 100644 --- a/crates/typst-library/src/introspection/locator.rs +++ b/crates/typst-library/src/introspection/locator.rs @@ -161,7 +161,7 @@ impl<'a> Locator<'a> { /// /// Should typically only be created at the document level, though there /// are a few places where we use it as well that just don't support - /// introspection (e.g. drawable patterns). + /// introspection (e.g. tilings). pub fn root() -> Self { Self { local: 0, outer: None } } diff --git a/crates/typst-library/src/text/mod.rs b/crates/typst-library/src/text/mod.rs index 62c870513..91927b572 100644 --- a/crates/typst-library/src/text/mod.rs +++ b/crates/typst-library/src/text/mod.rs @@ -249,7 +249,7 @@ pub struct TextElem { if paint.v.relative() == Smart::Custom(RelativeTo::Self_) { bail!( paint.span, - "gradients and patterns on text must be relative to the parent"; + "gradients and tilings on text must be relative to the parent"; hint: "make sure to set `relative: auto` on your text fill" ); } diff --git a/crates/typst-library/src/visualize/mod.rs b/crates/typst-library/src/visualize/mod.rs index 5c8bf6468..61c56a61c 100644 --- a/crates/typst-library/src/visualize/mod.rs +++ b/crates/typst-library/src/visualize/mod.rs @@ -6,10 +6,10 @@ mod image; mod line; mod paint; mod path; -mod pattern; mod polygon; mod shape; mod stroke; +mod tiling; pub use self::color::*; pub use self::gradient::*; @@ -17,12 +17,12 @@ pub use self::image::*; pub use self::line::*; pub use self::paint::*; pub use self::path::*; -pub use self::pattern::*; pub use self::polygon::*; pub use self::shape::*; pub use self::stroke::*; +pub use self::tiling::*; -use crate::foundations::{category, Category, Scope}; +use crate::foundations::{category, Category, Scope, Type}; /// Drawing and data visualization. /// @@ -37,7 +37,7 @@ pub(super) fn define(global: &mut Scope) { global.category(VISUALIZE); global.define_type::(); global.define_type::(); - global.define_type::(); + global.define_type::(); global.define_type::(); global.define_elem::(); global.define_elem::(); @@ -47,4 +47,7 @@ pub(super) fn define(global: &mut Scope) { global.define_elem::(); global.define_elem::(); global.define_elem::(); + + // Compatibility. + global.define("pattern", Type::of::()); } diff --git a/crates/typst-library/src/visualize/paint.rs b/crates/typst-library/src/visualize/paint.rs index cd1006aa3..a618e5154 100644 --- a/crates/typst-library/src/visualize/paint.rs +++ b/crates/typst-library/src/visualize/paint.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter}; use ecow::EcoString; use crate::foundations::{cast, Repr, Smart}; -use crate::visualize::{Color, Gradient, Pattern, RelativeTo}; +use crate::visualize::{Color, Gradient, RelativeTo, Tiling}; /// How a fill or stroke should be painted. #[derive(Clone, Eq, PartialEq, Hash)] @@ -12,8 +12,8 @@ pub enum Paint { Solid(Color), /// A gradient. Gradient(Gradient), - /// A pattern. - Pattern(Pattern), + /// A tiling. + Tiling(Tiling), } impl Paint { @@ -21,7 +21,7 @@ impl Paint { pub fn unwrap_solid(&self) -> Color { match self { Self::Solid(color) => *color, - Self::Gradient(_) | Self::Pattern(_) => panic!("expected solid color"), + Self::Gradient(_) | Self::Tiling(_) => panic!("expected solid color"), } } @@ -30,7 +30,7 @@ impl Paint { match self { Self::Solid(_) => Smart::Auto, Self::Gradient(gradient) => gradient.relative(), - Self::Pattern(pattern) => pattern.relative(), + Self::Tiling(tiling) => tiling.relative(), } } @@ -44,8 +44,8 @@ impl Paint { Self::Gradient(gradient) => { Self::Gradient(gradient.clone().with_relative(RelativeTo::Parent)) } - Self::Pattern(pattern) => { - Self::Pattern(pattern.clone().with_relative(RelativeTo::Parent)) + Self::Tiling(tiling) => { + Self::Tiling(tiling.clone().with_relative(RelativeTo::Parent)) } } } @@ -56,14 +56,14 @@ impl Debug for Paint { match self { Self::Solid(v) => v.fmt(f), Self::Gradient(v) => v.fmt(f), - Self::Pattern(v) => v.fmt(f), + Self::Tiling(v) => v.fmt(f), } } } -impl From for Paint { - fn from(pattern: Pattern) -> Self { - Self::Pattern(pattern) +impl From for Paint { + fn from(tiling: Tiling) -> Self { + Self::Tiling(tiling) } } @@ -72,7 +72,7 @@ impl Repr for Paint { match self { Self::Solid(color) => color.repr(), Self::Gradient(gradient) => gradient.repr(), - Self::Pattern(pattern) => pattern.repr(), + Self::Tiling(tiling) => tiling.repr(), } } } @@ -94,9 +94,9 @@ cast! { self => match self { Self::Solid(color) => color.into_value(), Self::Gradient(gradient) => gradient.into_value(), - Self::Pattern(pattern) => pattern.into_value(), + Self::Tiling(tiling) => tiling.into_value(), }, color: Color => Self::Solid(color), gradient: Gradient => Self::Gradient(gradient), - pattern: Pattern => Self::Pattern(pattern), + tiling: Tiling => Self::Tiling(tiling), } diff --git a/crates/typst-library/src/visualize/stroke.rs b/crates/typst-library/src/visualize/stroke.rs index 4ca10920f..2ab493a53 100644 --- a/crates/typst-library/src/visualize/stroke.rs +++ b/crates/typst-library/src/visualize/stroke.rs @@ -7,7 +7,7 @@ use crate::foundations::{ Resolve, Smart, StyleChain, Value, }; use crate::layout::{Abs, Length}; -use crate::visualize::{Color, Gradient, Paint, Pattern}; +use crate::visualize::{Color, Gradient, Paint, Tiling}; /// Defines how to draw a line. /// @@ -213,9 +213,9 @@ impl Stroke { thickness: self.thickness.map(&f), cap: self.cap, join: self.join, - dash: self.dash.map(|pattern| { - pattern.map(|pattern| DashPattern { - array: pattern + dash: self.dash.map(|dash| { + dash.map(|dash| DashPattern { + array: dash .array .into_iter() .map(|l| match l { @@ -223,7 +223,7 @@ impl Stroke { DashLength::LineWidth => DashLength::LineWidth, }) .collect(), - phase: f(pattern.phase), + phase: f(dash.phase), }) }), miter_limit: self.miter_limit, @@ -237,14 +237,10 @@ impl Stroke { let thickness = self.thickness.unwrap_or(default.thickness); let dash = self .dash - .map(|pattern| { - pattern.map(|pattern| DashPattern { - array: pattern - .array - .into_iter() - .map(|l| l.finish(thickness)) - .collect(), - phase: pattern.phase, + .map(|dash| { + dash.map(|dash| DashPattern { + array: dash.array.into_iter().map(|l| l.finish(thickness)).collect(), + phase: dash.phase, }) }) .unwrap_or(default.dash); @@ -372,8 +368,8 @@ cast! { paint: Smart::Custom(gradient.into()), ..Default::default() }, - pattern: Pattern => Self { - paint: Smart::Custom(pattern.into()), + tiling: Tiling => Self { + paint: Smart::Custom(tiling.into()), ..Default::default() }, mut dict: Dict => { diff --git a/crates/typst-library/src/visualize/pattern.rs b/crates/typst-library/src/visualize/tiling.rs similarity index 71% rename from crates/typst-library/src/visualize/pattern.rs rename to crates/typst-library/src/visualize/tiling.rs index 2017ea655..d699d3b6d 100644 --- a/crates/typst-library/src/visualize/pattern.rs +++ b/crates/typst-library/src/visualize/tiling.rs @@ -13,18 +13,18 @@ use crate::layout::{Abs, Axes, Frame, Length, Region, Size}; use crate::visualize::RelativeTo; use crate::World; -/// A repeating pattern fill. +/// A repeating tiling fill. /// -/// Typst supports the most common pattern type of tiled patterns, where a -/// 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 pattern. +/// Typst supports the most common type of tilings, where a 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 tiling. /// /// # Examples /// /// ```example -/// #let pat = pattern(size: (30pt, 30pt))[ +/// #let pat = tiling(size: (30pt, 30pt))[ /// #place(line(start: (0%, 0%), end: (100%, 100%))) /// #place(line(start: (0%, 100%), end: (100%, 0%))) /// ] @@ -32,14 +32,14 @@ use crate::World; /// #rect(fill: pat, width: 100%, height: 60pt, stroke: 1pt) /// ``` /// -/// Patterns are also supported on text, but only when setting the -/// [relativeness]($pattern.relative) to either `{auto}` (the default value) or -/// `{"parent"}`. To create word-by-word or glyph-by-glyph patterns, you can +/// Tilings are also supported on text, but only when setting the +/// [relativeness]($tiling.relative) to either `{auto}` (the default value) or +/// `{"parent"}`. To create word-by-word or glyph-by-glyph tilings, you can /// wrap the words or characters of your text in [boxes]($box) manually or /// through a [show rule]($styling/#show-rules). /// /// ```example -/// #let pat = pattern( +/// #let pat = tiling( /// size: (30pt, 30pt), /// relative: "parent", /// square( @@ -54,13 +54,13 @@ use crate::World; /// ``` /// /// You can also space the elements further or closer apart using the -/// [`spacing`]($pattern.spacing) feature of the pattern. If the spacing -/// is lower than the size of the pattern, the pattern will overlap. -/// If it is higher, the pattern will have gaps of the same color as the -/// background of the pattern. +/// [`spacing`]($tiling.spacing) feature of the tiling. If the spacing +/// is lower than the size of the tiling, the tiling will overlap. +/// If it is higher, the tiling will have gaps of the same color as the +/// background of the tiling. /// /// ```example -/// #let pat = pattern( +/// #let pat = tiling( /// size: (30pt, 30pt), /// spacing: (10pt, 10pt), /// relative: "parent", @@ -79,11 +79,11 @@ use crate::World; /// ``` /// /// # Relativeness -/// The location of the starting point of the pattern is dependent on the +/// The location of the starting point of the tiling is dependent on the /// dimensions of a container. This container can either be the shape that it is /// being painted on, or the closest surrounding container. This is controlled -/// by the `relative` argument of a pattern constructor. By default, patterns -/// are relative to the shape they are being painted on, unless the pattern is +/// by the `relative` argument of a tiling constructor. By default, tilings +/// are relative to the shape they are being painted on, unless the tiling is /// applied on text, in which case they are relative to the closest ancestor /// container. /// @@ -94,29 +94,33 @@ use crate::World; /// contains the shape. This includes the boxes and blocks that are implicitly /// created by show rules and elements. For example, a [`rotate`] will not /// affect the parent of a gradient, but a [`grid`] will. -#[ty(scope, cast)] +/// +/// # Compatibility +/// This type used to be called `pattern`. The name remains as an alias, but is +/// deprecated since Typst 0.13. +#[ty(scope, cast, keywords = ["pattern"])] #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Pattern(Arc); +pub struct Tiling(Arc); -/// Internal representation of [`Pattern`]. +/// Internal representation of [`Tiling`]. #[derive(Debug, Clone, Eq, PartialEq, Hash)] struct Repr { - /// The pattern's rendered content. + /// The tiling's rendered content. frame: LazyHash, - /// The pattern's tile size. + /// The tiling's tile size. size: Size, - /// The pattern's tile spacing. + /// The tiling's tile spacing. spacing: Size, - /// The pattern's relative transform. + /// The tiling's relative transform. relative: Smart, } #[scope] -impl Pattern { - /// Construct a new pattern. +impl Tiling { + /// Construct a new tiling. /// /// ```example - /// #let pat = pattern( + /// #let pat = tiling( /// size: (20pt, 20pt), /// relative: "parent", /// place( @@ -136,15 +140,15 @@ impl Pattern { engine: &mut Engine, /// The callsite span. span: Span, - /// The bounding box of each cell of the pattern. + /// The bounding box of each cell of the tiling. #[named] #[default(Spanned::new(Smart::Auto, Span::detached()))] size: Spanned>>, - /// The spacing between cells of the pattern. + /// The spacing between cells of the tiling. #[named] #[default(Spanned::new(Axes::splat(Length::zero()), Span::detached()))] spacing: Spanned>, - /// The [relative placement](#relativeness) of the pattern. + /// The [relative placement](#relativeness) of the tiling. /// /// For an element placed at the root/top level of the document, the /// parent is the page itself. For other elements, the parent is the @@ -153,14 +157,14 @@ impl Pattern { #[named] #[default(Smart::Auto)] relative: Smart, - /// The content of each cell of the pattern. + /// The content of each cell of the tiling. body: Content, - ) -> SourceResult { + ) -> SourceResult { let size_span = size.span; if let Smart::Custom(size) = size.v { // Ensure that sizes are absolute. if !size.x.em.is_zero() || !size.y.em.is_zero() { - bail!(size_span, "pattern tile size must be absolute"); + bail!(size_span, "tile size must be absolute"); } // Ensure that sizes are non-zero and finite. @@ -169,25 +173,25 @@ impl Pattern { || !size.x.is_finite() || !size.y.is_finite() { - bail!(size_span, "pattern tile size must be non-zero and non-infinite"); + bail!(size_span, "tile size must be non-zero and non-infinite"); } } // Ensure that spacing is absolute. if !spacing.v.x.em.is_zero() || !spacing.v.y.em.is_zero() { - bail!(spacing.span, "pattern tile spacing must be absolute"); + bail!(spacing.span, "tile spacing must be absolute"); } // Ensure that spacing is finite. if !spacing.v.x.is_finite() || !spacing.v.y.is_finite() { - bail!(spacing.span, "pattern tile spacing must be finite"); + bail!(spacing.span, "tile spacing must be finite"); } // The size of the frame let size = size.v.map(|l| l.map(|a| a.abs)); let region = size.unwrap_or_else(|| Axes::splat(Abs::inf())); - // Layout the pattern. + // Layout the tiling. let world = engine.world; let library = world.library(); let locator = Locator::root(); @@ -204,7 +208,7 @@ impl Pattern { // Check that the frame is non-zero. if frame.width().is_zero() || frame.height().is_zero() { bail!( - span, "pattern tile size must be non-zero"; + span, "tile size must be non-zero"; hint: "try setting the size manually" ); } @@ -218,8 +222,8 @@ impl Pattern { } } -impl Pattern { - /// Set the relative placement of the pattern. +impl Tiling { + /// Set the relative placement of the tiling. pub fn with_relative(mut self, relative: RelativeTo) -> Self { if let Some(this) = Arc::get_mut(&mut self.0) { this.relative = Smart::Custom(relative); @@ -233,27 +237,27 @@ impl Pattern { self } - /// Return the frame of the pattern. + /// Return the frame of the tiling. pub fn frame(&self) -> &Frame { &self.0.frame } - /// Return the size of the pattern in absolute units. + /// Return the size of the tiling in absolute units. pub fn size(&self) -> Size { self.0.size } - /// Return the spacing of the pattern in absolute units. + /// Return the spacing of the tiling in absolute units. pub fn spacing(&self) -> Size { self.0.spacing } - /// Returns the relative placement of the pattern. + /// Returns the relative placement of the tiling. pub fn relative(&self) -> Smart { self.0.relative } - /// Returns the relative placement of the pattern. + /// Returns the relative placement of the tiling. pub fn unwrap_relative(&self, on_text: bool) -> RelativeTo { self.0.relative.unwrap_or_else(|| { if on_text { @@ -265,10 +269,10 @@ impl Pattern { } } -impl repr::Repr for Pattern { +impl repr::Repr for Tiling { fn repr(&self) -> EcoString { let mut out = - eco_format!("pattern(({}, {})", self.0.size.x.repr(), self.0.size.y.repr()); + eco_format!("tiling(({}, {})", self.0.size.x.repr(), self.0.size.y.repr()); if self.0.spacing.is_zero() { out.push_str(", spacing: ("); diff --git a/crates/typst-pdf/src/color.rs b/crates/typst-pdf/src/color.rs index 7097c14a5..412afca9a 100644 --- a/crates/typst-pdf/src/color.rs +++ b/crates/typst-pdf/src/color.rs @@ -222,7 +222,7 @@ impl PaintEncode for Paint { match self { Self::Solid(c) => c.set_as_fill(ctx, on_text, transforms), Self::Gradient(gradient) => gradient.set_as_fill(ctx, on_text, transforms), - Self::Pattern(pattern) => pattern.set_as_fill(ctx, on_text, transforms), + Self::Tiling(tiling) => tiling.set_as_fill(ctx, on_text, transforms), } } @@ -235,7 +235,7 @@ impl PaintEncode for Paint { match self { Self::Solid(c) => c.set_as_stroke(ctx, on_text, transforms), Self::Gradient(gradient) => gradient.set_as_stroke(ctx, on_text, transforms), - Self::Pattern(pattern) => pattern.set_as_stroke(ctx, on_text, transforms), + Self::Tiling(tiling) => tiling.set_as_stroke(ctx, on_text, transforms), } } } diff --git a/crates/typst-pdf/src/content.rs b/crates/typst-pdf/src/content.rs index ce72365dd..d57f20939 100644 --- a/crates/typst-pdf/src/content.rs +++ b/crates/typst-pdf/src/content.rs @@ -1,6 +1,6 @@ //! Generic writer for PDF content. //! -//! It is used to write page contents, color glyph instructions, and patterns. +//! It is used to write page contents, color glyph instructions, and tilings. //! //! See also [`pdf_writer::Content`]. @@ -96,7 +96,7 @@ pub struct Encoded { /// objects only through resources. /// /// Content streams can be used for page contents, but also to describe color -/// glyphs and patterns. +/// glyphs and tilings. pub struct Builder<'a, R = ()> { /// Settings for PDF export. pub(crate) options: &'a PdfOptions<'a>, @@ -187,7 +187,7 @@ impl State { } } -/// Subset of the state used to calculate the transform of gradients and patterns. +/// Subset of the state used to calculate the transform of gradients and tilings. #[derive(Debug, Clone, Copy)] pub(super) struct Transforms { /// The transform of the current item. @@ -229,7 +229,7 @@ impl Builder<'_, ()> { let get_opacity = |paint: &Paint| { let color = match paint { Paint::Solid(color) => *color, - Paint::Gradient(_) | Paint::Pattern(_) => return 255, + Paint::Gradient(_) | Paint::Tiling(_) => return 255, }; color.alpha().map_or(255, |v| (v * 255.0).round() as u8) @@ -330,10 +330,10 @@ impl Builder<'_, ()> { self.content.set_line_join(to_pdf_line_join(*join)); } if self.state.stroke.as_ref().map(|s| &s.dash) != Some(dash) { - if let Some(pattern) = dash { + if let Some(dash) = dash { self.content.set_dash_pattern( - pattern.array.iter().map(|l| l.to_f32()), - pattern.phase.to_f32(), + dash.array.iter().map(|l| l.to_f32()), + dash.phase.to_f32(), ); } else { self.content.set_dash_pattern([], 0.0); diff --git a/crates/typst-pdf/src/lib.rs b/crates/typst-pdf/src/lib.rs index f9b4e902d..c315684de 100644 --- a/crates/typst-pdf/src/lib.rs +++ b/crates/typst-pdf/src/lib.rs @@ -11,8 +11,8 @@ mod image; mod named_destination; mod outline; mod page; -mod pattern; mod resources; +mod tiling; use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; @@ -39,10 +39,10 @@ use crate::gradient::{write_gradients, PdfGradient}; use crate::image::write_images; use crate::named_destination::{write_named_destinations, NamedDestinations}; use crate::page::{alloc_page_refs, traverse_pages, write_page_tree, EncodedPage}; -use crate::pattern::{write_patterns, PdfPattern}; use crate::resources::{ alloc_resources_refs, write_resource_dictionaries, Resources, ResourcesRefs, }; +use crate::tiling::{write_tilings, PdfTiling}; /// Export a document into a PDF file. /// @@ -65,7 +65,7 @@ pub fn pdf(document: &PagedDocument, options: &PdfOptions) -> SourceResult, /// The IDs of written gradients. gradients: HashMap, - /// The IDs of written patterns. - patterns: HashMap, + /// The IDs of written tilings. + tilings: HashMap, /// The IDs of written external graphics states. ext_gs: HashMap, } diff --git a/crates/typst-pdf/src/resources.rs b/crates/typst-pdf/src/resources.rs index d3fde5dd7..bdbf2f1e4 100644 --- a/crates/typst-pdf/src/resources.rs +++ b/crates/typst-pdf/src/resources.rs @@ -23,7 +23,7 @@ use crate::color_font::ColorFontMap; use crate::extg::ExtGState; use crate::gradient::PdfGradient; use crate::image::EncodedImage; -use crate::pattern::PatternRemapper; +use crate::tiling::TilingRemapper; use crate::{PdfChunk, Renumber, WithEverything, WithResources}; /// All the resources that have been collected when traversing the document. @@ -31,16 +31,16 @@ use crate::{PdfChunk, Renumber, WithEverything, WithResources}; /// This does not allocate references to resources, only track what was used /// and deduplicate what can be deduplicated. /// -/// You may notice that this structure is a tree: [`PatternRemapper`] and +/// You may notice that this structure is a tree: [`TilingRemapper`] and /// [`ColorFontMap`] (that are present in the fields of [`Resources`]), /// themselves contain [`Resources`] (that will be called "sub-resources" from -/// now on). Because color glyphs and patterns are defined using content +/// now on). Because color glyphs and tilings are defined using content /// streams, just like pages, they can refer to resources too, which are tracked /// by the respective sub-resources. /// /// Each instance of this structure will become a `/Resources` dictionary in /// the final PDF. It is not possible to use a single shared dictionary for all -/// pages, patterns and color fonts, because if a resource is listed in its own +/// pages, tilings and color fonts, because if a resource is listed in its own /// `/Resources` dictionary, some PDF readers will fail to open the document. /// /// Because we need to lazily initialize sub-resources (we don't know how deep @@ -66,8 +66,8 @@ pub struct Resources { pub deferred_images: HashMap>, Span)>, /// Deduplicates gradients used across the document. pub gradients: Remapper, - /// Deduplicates patterns used across the document. - pub patterns: Option>>, + /// Deduplicates tilings used across the document. + pub tilings: Option>>, /// Deduplicates external graphics states used across the document. pub ext_gs: Remapper, /// Deduplicates color glyphs. @@ -107,8 +107,8 @@ impl Renumber for Resources { color_fonts.resources.renumber(offset); } - if let Some(patterns) = &mut self.patterns { - patterns.resources.renumber(offset); + if let Some(tilings) = &mut self.tilings { + tilings.resources.renumber(offset); } } } @@ -122,7 +122,7 @@ impl Default for Resources<()> { images: Remapper::new("Im"), deferred_images: HashMap::new(), gradients: Remapper::new("Gr"), - patterns: None, + tilings: None, ext_gs: Remapper::new("Gs"), color_fonts: None, languages: BTreeMap::new(), @@ -144,9 +144,9 @@ impl Resources<()> { images: self.images, deferred_images: self.deferred_images, gradients: self.gradients, - patterns: self - .patterns - .zip(refs.patterns.as_ref()) + tilings: self + .tilings + .zip(refs.tilings.as_ref()) .map(|(p, r)| Box::new(p.with_refs(r))), ext_gs: self.ext_gs, color_fonts: self @@ -172,8 +172,8 @@ impl Resources { if let Some(color_fonts) = &self.color_fonts { color_fonts.resources.traverse(process)?; } - if let Some(patterns) = &self.patterns { - patterns.resources.traverse(process)?; + if let Some(tilings) = &self.tilings { + tilings.resources.traverse(process)?; } Ok(()) } @@ -186,7 +186,7 @@ impl Resources { pub struct ResourcesRefs { pub reference: Ref, pub color_fonts: Option>, - pub patterns: Option>, + pub tilings: Option>, } impl Renumber for ResourcesRefs { @@ -195,8 +195,8 @@ impl Renumber for ResourcesRefs { if let Some(color_fonts) = &mut self.color_fonts { color_fonts.renumber(offset); } - if let Some(patterns) = &mut self.patterns { - patterns.renumber(offset); + if let Some(tilings) = &mut self.tilings { + tilings.renumber(offset); } } } @@ -214,8 +214,8 @@ pub fn alloc_resources_refs( .color_fonts .as_ref() .map(|c| Box::new(refs_for(&c.resources, chunk))), - patterns: resources - .patterns + tilings: resources + .tilings .as_ref() .map(|p| Box::new(refs_for(&p.resources, chunk))), } @@ -231,7 +231,7 @@ pub fn alloc_resources_refs( /// to the root node of the page tree because using the resource inheritance /// feature breaks PDF merging with Apple Preview. /// -/// Also write resource dictionaries for Type3 fonts and patterns. +/// Also write resource dictionaries for Type3 fonts and PDF patterns. pub fn write_resource_dictionaries(ctx: &WithEverything) -> SourceResult<(PdfChunk, ())> { let mut chunk = PdfChunk::new(); let mut used_color_spaces = ColorSpaces::default(); @@ -266,8 +266,8 @@ pub fn write_resource_dictionaries(ctx: &WithEverything) -> SourceResult<(PdfChu resources .gradients .write(&ctx.references.gradients, &mut patterns_dict); - if let Some(p) = &resources.patterns { - p.remapper.write(&ctx.references.patterns, &mut patterns_dict); + if let Some(p) = &resources.tilings { + p.remapper.write(&ctx.references.tilings, &mut patterns_dict); } patterns_dict.finish(); diff --git a/crates/typst-pdf/src/pattern.rs b/crates/typst-pdf/src/tiling.rs similarity index 87% rename from crates/typst-pdf/src/pattern.rs rename to crates/typst-pdf/src/tiling.rs index ddc22fbd6..f8950f344 100644 --- a/crates/typst-pdf/src/pattern.rs +++ b/crates/typst-pdf/src/tiling.rs @@ -5,7 +5,7 @@ use pdf_writer::types::{ColorSpaceOperand, PaintType, TilingType}; use pdf_writer::{Filter, Name, Rect, Ref}; use typst_library::diag::SourceResult; use typst_library::layout::{Abs, Ratio, Transform}; -use typst_library::visualize::{Pattern, RelativeTo}; +use typst_library::visualize::{RelativeTo, Tiling}; use typst_utils::Numeric; use crate::color::PaintEncode; @@ -14,18 +14,18 @@ use crate::{content, transform_to_array, PdfChunk, Resources, WithGlobalRefs}; /// Writes the actual patterns (tiling patterns) to the PDF. /// This is performed once after writing all pages. -pub fn write_patterns( +pub fn write_tilings( context: &WithGlobalRefs, -) -> SourceResult<(PdfChunk, HashMap)> { +) -> SourceResult<(PdfChunk, HashMap)> { let mut chunk = PdfChunk::new(); let mut out = HashMap::new(); context.resources.traverse(&mut |resources| { - let Some(patterns) = &resources.patterns else { + let Some(patterns) = &resources.tilings else { return Ok(()); }; for pdf_pattern in patterns.remapper.items() { - let PdfPattern { transform, pattern, content, .. } = pdf_pattern; + let PdfTiling { transform, pattern, content, .. } = pdf_pattern; if out.contains_key(pdf_pattern) { continue; } @@ -69,11 +69,11 @@ pub fn write_patterns( /// A pattern and its transform. #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct PdfPattern { +pub struct PdfTiling { /// The transform to apply to the pattern. pub transform: Transform, /// The pattern to paint. - pub pattern: Pattern, + pub pattern: Tiling, /// The rendered pattern. pub content: Vec, } @@ -81,14 +81,14 @@ pub struct PdfPattern { /// Registers a pattern with the PDF. fn register_pattern( ctx: &mut content::Builder, - pattern: &Pattern, + pattern: &Tiling, on_text: bool, mut transforms: content::Transforms, ) -> SourceResult { let patterns = ctx .resources - .patterns - .get_or_insert_with(|| Box::new(PatternRemapper::new())); + .tilings + .get_or_insert_with(|| Box::new(TilingRemapper::new())); // Edge cases for strokes. if transforms.size.x.is_zero() { @@ -113,7 +113,7 @@ fn register_pattern( None, )?; - let pdf_pattern = PdfPattern { + let pdf_pattern = PdfTiling { transform, pattern: pattern.clone(), content: content.content.wait().clone(), @@ -122,7 +122,7 @@ fn register_pattern( Ok(patterns.remapper.insert(pdf_pattern)) } -impl PaintEncode for Pattern { +impl PaintEncode for Tiling { fn set_as_fill( &self, ctx: &mut content::Builder, @@ -159,14 +159,14 @@ impl PaintEncode for Pattern { } /// De-duplicate patterns and the resources they require to be drawn. -pub struct PatternRemapper { +pub struct TilingRemapper { /// Pattern de-duplicator. - pub remapper: Remapper, + pub remapper: Remapper, /// PDF resources that are used by these patterns. pub resources: Resources, } -impl PatternRemapper<()> { +impl TilingRemapper<()> { pub fn new() -> Self { Self { remapper: Remapper::new("P"), @@ -175,8 +175,8 @@ impl PatternRemapper<()> { } /// Allocate a reference to the resource dictionary of these patterns. - pub fn with_refs(self, refs: &ResourcesRefs) -> PatternRemapper { - PatternRemapper { + pub fn with_refs(self, refs: &ResourcesRefs) -> TilingRemapper { + TilingRemapper { remapper: self.remapper, resources: self.resources.with_refs(refs), } diff --git a/crates/typst-render/src/paint.rs b/crates/typst-render/src/paint.rs index 689f28a89..ce92fd6a3 100644 --- a/crates/typst-render/src/paint.rs +++ b/crates/typst-render/src/paint.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use tiny_skia as sk; use typst_library::layout::{Axes, Point, Ratio, Size}; -use typst_library::visualize::{Color, Gradient, Paint, Pattern, RelativeTo}; +use typst_library::visualize::{Color, Gradient, Paint, RelativeTo, Tiling}; use crate::{AbsExt, State}; @@ -72,26 +72,26 @@ impl PaintSampler for GradientSampler<'_> { } } -/// State used when sampling patterns for text. +/// State used when sampling tilings for text. /// /// It caches the inverse transform to the parent, so that we can /// reuse it instead of recomputing it for each pixel. #[derive(Clone, Copy)] -pub struct PatternSampler<'a> { +pub struct TilingSampler<'a> { size: Size, transform_to_parent: sk::Transform, pixmap: &'a sk::Pixmap, pixel_per_pt: f32, } -impl<'a> PatternSampler<'a> { +impl<'a> TilingSampler<'a> { pub fn new( - pattern: &'a Pattern, + tilings: &'a Tiling, pixmap: &'a sk::Pixmap, state: &State, on_text: bool, ) -> Self { - let relative = pattern.unwrap_relative(on_text); + let relative = tilings.unwrap_relative(on_text); let fill_transform = match relative { RelativeTo::Self_ => sk::Transform::identity(), RelativeTo::Parent => state.container_transform.invert().unwrap(), @@ -99,17 +99,17 @@ impl<'a> PatternSampler<'a> { Self { pixmap, - size: (pattern.size() + pattern.spacing()) * state.pixel_per_pt as f64, + size: (tilings.size() + tilings.spacing()) * state.pixel_per_pt as f64, transform_to_parent: fill_transform, pixel_per_pt: state.pixel_per_pt, } } } -impl PaintSampler for PatternSampler<'_> { +impl PaintSampler for TilingSampler<'_> { /// Samples a single point in a glyph. fn sample(self, (x, y): (u32, u32)) -> sk::PremultipliedColorU8 { - // Compute the point in the pattern's coordinate space. + // Compute the point in the tilings's coordinate space. let mut point = sk::Point { x: x as f32, y: y as f32 }; self.transform_to_parent.map_point(&mut point); @@ -118,7 +118,7 @@ impl PaintSampler for PatternSampler<'_> { let y = (point.y * self.pixel_per_pt).rem_euclid(self.size.y.to_f32()).floor() as u32; - // Sample the pattern + // Sample the tilings self.pixmap.pixel(x, y).unwrap() } } @@ -218,8 +218,8 @@ pub fn to_sk_paint<'a>( sk_paint.anti_alias = gradient.anti_alias(); } - Paint::Pattern(pattern) => { - let relative = pattern.unwrap_relative(on_text); + Paint::Tiling(tilings) => { + let relative = tilings.unwrap_relative(on_text); let fill_transform = match relative { RelativeTo::Self_ => fill_transform.unwrap_or_default(), @@ -228,7 +228,7 @@ pub fn to_sk_paint<'a>( .post_concat(state.transform.invert().unwrap()), }; - let canvas = render_pattern_frame(&state, pattern); + let canvas = render_tiling_frame(&state, tilings); *pixmap = Some(Arc::new(canvas)); let offset = match relative { @@ -265,17 +265,17 @@ pub fn to_sk_color_u8(color: Color) -> sk::ColorU8 { sk::ColorU8::from_rgba(r, g, b, a) } -pub fn render_pattern_frame(state: &State, pattern: &Pattern) -> sk::Pixmap { - let size = pattern.size() + pattern.spacing(); +pub fn render_tiling_frame(state: &State, tilings: &Tiling) -> sk::Pixmap { + let size = tilings.size() + tilings.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, ) .unwrap(); - // Render the pattern into a new canvas. + // Render the tilings 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(), ts, state.pixel_per_pt); - crate::render_frame(&mut canvas, temp_state, pattern.frame()); + let temp_state = State::new(tilings.size(), ts, state.pixel_per_pt); + crate::render_frame(&mut canvas, temp_state, tilings.frame()); canvas } diff --git a/crates/typst-render/src/shape.rs b/crates/typst-render/src/shape.rs index f9ff7f3a9..57d8ebc1a 100644 --- a/crates/typst-render/src/shape.rs +++ b/crates/typst-render/src/shape.rs @@ -168,11 +168,11 @@ pub fn to_sk_line_join(join: LineJoin) -> sk::LineJoin { } } -pub fn to_sk_dash_pattern(pattern: &DashPattern) -> Option { +pub fn to_sk_dash_pattern(dash: &DashPattern) -> Option { // tiny-skia only allows dash patterns with an even number of elements, // while pdf allows any number. - let pattern_len = pattern.array.len(); + let pattern_len = dash.array.len(); let len = if pattern_len % 2 == 1 { 2 * pattern_len } else { pattern_len }; - let dash_array = pattern.array.iter().map(|l| l.to_f32()).cycle().take(len).collect(); - sk::StrokeDash::new(dash_array, pattern.phase.to_f32()) + let dash_array = dash.array.iter().map(|l| l.to_f32()).cycle().take(len).collect(); + sk::StrokeDash::new(dash_array, dash.phase.to_f32()) } diff --git a/crates/typst-render/src/text.rs b/crates/typst-render/src/text.rs index b47659cba..16490aff4 100644 --- a/crates/typst-render/src/text.rs +++ b/crates/typst-render/src/text.rs @@ -8,7 +8,7 @@ use typst_library::text::color::{glyph_frame, should_outline}; use typst_library::text::{Font, TextItem}; use typst_library::visualize::{FixedStroke, Paint}; -use crate::paint::{self, GradientSampler, PaintSampler, PatternSampler}; +use crate::paint::{self, GradientSampler, PaintSampler, TilingSampler}; use crate::{shape, AbsExt, State}; /// Render a text run into the canvas. @@ -145,9 +145,9 @@ fn render_outline_glyph( paint::to_sk_color_u8(*color).premultiply(), )?; } - Paint::Pattern(pattern) => { - let pixmap = paint::render_pattern_frame(&state, pattern); - let sampler = PatternSampler::new(pattern, &pixmap, &state, true); + Paint::Tiling(tiling) => { + let pixmap = paint::render_tiling_frame(&state, tiling); + let sampler = TilingSampler::new(tiling, &pixmap, &state, true); write_bitmap(canvas, &bitmap, &state, sampler)?; } } diff --git a/crates/typst-svg/src/lib.rs b/crates/typst-svg/src/lib.rs index b21fe4fb8..f99513321 100644 --- a/crates/typst-svg/src/lib.rs +++ b/crates/typst-svg/src/lib.rs @@ -14,11 +14,11 @@ use typst_library::layout::{ Abs, Frame, FrameItem, FrameKind, GroupItem, Page, PagedDocument, Point, Ratio, Size, Transform, }; -use typst_library::visualize::{Geometry, Gradient, Pattern}; +use typst_library::visualize::{Geometry, Gradient, Tiling}; use typst_utils::hash128; use xmlwriter::XmlWriter; -use crate::paint::{GradientRef, PatternRef, SVGSubGradient}; +use crate::paint::{GradientRef, SVGSubGradient, TilingRef}; use crate::text::RenderedGlyph; /// Export a frame into a SVG file. @@ -92,12 +92,12 @@ struct SVGRenderer { /// different transforms. Therefore this allows us to reuse the same gradient /// multiple times. gradient_refs: Deduplicator, - /// Deduplicated patterns with transform matrices. They use a reference - /// (`href`) to a "source" pattern instead of being defined inline. - /// This saves a lot of space since patterns are often reused but with + /// Deduplicated tilings with transform matrices. They use a reference + /// (`href`) to a "source" tiling instead of being defined inline. + /// This saves a lot of space since tilings are often reused but with /// different transforms. Therefore this allows us to reuse the same gradient /// multiple times. - pattern_refs: Deduplicator, + tiling_refs: Deduplicator, /// These are the actual gradients being written in the SVG file. /// These gradients are deduplicated because they do not contain the transform /// matrix, allowing them to be reused across multiple invocations. @@ -105,12 +105,12 @@ struct SVGRenderer { /// The `Ratio` is the aspect ratio of the gradient, this is used to correct /// the angle of the gradient. gradients: Deduplicator<(Gradient, Ratio)>, - /// These are the actual patterns being written in the SVG file. - /// These patterns are deduplicated because they do not contain the transform + /// These are the actual tilings being written in the SVG file. + /// These tilings are deduplicated because they do not contain the transform /// matrix, allowing them to be reused across multiple invocations. /// - /// The `String` is the rendered pattern frame. - patterns: Deduplicator, + /// The `String` is the rendered tiling frame. + tilings: Deduplicator, /// These are the gradients that compose a conic gradient. conic_subgradients: Deduplicator, } @@ -163,8 +163,8 @@ impl SVGRenderer { gradient_refs: Deduplicator::new('g'), gradients: Deduplicator::new('f'), conic_subgradients: Deduplicator::new('s'), - pattern_refs: Deduplicator::new('p'), - patterns: Deduplicator::new('t'), + tiling_refs: Deduplicator::new('p'), + tilings: Deduplicator::new('t'), } } @@ -272,8 +272,8 @@ impl SVGRenderer { self.write_gradients(); self.write_gradient_refs(); self.write_subgradients(); - self.write_patterns(); - self.write_pattern_refs(); + self.write_tilings(); + self.write_tiling_refs(); self.xml.end_document() } diff --git a/crates/typst-svg/src/paint.rs b/crates/typst-svg/src/paint.rs index 58348c94b..75ab41cdf 100644 --- a/crates/typst-svg/src/paint.rs +++ b/crates/typst-svg/src/paint.rs @@ -4,7 +4,7 @@ use ecow::{eco_format, EcoString}; use ttf_parser::OutlineBuilder; use typst_library::foundations::Repr; use typst_library::layout::{Angle, Axes, Frame, Quadrant, Ratio, Size, Transform}; -use typst_library::visualize::{Color, FillRule, Gradient, Paint, Pattern, RatioOrAngle}; +use typst_library::visualize::{Color, FillRule, Gradient, Paint, RatioOrAngle, Tiling}; use typst_utils::hash128; use xmlwriter::XmlWriter; @@ -17,7 +17,7 @@ const CONIC_SEGMENT: usize = 360; impl SVGRenderer { /// Render a frame to a string. - pub(super) fn render_pattern_frame( + pub(super) fn render_tiling_frame( &mut self, state: State, ts: Transform, @@ -44,8 +44,8 @@ impl SVGRenderer { let id = self.push_gradient(gradient, size, ts); self.xml.write_attribute_fmt("fill", format_args!("url(#{id})")); } - Paint::Pattern(pattern) => { - let id = self.push_pattern(pattern, size, ts); + Paint::Tiling(tiling) => { + let id = self.push_tiling(tiling, size, ts); self.xml.write_attribute_fmt("fill", format_args!("url(#{id})")); } } @@ -86,32 +86,31 @@ impl SVGRenderer { }) } - pub(super) fn push_pattern( + pub(super) fn push_tiling( &mut self, - pattern: &Pattern, + tiling: &Tiling, size: Size, ts: Transform, ) -> Id { - let pattern_size = pattern.size() + pattern.spacing(); + let tiling_size = tiling.size() + tiling.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. - self.render_pattern_frame( - State::new(pattern_size, Transform::identity()), + self.render_tiling_frame( + State::new(tiling_size, Transform::identity()), Transform::identity(), - pattern.frame(), + tiling.frame(), ); - let pattern_id = self.patterns.insert_with(hash128(pattern), || pattern.clone()); - self.pattern_refs - .insert_with(hash128(&(pattern_id, ts)), || PatternRef { - id: pattern_id, - transform: ts, - ratio: Axes::new( - Ratio::new(pattern_size.x.to_pt() / size.x.to_pt()), - Ratio::new(pattern_size.y.to_pt() / size.y.to_pt()), - ), - }) + let tiling_id = self.tilings.insert_with(hash128(tiling), || tiling.clone()); + self.tiling_refs.insert_with(hash128(&(tiling_id, ts)), || TilingRef { + id: tiling_id, + transform: ts, + ratio: Axes::new( + Ratio::new(tiling_size.x.to_pt() / size.x.to_pt()), + Ratio::new(tiling_size.y.to_pt() / size.y.to_pt()), + ), + }) } /// Write the raw gradients (without transform) to the SVG file. @@ -188,12 +187,12 @@ impl SVGRenderer { // Create the path for the segment. let mut builder = SvgPathBuilder::default(); builder.move_to( - correct_pattern_pos(center.0), - correct_pattern_pos(center.1), + correct_tiling_pos(center.0), + correct_tiling_pos(center.1), ); builder.line_to( - correct_pattern_pos(-2.0 * (theta1 + angle).cos() + center.0), - correct_pattern_pos(2.0 * (theta1 + angle).sin() + center.1), + correct_tiling_pos(-2.0 * (theta1 + angle).cos() + center.0), + correct_tiling_pos(2.0 * (theta1 + angle).sin() + center.1), ); builder.arc( (2.0, 2.0), @@ -201,10 +200,10 @@ impl SVGRenderer { 0, 1, ( - correct_pattern_pos( + correct_tiling_pos( -2.0 * (theta2 + angle).cos() + center.0, ), - correct_pattern_pos( + correct_tiling_pos( 2.0 * (theta2 + angle).sin() + center.1, ), ), @@ -370,19 +369,19 @@ impl SVGRenderer { self.xml.end_element(); } - /// Write the raw gradients (without transform) to the SVG file. - pub(super) fn write_patterns(&mut self) { - if self.patterns.is_empty() { + /// Write the raw tilings (without transform) to the SVG file. + pub(super) fn write_tilings(&mut self) { + if self.tilings.is_empty() { return; } self.xml.start_element("defs"); - self.xml.write_attribute("id", "patterns"); + self.xml.write_attribute("id", "tilings"); - for (id, pattern) in - self.patterns.iter().map(|(i, p)| (i, p.clone())).collect::>() + for (id, tiling) in + self.tilings.iter().map(|(i, p)| (i, p.clone())).collect::>() { - let size = pattern.size() + pattern.spacing(); + let size = tiling.size() + tiling.spacing(); self.xml.start_element("pattern"); self.xml.write_attribute("id", &id); self.xml.write_attribute("width", &size.x.to_pt()); @@ -396,7 +395,7 @@ impl SVGRenderer { // Render the frame. let state = State::new(size, Transform::identity()); let ts = Transform::identity(); - self.render_frame(state, ts, pattern.frame()); + self.render_frame(state, ts, tiling.frame()); self.xml.end_element(); } @@ -404,28 +403,28 @@ impl SVGRenderer { self.xml.end_element() } - /// Writes the references to the deduplicated patterns for each usage site. - pub(super) fn write_pattern_refs(&mut self) { - if self.pattern_refs.is_empty() { + /// Writes the references to the deduplicated tilings for each usage site. + pub(super) fn write_tiling_refs(&mut self) { + if self.tiling_refs.is_empty() { return; } self.xml.start_element("defs"); - self.xml.write_attribute("id", "pattern-refs"); - for (id, pattern_ref) in self.pattern_refs.iter() { + self.xml.write_attribute("id", "tilings-refs"); + for (id, tiling_ref) in self.tiling_refs.iter() { self.xml.start_element("pattern"); self.xml - .write_attribute("patternTransform", &SvgMatrix(pattern_ref.transform)); + .write_attribute("patternTransform", &SvgMatrix(tiling_ref.transform)); self.xml.write_attribute("id", &id); // Writing the href attribute to the "reference" pattern. self.xml - .write_attribute_fmt("href", format_args!("#{}", pattern_ref.id)); + .write_attribute_fmt("href", format_args!("#{}", tiling_ref.id)); // Also writing the xlink:href attribute for compatibility. self.xml - .write_attribute_fmt("xlink:href", format_args!("#{}", pattern_ref.id)); + .write_attribute_fmt("xlink:href", format_args!("#{}", tiling_ref.id)); self.xml.end_element(); } @@ -433,15 +432,15 @@ impl SVGRenderer { } } -/// A reference to a deduplicated pattern, with a transform matrix. +/// A reference to a deduplicated tiling, with a transform matrix. /// -/// Allows patterns to be reused across multiple invocations, -/// simply by changing the transform matrix. +/// Allows tilings to be reused across multiple invocations, simply by changing +/// the transform matrix. #[derive(Hash)] -pub struct PatternRef { +pub struct TilingRef { /// The ID of the deduplicated gradient id: Id, - /// The transform matrix to apply to the pattern. + /// The transform matrix to apply to the tiling. transform: Transform, /// The ratio of the size of the cell to the size of the filled area. ratio: Axes, @@ -587,7 +586,7 @@ impl ColorEncode for Color { } } -/// Maps a coordinate in a unit size square to a coordinate in the pattern. -pub fn correct_pattern_pos(x: f32) -> f32 { +/// Maps a coordinate in a unit size square to a coordinate in the tiling. +pub fn correct_tiling_pos(x: f32) -> f32 { (x + 0.5) / 2.0 } diff --git a/crates/typst-svg/src/shape.rs b/crates/typst-svg/src/shape.rs index e188ed8ba..151049d69 100644 --- a/crates/typst-svg/src/shape.rs +++ b/crates/typst-svg/src/shape.rs @@ -67,8 +67,8 @@ impl SVGRenderer { ) .post_concat(state.transform.invert().unwrap()), } - } else if let Paint::Pattern(pattern) = paint { - match pattern.unwrap_relative(false) { + } else if let Paint::Tiling(tiling) = paint { + match tiling.unwrap_relative(false) { RelativeTo::Self_ => Transform::identity(), RelativeTo::Parent => state.transform.invert().unwrap(), } @@ -112,8 +112,8 @@ impl SVGRenderer { let id = self.push_gradient(gradient, size, fill_transform); self.xml.write_attribute_fmt("stroke", format_args!("url(#{id})")); } - Paint::Pattern(pattern) => { - let id = self.push_pattern(pattern, size, fill_transform); + Paint::Tiling(tiling) => { + let id = self.push_tiling(tiling, size, fill_transform); self.xml.write_attribute_fmt("stroke", format_args!("url(#{id})")); } } @@ -137,11 +137,11 @@ impl SVGRenderer { ); self.xml .write_attribute("stroke-miterlimit", &stroke.miter_limit.get()); - if let Some(pattern) = &stroke.dash { - self.xml.write_attribute("stroke-dashoffset", &pattern.phase.to_pt()); + if let Some(dash) = &stroke.dash { + self.xml.write_attribute("stroke-dashoffset", &dash.phase.to_pt()); self.xml.write_attribute( "stroke-dasharray", - &pattern + &dash .array .iter() .map(|dash| dash.to_pt().to_string()) diff --git a/crates/typst-svg/src/text.rs b/crates/typst-svg/src/text.rs index 76cd53cb2..80de32089 100644 --- a/crates/typst-svg/src/text.rs +++ b/crates/typst-svg/src/text.rs @@ -165,7 +165,7 @@ impl SVGRenderer { ) .post_concat(state.transform.invert().unwrap()), }, - Paint::Pattern(pattern) => match pattern.unwrap_relative(true) { + Paint::Tiling(tiling) => match tiling.unwrap_relative(true) { RelativeTo::Self_ => Transform::identity(), RelativeTo::Parent => state.transform.invert().unwrap(), }, diff --git a/crates/typst-syntax/src/ast.rs b/crates/typst-syntax/src/ast.rs index 34bd0110a..45d995a92 100644 --- a/crates/typst-syntax/src/ast.rs +++ b/crates/typst-syntax/src/ast.rs @@ -163,7 +163,7 @@ pub enum Expr<'a> { Parenthesized(Parenthesized<'a>), /// An array: `(1, "hi", 12cm)`. Array(Array<'a>), - /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + /// A dictionary: `(thickness: 3pt, dash: "solid")`. Dict(Dict<'a>), /// A unary operation: `-x`. Unary(Unary<'a>), @@ -1195,7 +1195,7 @@ impl<'a> AstNode<'a> for ArrayItem<'a> { } node! { - /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + /// A dictionary: `(thickness: 3pt, dash: "solid")`. Dict } diff --git a/crates/typst-syntax/src/kind.rs b/crates/typst-syntax/src/kind.rs index a4456b9f4..0a7c160b4 100644 --- a/crates/typst-syntax/src/kind.rs +++ b/crates/typst-syntax/src/kind.rs @@ -224,7 +224,7 @@ pub enum SyntaxKind { Parenthesized, /// An array: `(1, "hi", 12cm)`. Array, - /// A dictionary: `(thickness: 3pt, pattern: dashed)`. + /// A dictionary: `(thickness: 3pt, dash: "solid")`. Dict, /// A named pair: `thickness: 3pt`. Named, diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs index cb5e2dd85..6c1778c4a 100644 --- a/crates/typst-syntax/src/parser.rs +++ b/crates/typst-syntax/src/parser.rs @@ -1077,7 +1077,7 @@ fn expr_with_paren(p: &mut Parser, atomic: bool) { /// Parses either /// - a parenthesized expression: `(1 + 2)`, or /// - an array: `(1, "hi", 12cm)`, or -/// - a dictionary: `(thickness: 3pt, pattern: dashed)`. +/// - a dictionary: `(thickness: 3pt, dash: "solid")`. fn parenthesized_or_array_or_dict(p: &mut Parser) -> SyntaxKind { let mut state = GroupState { count: 0, diff --git a/docs/changelog/0.10.0.md b/docs/changelog/0.10.0.md index 0b17bea51..5a2a3dea3 100644 --- a/docs/changelog/0.10.0.md +++ b/docs/changelog/0.10.0.md @@ -31,7 +31,7 @@ description: Changes in Typst 0.10.0 - More LaTeX commands (e.g. for quotes) are now respected in `.bib` files ## Visualization -- Added support for [patterns]($pattern) as fills and strokes +- Added support for [patterns]($tiling) as fills and strokes - The `alpha` parameter of the [`components`]($color.components) function on colors is now a named parameter **(Breaking change)** - Added support for the [Oklch]($color.oklch) color space diff --git a/docs/changelog/0.11.1.md b/docs/changelog/0.11.1.md index 3269c5586..e045914b5 100644 --- a/docs/changelog/0.11.1.md +++ b/docs/changelog/0.11.1.md @@ -37,7 +37,7 @@ description: Changes in Typst 0.11.1 ## Export - Fixed [smart quotes]($smartquote) in PDF outline -- Fixed [patterns]($pattern) with spacing in PDF +- Fixed [patterns]($tiling) with spacing in PDF - Fixed wrong PDF page labels when [page numbering]($page.numbering) was disabled after being previously enabled diff --git a/docs/guides/tables.md b/docs/guides/tables.md index d59073678..5c9cf11da 100644 --- a/docs/guides/tables.md +++ b/docs/guides/tables.md @@ -226,7 +226,7 @@ applications, while academic applications tend to use strokes instead. To add zebra stripes to a table, we use the `table` function's `fill` argument. It can take three kinds of arguments: -- A single color (this can also be a gradient or a pattern) to fill all cells +- A single color (this can also be a gradient or a tiling) to fill all cells with. Because we want some cells to have another color, this is not useful if we want to build zebra tables. - An array with colors which Typst cycles through for each column. We can use an @@ -828,7 +828,7 @@ line appears because there is no `top` line that could suppress it. ### How to achieve a double line? { #double-stroke } Typst does not yet have a native way to draw double strokes, but there are -multiple ways to emulate them, for example with [patterns]($pattern). We will +multiple ways to emulate them, for example with [tilings]($tiling). We will show a different workaround in this section: Table gutters. Tables can space their cells apart using the `gutter` argument. When a gutter is diff --git a/tests/ref/grid-stroke-pattern.png b/tests/ref/grid-stroke-tiling.png similarity index 100% rename from tests/ref/grid-stroke-pattern.png rename to tests/ref/grid-stroke-tiling.png diff --git a/tests/ref/pattern-line.png b/tests/ref/tiling-line.png similarity index 100% rename from tests/ref/pattern-line.png rename to tests/ref/tiling-line.png diff --git a/tests/ref/pattern-lines.png b/tests/ref/tiling-lines.png similarity index 100% rename from tests/ref/pattern-lines.png rename to tests/ref/tiling-lines.png diff --git a/tests/ref/tiling-pattern-compatibility.png b/tests/ref/tiling-pattern-compatibility.png new file mode 100644 index 0000000000000000000000000000000000000000..b891b6d7ccc8649f064968a63b5166411845ef0e GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@qBp9qiuIB