typst_library/text/
shift.rs

1use crate::introspection::Tagged;
2use ttf_parser::Tag;
3
4use crate::foundations::{Content, Smart, elem};
5use crate::layout::{Em, Length};
6use crate::text::{FontMetrics, ScriptMetrics, TextSize};
7
8/// Renders text in subscript.
9///
10/// The text is rendered smaller and its baseline is lowered.
11///
12/// # Example
13/// ```example
14/// Revenue#sub[yearly]
15/// ```
16#[elem(title = "Subscript", Tagged)]
17pub struct SubElem {
18    /// Whether to use subscript glyphs from the font if available.
19    ///
20    /// Ideally, subscripts glyphs are provided by the font (using the `subs`
21    /// OpenType feature). Otherwise, Typst is able to synthesize subscripts by
22    /// lowering and scaling down regular glyphs.
23    ///
24    /// When this is set to `{false}`, synthesized glyphs will be used
25    /// regardless of whether the font provides dedicated subscript glyphs. When
26    /// `{true}`, synthesized glyphs may still be used in case the font does not
27    /// provide the necessary subscript glyphs.
28    ///
29    /// ```example
30    /// N#sub(typographic: true)[1]
31    /// N#sub(typographic: false)[1]
32    /// ```
33    #[default(true)]
34    pub typographic: bool,
35
36    /// The downward baseline shift for synthesized subscripts.
37    ///
38    /// This only applies to synthesized subscripts. In other words, this has no
39    /// effect if `typographic` is `{true}` and the font provides the necessary
40    /// subscript glyphs.
41    ///
42    /// If set to `{auto}`, the baseline is shifted according to the metrics
43    /// provided by the font, with a fallback to `{0.2em}` in case the font does
44    /// not define the necessary metrics.
45    pub baseline: Smart<Length>,
46
47    /// The font size for synthesized subscripts.
48    ///
49    /// This only applies to synthesized subscripts. In other words, this has no
50    /// effect if `typographic` is `{true}` and the font provides the necessary
51    /// subscript glyphs.
52    ///
53    /// If set to `{auto}`, the size is scaled according to the metrics provided
54    /// by the font, with a fallback to `{0.6em}` in case the font does not
55    /// define the necessary metrics.
56    pub size: Smart<TextSize>,
57
58    /// The text to display in subscript.
59    #[required]
60    pub body: Content,
61}
62
63/// Renders text in superscript.
64///
65/// The text is rendered smaller and its baseline is raised.
66///
67/// # Example
68/// ```example
69/// 1#super[st] try!
70/// ```
71#[elem(title = "Superscript", Tagged)]
72pub struct SuperElem {
73    /// Whether to use superscript glyphs from the font if available.
74    ///
75    /// Ideally, superscripts glyphs are provided by the font (using the `sups`
76    /// OpenType feature). Otherwise, Typst is able to synthesize superscripts
77    /// by raising and scaling down regular glyphs.
78    ///
79    /// When this is set to `{false}`, synthesized glyphs will be used
80    /// regardless of whether the font provides dedicated superscript glyphs.
81    /// When `{true}`, synthesized glyphs may still be used in case the font
82    /// does not provide the necessary superscript glyphs.
83    ///
84    /// ```example
85    /// N#super(typographic: true)[1]
86    /// N#super(typographic: false)[1]
87    /// ```
88    #[default(true)]
89    pub typographic: bool,
90
91    /// The downward baseline shift for synthesized superscripts.
92    ///
93    /// This only applies to synthesized superscripts. In other words, this has
94    /// no effect if `typographic` is `{true}` and the font provides the
95    /// necessary superscript glyphs.
96    ///
97    /// If set to `{auto}`, the baseline is shifted according to the metrics
98    /// provided by the font, with a fallback to `{-0.5em}` in case the font
99    /// does not define the necessary metrics.
100    ///
101    /// Note that, since the baseline shift is applied downward, you will need
102    /// to provide a negative value for the content to appear as raised above
103    /// the normal baseline.
104    pub baseline: Smart<Length>,
105
106    /// The font size for synthesized superscripts.
107    ///
108    /// This only applies to synthesized superscripts. In other words, this has
109    /// no effect if `typographic` is `{true}` and the font provides the
110    /// necessary superscript glyphs.
111    ///
112    /// If set to `{auto}`, the size is scaled according to the metrics provided
113    /// by the font, with a fallback to `{0.6em}` in case the font does not
114    /// define the necessary metrics.
115    pub size: Smart<TextSize>,
116
117    /// The text to display in superscript.
118    #[required]
119    pub body: Content,
120}
121
122/// Configuration values for sub- or superscript text.
123#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
124pub struct ShiftSettings {
125    /// Whether the OpenType feature should be used if possible.
126    pub typographic: bool,
127    /// The baseline shift of the script, relative to the outer text size.
128    ///
129    /// For superscripts, this is positive. For subscripts, this is negative. A
130    /// value of [`Smart::Auto`] indicates that the value should be obtained
131    /// from font metrics.
132    pub shift: Smart<Em>,
133    /// The size of the script, relative to the outer text size.
134    ///
135    /// A value of [`Smart::Auto`] indicates that the value should be obtained
136    /// from font metrics.
137    pub size: Smart<Em>,
138    /// The kind of script (either a subscript, or a superscript).
139    ///
140    /// This is used to know which OpenType table to use to resolve
141    /// [`Smart::Auto`] values.
142    pub kind: ScriptKind,
143}
144
145#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
146pub enum ScriptKind {
147    Sub,
148    Super,
149}
150
151impl ScriptKind {
152    /// Returns the default metrics for this script kind.
153    ///
154    /// This can be used as a last resort if neither the user nor the font
155    /// provided those metrics.
156    pub fn default_metrics(self) -> &'static ScriptMetrics {
157        match self {
158            Self::Sub => &DEFAULT_SUBSCRIPT_METRICS,
159            Self::Super => &DEFAULT_SUPERSCRIPT_METRICS,
160        }
161    }
162
163    /// Reads the script metrics from the font table for to this script kind.
164    pub fn read_metrics(self, font_metrics: &FontMetrics) -> &ScriptMetrics {
165        match self {
166            Self::Sub => font_metrics.subscript.as_ref(),
167            Self::Super => font_metrics.superscript.as_ref(),
168        }
169        .unwrap_or(self.default_metrics())
170    }
171
172    /// The corresponding OpenType feature.
173    pub const fn feature(self) -> Tag {
174        match self {
175            Self::Sub => Tag::from_bytes(b"subs"),
176            Self::Super => Tag::from_bytes(b"sups"),
177        }
178    }
179}
180pub static DEFAULT_SUBSCRIPT_METRICS: ScriptMetrics = ScriptMetrics {
181    width: Em::new(0.6),
182    height: Em::new(0.6),
183    horizontal_offset: Em::zero(),
184    vertical_offset: Em::new(-0.2),
185};
186
187pub static DEFAULT_SUPERSCRIPT_METRICS: ScriptMetrics = ScriptMetrics {
188    width: Em::new(0.6),
189    height: Em::new(0.6),
190    horizontal_offset: Em::zero(),
191    vertical_offset: Em::new(0.5),
192};