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};