1use read_fonts::types::{F2Dot14, Fixed, GlyphId};
2use read_fonts::{FontRef, TableProvider};
3use smallvec::SmallVec;
4
5use super::aat::AatTables;
6use super::charmap::{cache_t as cmap_cache_t, Charmap};
7use super::glyph_metrics::GlyphMetrics;
8use super::glyph_names::GlyphNames;
9use super::ot::{LayoutTable, OtCache, OtTables};
10use super::ot_layout::TableIndex;
11use super::ot_shape::{hb_ot_shape_context_t, shape_internal};
12use crate::hb::aat::AatCache;
13use crate::hb::buffer::hb_buffer_t;
14use crate::hb::tables::TableOffsets;
15use crate::{script, Feature, GlyphBuffer, NormalizedCoord, ShapePlan, UnicodeBuffer, Variation};
16
17pub struct ShaperData {
19 table_offsets: TableOffsets,
20 ot_cache: OtCache,
21 aat_cache: AatCache,
22 cmap_cache: cmap_cache_t,
23}
24
25impl ShaperData {
26 pub fn new(font: &FontRef) -> Self {
28 let ot_cache = OtCache::new(font);
29 let aat_cache = AatCache::new(font);
30 let table_offsets = TableOffsets::new(font);
31 let cmap_cache = cmap_cache_t::new();
32 Self {
33 table_offsets,
34 ot_cache,
35 aat_cache,
36 cmap_cache,
37 }
38 }
39
40 pub fn shaper<'a>(&'a self, font: &FontRef<'a>) -> ShaperBuilder<'a> {
43 ShaperBuilder {
44 data: self,
45 font: font.clone(),
46 instance: None,
47 point_size: None,
48 }
49 }
50}
51
52const MAX_INLINE_COORDS: usize = 11;
57
58#[derive(Clone, Default, Debug)]
60pub struct ShaperInstance {
61 coords: SmallVec<[F2Dot14; MAX_INLINE_COORDS]>,
62 pub(crate) feature_variations: [Option<u32>; 2],
63 }
65
66impl ShaperInstance {
67 pub fn from_variations<V>(font: &FontRef, variations: V) -> Self
72 where
73 V: IntoIterator,
74 V::Item: Into<Variation>,
75 {
76 let mut this = Self::default();
77 this.set_variations(font, variations);
78 this
79 }
80
81 pub fn from_coords(font: &FontRef, coords: impl IntoIterator<Item = NormalizedCoord>) -> Self {
86 let mut this = Self::default();
87 this.set_coords(font, coords);
88 this
89 }
90
91 pub fn from_named_instance(font: &FontRef, index: usize) -> Self {
94 let mut this = Self::default();
95 this.set_named_instance(font, index);
96 this
97 }
98
99 pub fn coords(&self) -> &[F2Dot14] {
101 &self.coords
102 }
103
104 pub fn set_variations<V>(&mut self, font: &FontRef, variations: V)
106 where
107 V: IntoIterator,
108 V::Item: Into<Variation>,
109 {
110 self.coords.clear();
111 if let Ok(fvar) = font.fvar() {
112 self.coords
113 .resize(fvar.axis_count() as usize, F2Dot14::ZERO);
114 fvar.user_to_normalized(
115 font.avar().ok().as_ref(),
116 variations
117 .into_iter()
118 .map(Into::into)
119 .map(|var| (var.tag, Fixed::from_f64(var.value as _))),
120 self.coords.as_mut_slice(),
121 );
122 self.check_default();
123 self.set_feature_variations(font);
124 }
125 }
126
127 pub fn set_coords(&mut self, font: &FontRef, coords: impl IntoIterator<Item = F2Dot14>) {
129 self.coords.clear();
130 if let Ok(fvar) = font.fvar() {
131 let count = fvar.axis_count() as usize;
132 self.coords.reserve(count);
133 self.coords.extend(coords.into_iter().take(count));
134 self.check_default();
135 self.set_feature_variations(font);
136 }
137 }
138
139 pub fn set_named_instance(&mut self, font: &FontRef, index: usize) {
142 self.coords.clear();
143 if let Ok(fvar) = font.fvar() {
144 if let Ok((axes, instance)) = fvar
145 .axis_instance_arrays()
146 .and_then(|arrays| Ok((arrays.axes(), arrays.instances().get(index)?)))
147 {
148 self.set_variations(
149 font,
150 axes.iter()
151 .zip(instance.coordinates)
152 .map(|(axis, coord)| (axis.axis_tag(), coord.get().to_f32())),
153 );
154 }
155 }
156 }
157
158 fn set_feature_variations(&mut self, font: &FontRef) {
159 self.feature_variations = [None; 2];
160 if self.coords.is_empty() {
161 return;
162 }
163 self.feature_variations[0] = font
164 .gsub()
165 .ok()
166 .and_then(|t| LayoutTable::Gsub(t).feature_variation_index(&self.coords));
167 self.feature_variations[1] = font
168 .gpos()
169 .ok()
170 .and_then(|t| LayoutTable::Gpos(t).feature_variation_index(&self.coords));
171 }
172
173 fn check_default(&mut self) {
174 if self.coords.iter().all(|coord| *coord == F2Dot14::ZERO) {
175 self.coords.clear();
176 }
177 }
178}
179
180pub struct ShaperBuilder<'a> {
182 data: &'a ShaperData,
183 font: FontRef<'a>,
184 instance: Option<&'a ShaperInstance>,
185 point_size: Option<f32>,
186}
187
188impl<'a> ShaperBuilder<'a> {
189 pub fn instance(mut self, instance: Option<&'a ShaperInstance>) -> Self {
193 self.instance = instance;
194 self
195 }
196
197 pub fn point_size(mut self, size: Option<f32>) -> Self {
201 self.point_size = size;
202 self
203 }
204
205 pub fn build(self) -> crate::Shaper<'a> {
207 let font = self.font;
208 let units_per_em = self.data.table_offsets.units_per_em;
209 let charmap = Charmap::new(&font, &self.data.table_offsets, &self.data.cmap_cache);
210 let glyph_metrics = GlyphMetrics::new(&font, &self.data.table_offsets);
211 let (coords, feature_variations) = self
212 .instance
213 .map(|instance| (instance.coords(), instance.feature_variations))
214 .unwrap_or_default();
215 let ot_tables = OtTables::new(
216 &font,
217 &self.data.ot_cache,
218 &self.data.table_offsets,
219 coords,
220 feature_variations,
221 );
222 let aat_tables = AatTables::new(&font, &self.data.aat_cache, &self.data.table_offsets);
223 hb_font_t {
224 font,
225 units_per_em,
226 points_per_em: self.point_size,
227 charmap,
228 glyph_metrics,
229 ot_tables,
230 aat_tables,
231 }
232 }
233}
234
235#[derive(Clone)]
237pub struct hb_font_t<'a> {
238 pub(crate) font: FontRef<'a>,
239 pub(crate) units_per_em: u16,
240 pub(crate) points_per_em: Option<f32>,
241 charmap: Charmap<'a>,
242 glyph_metrics: GlyphMetrics<'a>,
243 pub(crate) ot_tables: OtTables<'a>,
244 pub(crate) aat_tables: AatTables<'a>,
245}
246
247impl<'a> crate::Shaper<'a> {
248 #[inline]
250 pub fn units_per_em(&self) -> i32 {
251 self.units_per_em as i32
252 }
253
254 pub fn coords(&self) -> &'a [NormalizedCoord] {
256 self.ot_tables.coords
257 }
258
259 pub fn shape(&self, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
268 let plan = ShapePlan::new(
269 self,
270 buffer.0.direction,
271 buffer.0.script,
272 buffer.0.language.as_ref(),
273 features,
274 );
275 self.shape_with_plan(&plan, buffer, features)
276 }
277
278 pub fn shape_with_plan(
291 &self,
292 plan: &ShapePlan,
293 buffer: UnicodeBuffer,
294 features: &[Feature],
295 ) -> GlyphBuffer {
296 let mut buffer = buffer.0;
297 buffer.enter();
298
299 assert_eq!(
300 buffer.direction, plan.direction,
301 "Buffer direction does not match plan direction: {:?} != {:?}",
302 buffer.direction, plan.direction
303 );
304 assert_eq!(
305 buffer.script.unwrap_or(script::UNKNOWN),
306 plan.script.unwrap_or(script::UNKNOWN),
307 "Buffer script does not match plan script: {:?} != {:?}",
308 buffer.script.unwrap_or(script::UNKNOWN),
309 plan.script.unwrap_or(script::UNKNOWN)
310 );
311
312 if buffer.len > 0 {
313 let target_direction = buffer.direction;
315 shape_internal(&mut hb_ot_shape_context_t {
316 plan,
317 face: self,
318 buffer: &mut buffer,
319 target_direction,
320 features,
321 });
322 }
323
324 buffer.leave();
325
326 GlyphBuffer(buffer)
327 }
328
329 pub(crate) fn has_glyph(&self, c: u32) -> bool {
330 self.get_nominal_glyph(c).is_some()
331 }
332
333 pub(crate) fn get_nominal_glyph(&self, c: u32) -> Option<GlyphId> {
334 self.charmap.map(c)
335 }
336
337 pub(crate) fn get_nominal_variant_glyph(&self, c: u32, vs: u32) -> Option<GlyphId> {
338 self.charmap.map_variant(c, vs)
339 }
340
341 pub(crate) fn glyph_h_advance(&self, glyph: GlyphId) -> i32 {
342 self.glyph_metrics
343 .advance_width(glyph, self.ot_tables.coords)
344 .unwrap_or_default()
345 }
346 pub(crate) fn glyph_h_advances(&self, buffer: &mut hb_buffer_t) {
347 self.glyph_metrics
348 .populate_advance_widths(buffer, self.ot_tables.coords);
349 }
350
351 pub(crate) fn glyph_v_advance(&self, glyph: GlyphId) -> i32 {
352 -self
353 .glyph_metrics
354 .advance_height(glyph, self.ot_tables.coords)
355 .unwrap_or(self.units_per_em as i32)
356 }
357
358 pub(crate) fn glyph_h_origin(&self, glyph: GlyphId) -> i32 {
359 self.glyph_h_advance(glyph) / 2
360 }
361
362 pub(crate) fn glyph_v_origin(&self, glyph: GlyphId) -> i32 {
363 self.glyph_metrics
364 .v_origin(glyph, self.ot_tables.coords)
365 .unwrap_or_default()
366 }
367
368 pub(crate) fn glyph_extents(
369 &self,
370 glyph: GlyphId,
371 glyph_extents: &mut hb_glyph_extents_t,
372 ) -> bool {
373 if let Some(extents) = self.glyph_metrics.extents(glyph, self.ot_tables.coords) {
374 glyph_extents.x_bearing = extents.x_min;
375 glyph_extents.y_bearing = extents.y_max;
376 glyph_extents.width = extents.x_max - extents.x_min;
377 glyph_extents.height = extents.y_min - extents.y_max;
378 true
379 } else {
380 false
381 }
382 }
383
384 pub(crate) fn glyph_names(&self) -> GlyphNames<'a> {
385 GlyphNames::new(&self.font)
386 }
387
388 pub(crate) fn layout_table(&self, table_index: TableIndex) -> Option<LayoutTable<'a>> {
389 match table_index {
390 TableIndex::GSUB => self
391 .ot_tables
392 .gsub
393 .as_ref()
394 .map(|table| LayoutTable::Gsub(table.table.clone())),
395 TableIndex::GPOS => self
396 .ot_tables
397 .gpos
398 .as_ref()
399 .map(|table| LayoutTable::Gpos(table.table.clone())),
400 }
401 }
402
403 pub(crate) fn layout_tables(&self) -> impl Iterator<Item = (TableIndex, LayoutTable<'a>)> + '_ {
404 TableIndex::iter().filter_map(move |idx| self.layout_table(idx).map(|table| (idx, table)))
405 }
406}
407
408#[derive(Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)]
409#[repr(C)]
410pub struct hb_glyph_extents_t {
411 pub x_bearing: i32,
412 pub y_bearing: i32,
413 pub width: i32,
414 pub height: i32,
415}