xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/skrifa-0.15.5/src/instance.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //! Helpers for selecting a font size and location in variation space.
2 
3 use read_fonts::types::Fixed;
4 
5 use crate::small_array::SmallArray;
6 
7 /// Type for a normalized variation coordinate.
8 pub type NormalizedCoord = read_fonts::types::F2Dot14;
9 
10 /// Font size in pixels per em units.
11 ///
12 /// Sizes in this crate are represented as a ratio of pixels to the size of
13 /// the em square defined by the font. This is equivalent to the `px` unit
14 /// in CSS (assuming a DPI scale factor of 1.0).
15 ///
16 /// To retrieve metrics and outlines in font units, use the [unscaled](Self::unscaled)
17 /// construtor on this type.
18 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
19 pub struct Size(Option<f32>);
20 
21 impl Size {
22     /// Creates a new font size from the given value in pixels per em units.
new(ppem: f32) -> Self23     pub fn new(ppem: f32) -> Self {
24         Self(Some(ppem))
25     }
26 
27     /// Creates a new font size for generating unscaled metrics or outlines in
28     /// font units.
unscaled() -> Self29     pub fn unscaled() -> Self {
30         Self(None)
31     }
32 
33     /// Returns the raw size in pixels per em units.
34     ///
35     /// Results in `None` if the size is unscaled.
ppem(self) -> Option<f32>36     pub fn ppem(self) -> Option<f32> {
37         self.0
38     }
39 
40     /// Computes a linear scale factor for this font size and the given units
41     /// per em value which can be retrieved from the [Metrics](crate::metrics::Metrics)
42     /// type or from the [head](read_fonts::tables::head::Head) table.
43     ///
44     /// Returns 1.0 for an unscaled size or when `units_per_em` is 0.
linear_scale(self, units_per_em: u16) -> f3245     pub fn linear_scale(self, units_per_em: u16) -> f32 {
46         match self.0 {
47             Some(ppem) if units_per_em != 0 => ppem / units_per_em as f32,
48             _ => 1.0,
49         }
50     }
51 
52     /// Computes a fixed point linear scale factor that matches FreeType.
fixed_linear_scale(self, units_per_em: u16) -> Fixed53     pub(crate) fn fixed_linear_scale(self, units_per_em: u16) -> Fixed {
54         // FreeType computes a 16.16 scale factor that converts to 26.6.
55         // This is done in two steps, assuming use of FT_Set_Pixel_Size:
56         // 1) height is multiplied by 64:
57         //    <https://gitlab.freedesktop.org/freetype/freetype/-/blob/49781ab72b2dfd0f78172023921d08d08f323ade/src/base/ftobjs.c#L3596>
58         // 2) this value is divided by UPEM:
59         //    (here, scaled_h=height and h=upem)
60         //    <https://gitlab.freedesktop.org/freetype/freetype/-/blob/49781ab72b2dfd0f78172023921d08d08f323ade/src/base/ftobjs.c#L3312>
61         match self.0 {
62             Some(ppem) if units_per_em > 0 => {
63                 Fixed::from_bits((ppem * 64.) as i32) / Fixed::from_bits(units_per_em as i32)
64             }
65             _ => {
66                 // This is an identity scale for the pattern
67                 // `mul_div(value, scale, 64)`
68                 Fixed::from_bits(0x10000 * 64)
69             }
70         }
71     }
72 }
73 
74 /// Reference to an ordered sequence of normalized variation coordinates.
75 ///
76 /// This type represents a position in the variation space where each
77 /// coordinate corresponds to an axis (in the same order as the `fvar` table)
78 /// and is a normalized value in the range `[-1..1]`.
79 ///
80 /// See [Coordinate Scales and Normalization](https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview#coordinate-scales-and-normalization)
81 /// for further details.
82 ///
83 /// If the array is larger in length than the number of axes, extraneous
84 /// values are ignored. If it is smaller, unrepresented axes are assumed to be
85 /// at their default positions (i.e. 0).
86 ///
87 /// A value of this type constructed with `default()` represents the default
88 /// position for each axis.
89 ///
90 /// Normalized coordinates are ignored for non-variable fonts.
91 #[derive(Copy, Clone, Default, Debug)]
92 pub struct LocationRef<'a>(&'a [NormalizedCoord]);
93 
94 impl<'a> LocationRef<'a> {
95     /// Creates a new sequence of normalized coordinates from the given array.
new(coords: &'a [NormalizedCoord]) -> Self96     pub fn new(coords: &'a [NormalizedCoord]) -> Self {
97         Self(coords)
98     }
99 
100     /// Returns the underlying array of normalized coordinates.
coords(&self) -> &'a [NormalizedCoord]101     pub fn coords(&self) -> &'a [NormalizedCoord] {
102         self.0
103     }
104 }
105 
106 impl<'a> From<&'a [NormalizedCoord]> for LocationRef<'a> {
from(value: &'a [NormalizedCoord]) -> Self107     fn from(value: &'a [NormalizedCoord]) -> Self {
108         Self(value)
109     }
110 }
111 
112 impl<'a> IntoIterator for LocationRef<'a> {
113     type IntoIter = core::slice::Iter<'a, NormalizedCoord>;
114     type Item = &'a NormalizedCoord;
115 
into_iter(self) -> Self::IntoIter116     fn into_iter(self) -> Self::IntoIter {
117         self.0.iter()
118     }
119 }
120 
121 impl<'a> IntoIterator for &'_ LocationRef<'a> {
122     type IntoIter = core::slice::Iter<'a, NormalizedCoord>;
123     type Item = &'a NormalizedCoord;
124 
into_iter(self) -> Self::IntoIter125     fn into_iter(self) -> Self::IntoIter {
126         self.0.iter()
127     }
128 }
129 
130 /// Maximum number of coords to store inline in a `Location` object.
131 ///
132 /// This value was chosen to maximize use of space in the underlying
133 /// `SmallArray` storage.
134 const MAX_INLINE_COORDS: usize = 8;
135 
136 /// Ordered sequence of normalized variation coordinates.
137 ///
138 /// This is an owned version of [`LocationRef`]. See the documentation on that
139 /// type for more detail.
140 #[derive(Clone, Debug)]
141 pub struct Location {
142     coords: SmallArray<NormalizedCoord, MAX_INLINE_COORDS>,
143 }
144 
145 impl Location {
146     /// Creates a new location with the given number of normalized coordinates.
147     ///
148     /// Each element will be initialized to the default value (0.0).
new(len: usize) -> Self149     pub fn new(len: usize) -> Self {
150         Self {
151             coords: SmallArray::new(NormalizedCoord::default(), len),
152         }
153     }
154 
155     /// Returns the underlying slice of normalized coordinates.
coords(&self) -> &[NormalizedCoord]156     pub fn coords(&self) -> &[NormalizedCoord] {
157         self.coords.as_slice()
158     }
159 
160     /// Returns a mutable reference to the underlying slice of normalized
161     /// coordinates.
coords_mut(&mut self) -> &mut [NormalizedCoord]162     pub fn coords_mut(&mut self) -> &mut [NormalizedCoord] {
163         self.coords.as_mut_slice()
164     }
165 }
166 
167 impl Default for Location {
default() -> Self168     fn default() -> Self {
169         Self {
170             coords: SmallArray::new(NormalizedCoord::default(), 0),
171         }
172     }
173 }
174 
175 impl<'a> From<&'a Location> for LocationRef<'a> {
from(value: &'a Location) -> Self176     fn from(value: &'a Location) -> Self {
177         LocationRef(value.coords())
178     }
179 }
180 
181 impl<'a> IntoIterator for &'a Location {
182     type IntoIter = core::slice::Iter<'a, NormalizedCoord>;
183     type Item = &'a NormalizedCoord;
184 
into_iter(self) -> Self::IntoIter185     fn into_iter(self) -> Self::IntoIter {
186         self.coords().iter()
187     }
188 }
189 
190 impl<'a> IntoIterator for &'a mut Location {
191     type IntoIter = core::slice::IterMut<'a, NormalizedCoord>;
192     type Item = &'a mut NormalizedCoord;
193 
into_iter(self) -> Self::IntoIter194     fn into_iter(self) -> Self::IntoIter {
195         self.coords_mut().iter_mut()
196     }
197 }
198