diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-07-02 19:59:52 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-07-02 20:07:43 +0200 |
| commit | ebfdb1dafa430786db10dad2ef7d5467c1bdbed1 (patch) | |
| tree | 2bbc24ddb4124c4bb14dec0e536129d4de37b056 /library/src/text/mod.rs | |
| parent | 3ab19185093d7709f824b95b979060ce125389d8 (diff) | |
Move everything into `crates/` directory
Diffstat (limited to 'library/src/text/mod.rs')
| -rw-r--r-- | library/src/text/mod.rs | 769 |
1 files changed, 0 insertions, 769 deletions
diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs deleted file mode 100644 index ff8cbad8..00000000 --- a/library/src/text/mod.rs +++ /dev/null @@ -1,769 +0,0 @@ -//! Text handling. - -mod deco; -mod misc; -mod quotes; -mod raw; -mod shaping; -mod shift; - -pub use self::deco::*; -pub use self::misc::*; -pub use self::quotes::*; -pub use self::raw::*; -pub use self::shaping::*; -pub use self::shift::*; - -use rustybuzz::Tag; -use typst::font::{FontMetrics, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; - -use crate::layout::ParElem; -use crate::prelude::*; - -/// Hook up all text definitions. -pub(super) fn define(global: &mut Scope) { - global.define("text", TextElem::func()); - global.define("linebreak", LinebreakElem::func()); - global.define("smartquote", SmartQuoteElem::func()); - global.define("strong", StrongElem::func()); - global.define("emph", EmphElem::func()); - global.define("lower", lower_func()); - global.define("upper", upper_func()); - global.define("smallcaps", smallcaps_func()); - global.define("sub", SubElem::func()); - global.define("super", SuperElem::func()); - global.define("underline", UnderlineElem::func()); - global.define("strike", StrikeElem::func()); - global.define("overline", OverlineElem::func()); - global.define("raw", RawElem::func()); - global.define("lorem", lorem_func()); -} - -/// Customizes the look and layout of text in a variety of ways. -/// -/// This function is used frequently, both with set rules and directly. While -/// the set rule is often the simpler choice, calling the `text` function -/// directly can be useful when passing text as an argument to another function. -/// -/// ## Example { #example } -/// ```example -/// #set text(18pt) -/// With a set rule. -/// -/// #emph(text(blue)[ -/// With a function call. -/// ]) -/// ``` -/// -/// Display: Text -/// Category: text -#[element(Construct, PlainText)] -pub struct TextElem { - /// A prioritized sequence of font families. - /// - /// When processing text, Typst tries all specified font families in order - /// until it finds a font that has the necessary glyphs. In the example - /// below, the font `Inria Serif` is preferred, but since it does not - /// contain Arabic glyphs, the arabic text uses `Noto Sans Arabic` instead. - /// - /// ```example - /// #set text(font: ( - /// "Inria Serif", - /// "Noto Sans Arabic", - /// )) - /// - /// This is Latin. \ - /// هذا عربي. - /// - /// ``` - #[default(FontList(vec![FontFamily::new("Linux Libertine")]))] - pub font: FontList, - - /// Whether to allow last resort font fallback when the primary font list - /// contains no match. This lets Typst search through all available fonts - /// for the most similar one that has the necessary glyphs. - /// - /// _Note:_ Currently, there are no warnings when fallback is disabled and - /// no glyphs are found. Instead, your text shows up in the form of "tofus": - /// Small boxes that indicate the lack of an appropriate glyph. In the - /// future, you will be able to instruct Typst to issue warnings so you know - /// something is up. - /// - /// ```example - /// #set text(font: "Inria Serif") - /// هذا عربي - /// - /// #set text(fallback: false) - /// هذا عربي - /// ``` - #[default(true)] - pub fallback: bool, - - /// The desired font style. - /// - /// When an italic style is requested and only an oblique one is available, - /// it is used. Similarly, the other way around, an italic style can stand - /// in for an oblique one. When neither an italic nor an oblique style is - /// available, Typst selects the normal style. Since most fonts are only - /// available either in an italic or oblique style, the difference between - /// italic and oblique style is rarely observable. - /// - /// If you want to emphasize your text, you should do so using the - /// [emph]($func/emph) function instead. This makes it easy to adapt the - /// style later if you change your mind about how to signify the emphasis. - /// - /// ```example - /// #text(font: "Linux Libertine", style: "italic")[Italic] - /// #text(font: "DejaVu Sans", style: "oblique")[Oblique] - /// ``` - pub style: FontStyle, - - /// The desired thickness of the font's glyphs. Accepts an integer between - /// `{100}` and `{900}` or one of the predefined weight names. When the - /// desired weight is not available, Typst selects the font from the family - /// that is closest in weight. - /// - /// If you want to strongly emphasize your text, you should do so using the - /// [strong]($func/strong) function instead. This makes it easy to adapt the - /// style later if you change your mind about how to signify the strong - /// emphasis. - /// - /// ```example - /// #set text(font: "IBM Plex Sans") - /// - /// #text(weight: "light")[Light] \ - /// #text(weight: "regular")[Regular] \ - /// #text(weight: "medium")[Medium] \ - /// #text(weight: 500)[Medium] \ - /// #text(weight: "bold")[Bold] - /// ``` - pub weight: FontWeight, - - /// The desired width of the glyphs. Accepts a ratio between `{50%}` and - /// `{200%}`. When the desired weight is not available, Typst selects the - /// font from the family that is closest in stretch. This will only stretch - /// the text if a condensed or expanded version of the font is available. - /// - /// If you want to adjust the amount of space between characters instead of - /// stretching the glyphs itself, use the [`tracking`]($func/text.tracking) - /// property instead. - /// - /// ```example - /// #text(stretch: 75%)[Condensed] \ - /// #text(stretch: 100%)[Normal] - /// ``` - pub stretch: FontStretch, - - /// The size of the glyphs. This value forms the basis of the `em` unit: - /// `{1em}` is equivalent to the font size. - /// - /// You can also give the font size itself in `em` units. Then, it is - /// relative to the previous font size. - /// - /// ```example - /// #set text(size: 20pt) - /// very #text(1.5em)[big] text - /// ``` - #[parse(args.named_or_find("size")?)] - #[fold] - #[default(Abs::pt(11.0))] - pub size: TextSize, - - /// The glyph fill color. - /// - /// ```example - /// #set text(fill: red) - /// This text is red. - /// ``` - #[parse(args.named_or_find("fill")?)] - #[default(Color::BLACK.into())] - pub fill: Paint, - - /// The amount of space that should be added between characters. - /// - /// ```example - /// #set text(tracking: 1.5pt) - /// Distant text. - /// ``` - #[resolve] - pub tracking: Length, - - /// The amount of space between words. - /// - /// Can be given as an absolute length, but also relative to the width of - /// the space character in the font. - /// - /// If you want to adjust the amount of space between characters rather than - /// words, use the [`tracking`]($func/text.tracking) property instead. - /// - /// ```example - /// #set text(spacing: 200%) - /// Text with distant words. - /// ``` - #[resolve] - #[default(Rel::one())] - pub spacing: Rel<Length>, - - /// An amount to shift the text baseline by. - /// - /// ```example - /// A #text(baseline: 3pt)[lowered] - /// word. - /// ``` - #[resolve] - pub baseline: Length, - - /// Whether certain glyphs can hang over into the margin in justified text. - /// This can make justification visually more pleasing. - /// - /// ```example - /// #set par(justify: true) - /// This justified text has a hyphen in - /// the paragraph's first line. Hanging - /// the hyphen slightly into the margin - /// results in a clearer paragraph edge. - /// - /// #set text(overhang: false) - /// This justified text has a hyphen in - /// the paragraph's first line. Hanging - /// the hyphen slightly into the margin - /// results in a clearer paragraph edge. - /// ``` - #[default(true)] - pub overhang: bool, - - /// The top end of the conceptual frame around the text used for layout and - /// positioning. This affects the size of containers that hold text. - /// - /// ```example - /// #set rect(inset: 0pt) - /// #set text(size: 20pt) - /// - /// #set text(top-edge: "ascender") - /// #rect(fill: aqua)[Typst] - /// - /// #set text(top-edge: "cap-height") - /// #rect(fill: aqua)[Typst] - /// ``` - #[default(TextEdge::Metric(VerticalFontMetric::CapHeight))] - pub top_edge: TextEdge, - - /// The bottom end of the conceptual frame around the text used for layout - /// and positioning. This affects the size of containers that hold text. - /// - /// ```example - /// #set rect(inset: 0pt) - /// #set text(size: 20pt) - /// - /// #set text(bottom-edge: "baseline") - /// #rect(fill: aqua)[Typst] - /// - /// #set text(bottom-edge: "descender") - /// #rect(fill: aqua)[Typst] - /// ``` - #[default(TextEdge::Metric(VerticalFontMetric::Baseline))] - pub bottom_edge: TextEdge, - - /// An [ISO 639-1/2/3 language code.](https://en.wikipedia.org/wiki/ISO_639) - /// - /// Setting the correct language affects various parts of Typst: - /// - /// - The text processing pipeline can make more informed choices. - /// - Hyphenation will use the correct patterns for the language. - /// - [Smart quotes]($func/smartquote) turns into the correct quotes for the - /// language. - /// - And all other things which are language-aware. - /// - /// ```example - /// #set text(lang: "de") - /// #outline() - /// - /// = Einleitung - /// In diesem Dokument, ... - /// ``` - #[default(Lang::ENGLISH)] - pub lang: Lang, - - /// An [ISO 3166-1 alpha-2 region code.](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - /// - /// This lets the text processing pipeline make more informed choices. - pub region: Option<Region>, - - /// The dominant direction for text and inline objects. Possible values are: - /// - /// - `{auto}`: Automatically infer the direction from the `lang` property. - /// - `{ltr}`: Layout text from left to right. - /// - `{rtl}`: Layout text from right to left. - /// - /// When writing in right-to-left scripts like Arabic or Hebrew, you should - /// set the [text language]($func/text.lang) or direction. While individual - /// runs of text are automatically layouted in the correct direction, - /// setting the dominant direction gives the bidirectional reordering - /// algorithm the necessary information to correctly place punctuation and - /// inline objects. Furthermore, setting the direction affects the alignment - /// values `start` and `end`, which are equivalent to `left` and `right` in - /// `ltr` text and the other way around in `rtl` text. - /// - /// If you set this to `rtl` and experience bugs or in some way bad looking - /// output, please do get in touch with us through the - /// [contact form](https://typst.app/contact) or our - /// [Discord server]($community/#discord)! - /// - /// ```example - /// #set text(dir: rtl) - /// هذا عربي. - /// ``` - #[resolve] - pub dir: TextDir, - - /// Whether to hyphenate text to improve line breaking. When `{auto}`, text - /// will be hyphenated if and only if justification is enabled. - /// - /// Setting the [text language]($func/text.lang) ensures that the correct - /// hyphenation patterns are used. - /// - /// ```example - /// #set page(width: 200pt) - /// - /// #set par(justify: true) - /// This text illustrates how - /// enabling hyphenation can - /// improve justification. - /// - /// #set text(hyphenate: false) - /// This text illustrates how - /// enabling hyphenation can - /// improve justification. - /// ``` - #[resolve] - pub hyphenate: Hyphenate, - - /// Whether to apply kerning. - /// - /// When enabled, specific letter pairings move closer together or further - /// apart for a more visually pleasing result. The example below - /// demonstrates how decreasing the gap between the "T" and "o" results in a - /// more natural look. Setting this to `{false}` disables kerning by turning - /// off the OpenType `kern` font feature. - /// - /// ```example - /// #set text(size: 25pt) - /// Totally - /// - /// #set text(kerning: false) - /// Totally - /// ``` - #[default(true)] - pub kerning: bool, - - /// Whether to apply stylistic alternates. - /// - /// Sometimes fonts contain alternative glyphs for the same codepoint. - /// Setting this to `{true}` switches to these by enabling the OpenType - /// `salt` font feature. - /// - /// ```example - /// #set text( - /// font: "IBM Plex Sans", - /// size: 20pt, - /// ) - /// - /// 0, a, g, ß - /// - /// #set text(alternates: true) - /// 0, a, g, ß - /// ``` - #[default(false)] - pub alternates: bool, - - /// Which stylistic set to apply. Font designers can categorize alternative - /// glyphs forms into stylistic sets. As this value is highly font-specific, - /// you need to consult your font to know which sets are available. When set - /// to an integer between `{1}` and `{20}`, enables the corresponding - /// OpenType font feature from `ss01`, ..., `ss20`. - pub stylistic_set: Option<StylisticSet>, - - /// Whether standard ligatures are active. - /// - /// Certain letter combinations like "fi" are often displayed as a single - /// merged glyph called a _ligature._ Setting this to `{false}` disables - /// these ligatures by turning off the OpenType `liga` and `clig` font - /// features. - /// - /// ```example - /// #set text(size: 20pt) - /// A fine ligature. - /// - /// #set text(ligatures: false) - /// A fine ligature. - /// ``` - #[default(true)] - pub ligatures: bool, - - /// Whether ligatures that should be used sparingly are active. Setting this - /// to `{true}` enables the OpenType `dlig` font feature. - #[default(false)] - pub discretionary_ligatures: bool, - - /// Whether historical ligatures are active. Setting this to `{true}` - /// enables the OpenType `hlig` font feature. - #[default(false)] - pub historical_ligatures: bool, - - /// Which kind of numbers / figures to select. When set to `{auto}`, the - /// default numbers for the font are used. - /// - /// ```example - /// #set text(font: "Noto Sans", 20pt) - /// #set text(number-type: "lining") - /// Number 9. - /// - /// #set text(number-type: "old-style") - /// Number 9. - /// ``` - pub number_type: Smart<NumberType>, - - /// The width of numbers / figures. When set to `{auto}`, the default - /// numbers for the font are used. - /// - /// ```example - /// #set text(font: "Noto Sans", 20pt) - /// #set text(number-width: "proportional") - /// A 12 B 34. \ - /// A 56 B 78. - /// - /// #set text(number-width: "tabular") - /// A 12 B 34. \ - /// A 56 B 78. - /// ``` - pub number_width: Smart<NumberWidth>, - - /// Whether to have a slash through the zero glyph. Setting this to `{true}` - /// enables the OpenType `zero` font feature. - /// - /// ```example - /// 0, #text(slashed-zero: true)[0] - /// ``` - #[default(false)] - pub slashed_zero: bool, - - /// Whether to turn numbers into fractions. Setting this to `{true}` - /// enables the OpenType `frac` font feature. - /// - /// It is not advisable to enable this property globally as it will mess - /// with all appearances of numbers after a slash (e.g., in URLs). Instead, - /// enable it locally when you want a fraction. - /// - /// ```example - /// 1/2 \ - /// #text(fractions: true)[1/2] - /// ``` - #[default(false)] - pub fractions: bool, - - /// Raw OpenType features to apply. - /// - /// - If given an array of strings, sets the features identified by the - /// strings to `{1}`. - /// - If given a dictionary mapping to numbers, sets the features - /// identified by the keys to the values. - /// - /// ```example - /// // Enable the `frac` feature manually. - /// #set text(features: ("frac",)) - /// 1/2 - /// ``` - #[fold] - pub features: FontFeatures, - - /// Content in which all text is styled according to the other arguments. - #[external] - #[required] - pub body: Content, - - /// The text. - #[internal] - #[required] - pub text: EcoString, - - /// A delta to apply on the font weight. - #[internal] - #[fold] - pub delta: Delta, - - /// Whether the font style should be inverted. - #[internal] - #[fold] - #[default(false)] - pub emph: Toggle, - - /// Decorative lines. - #[internal] - #[fold] - pub deco: Decoration, - - /// A case transformation that should be applied to the text. - #[internal] - pub case: Option<Case>, - - /// Whether small capital glyphs should be used. ("smcp") - #[internal] - #[default(false)] - pub smallcaps: bool, -} - -impl TextElem { - /// Create a new packed text element. - pub fn packed(text: impl Into<EcoString>) -> Content { - Self::new(text.into()).pack() - } -} - -impl Construct for TextElem { - fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { - // The text constructor is special: It doesn't create a text element. - // Instead, it leaves the passed argument structurally unchanged, but - // styles all text in it. - let styles = Self::set(args)?; - let body = args.expect::<Content>("body")?; - Ok(body.styled_with_map(styles)) - } -} - -impl PlainText for TextElem { - fn plain_text(&self, text: &mut EcoString) { - text.push_str(&self.text()); - } -} - -/// A lowercased font family like "arial". -#[derive(Clone, Eq, PartialEq, Hash)] -pub struct FontFamily(EcoString); - -impl FontFamily { - /// Create a named font family variant. - pub fn new(string: &str) -> Self { - Self(string.to_lowercase().into()) - } - - /// The lowercased family name. - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl Debug for FontFamily { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -cast! { - FontFamily, - self => self.0.into_value(), - string: EcoString => Self::new(&string), -} - -/// Font family fallback list. -#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] -pub struct FontList(pub Vec<FontFamily>); - -impl IntoIterator for FontList { - type IntoIter = std::vec::IntoIter<FontFamily>; - type Item = FontFamily; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -cast! { - FontList, - self => if self.0.len() == 1 { - self.0.into_iter().next().unwrap().0.into_value() - } else { - self.0.into_value() - }, - family: FontFamily => Self(vec![family]), - values: Array => Self(values.into_iter().map(|v| v.cast()).collect::<StrResult<_>>()?), -} - -/// The size of text. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct TextSize(pub Length); - -impl Fold for TextSize { - type Output = Abs; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.0.em.at(outer) + self.0.abs - } -} - -cast! { - TextSize, - self => self.0.into_value(), - v: Length => Self(v), -} - -/// Specifies the bottom or top edge of text. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum TextEdge { - /// An edge specified using one of the well-known font metrics. - Metric(VerticalFontMetric), - /// An edge specified as a length. - Length(Length), -} - -impl TextEdge { - /// Resolve the value of the text edge given a font's metrics. - pub fn resolve(self, styles: StyleChain, metrics: &FontMetrics) -> Abs { - match self { - Self::Metric(metric) => metrics.vertical(metric).resolve(styles), - Self::Length(length) => length.resolve(styles), - } - } -} - -cast! { - TextEdge, - self => match self { - Self::Metric(metric) => metric.into_value(), - Self::Length(length) => length.into_value(), - }, - v: VerticalFontMetric => Self::Metric(v), - v: Length => Self::Length(v), -} - -/// The direction of text and inline objects in their line. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] -pub struct TextDir(pub Smart<Dir>); - -cast! { - TextDir, - self => self.0.into_value(), - v: Smart<Dir> => { - if v.map_or(false, |dir| dir.axis() == Axis::Y) { - bail!("text direction must be horizontal"); - } - Self(v) - }, -} - -impl Resolve for TextDir { - type Output = Dir; - - fn resolve(self, styles: StyleChain) -> Self::Output { - match self.0 { - Smart::Auto => TextElem::lang_in(styles).dir(), - Smart::Custom(dir) => dir, - } - } -} - -/// Whether to hyphenate text. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] -pub struct Hyphenate(pub Smart<bool>); - -cast! { - Hyphenate, - self => self.0.into_value(), - v: Smart<bool> => Self(v), -} - -impl Resolve for Hyphenate { - type Output = bool; - - fn resolve(self, styles: StyleChain) -> Self::Output { - match self.0 { - Smart::Auto => ParElem::justify_in(styles), - Smart::Custom(v) => v, - } - } -} - -/// A stylistic set in a font. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct StylisticSet(u8); - -impl StylisticSet { - /// Create a new set, clamping to 1-20. - pub fn new(index: u8) -> Self { - Self(index.clamp(1, 20)) - } - - /// Get the value, guaranteed to be 1-20. - pub fn get(self) -> u8 { - self.0 - } -} - -cast! { - StylisticSet, - self => self.0.into_value(), - v: i64 => match v { - 1 ..= 20 => Self::new(v as u8), - _ => bail!("stylistic set must be between 1 and 20"), - }, -} - -/// Which kind of numbers / figures to select. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] -pub enum NumberType { - /// Numbers that fit well with capital text (the OpenType `lnum` - /// font feature). - Lining, - /// Numbers that fit well into a flow of upper- and lowercase text (the - /// OpenType `onum` font feature). - OldStyle, -} - -/// The width of numbers / figures. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] -pub enum NumberWidth { - /// Numbers with glyph-specific widths (the OpenType `pnum` font feature). - Proportional, - /// Numbers of equal width (the OpenType `tnum` font feature). - Tabular, -} - -/// OpenType font features settings. -#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] -pub struct FontFeatures(pub Vec<(Tag, u32)>); - -cast! { - FontFeatures, - self => self.0 - .into_iter() - .map(|(tag, num)| { - let bytes = tag.to_bytes(); - let key = std::str::from_utf8(&bytes).unwrap_or_default(); - (key.into(), num.into_value()) - }) - .collect::<Dict>() - .into_value(), - values: Array => Self(values - .into_iter() - .map(|v| { - let tag = v.cast::<EcoString>()?; - Ok((Tag::from_bytes_lossy(tag.as_bytes()), 1)) - }) - .collect::<StrResult<_>>()?), - values: Dict => Self(values - .into_iter() - .map(|(k, v)| { - let num = v.cast::<u32>()?; - let tag = Tag::from_bytes_lossy(k.as_bytes()); - Ok((tag, num)) - }) - .collect::<StrResult<_>>()?), -} - -impl Fold for FontFeatures { - type Output = Self; - - fn fold(mut self, outer: Self::Output) -> Self::Output { - self.0.extend(outer.0); - self - } -} |
