1use crate::model::Error;
4use crate::{
5 model::{
6 glyph::outline::{DrawOptions, DrawnMetrics, PathSink, UnscaledOutlineSink},
7 Font,
8 },
9 tables::{
10 glyf::Glyf,
11 glyf::{
12 outline::{
13 Buffers, OutlineContext, OutlinePlan, Scale, Scale26Dot6, ScaleF32, Unscaled,
14 },
15 PointCoord, PHANTOM_POINT_COUNT,
16 },
17 gvar::{GlyphVariationData, SelectedGvar},
18 hmtx::GlyphMetricRecords,
19 loca::{Loca, LocaGlyph},
20 },
21 types::{F2Dot14, Fixed, GlyphId, Point},
22};
23
24#[derive(Copy, Clone, PartialEq, Eq, Debug)]
29pub(crate) enum Precision {
30 Fixed,
35 Float,
39}
40
41#[derive(Clone)]
49pub struct GlyfGlyph<'a> {
50 context: GlyfContext<'a>,
51 plan: OutlinePlan<'a>,
52}
53
54impl<'a> GlyfGlyph<'a> {
55 pub(crate) fn new(context: GlyfContext<'a>, glyph: GlyphId) -> Option<Self> {
56 let plan = OutlinePlan::new(&context, glyph).ok()?;
57 Some(Self { context, plan })
58 }
59
60 pub fn glyph(&self) -> GlyphId {
62 self.plan.glyph
63 }
64
65 pub fn font(&self) -> &'a Font {
67 self.context.font
68 }
69
70 pub fn plan(&self) -> &OutlinePlan<'a> {
73 &self.plan
74 }
75
76 pub fn required_memory_size(&self) -> usize {
78 plan_buffer_size(&self.plan)
79 }
80
81 pub(crate) fn draw(
82 &self,
83 options: &DrawOptions,
84 precision: Precision,
85 buf: &mut [u8],
86 sink: &mut dyn PathSink,
87 ) -> Result<DrawnMetrics, Error> {
88 draw_plan(&self.plan, &self.context, options, precision, buf, sink)
89 }
90
91 pub fn required_memory_size_unscaled(&self) -> usize {
94 self.plan
95 .buffer_lengths::<Unscaled>()
96 .packed_len::<Unscaled>()
97 }
98
99 pub(crate) fn draw_unscaled(
101 &self,
102 buf: &mut [u8],
103 sink: &mut dyn UnscaledOutlineSink,
104 ) -> Result<DrawnMetrics, Error> {
105 let lengths = self.plan.buffer_lengths::<Unscaled>();
106 let buffers = Buffers::from_bytes(buf, &lengths)?;
107 let outline = self.plan.load(&self.context, &Unscaled, buffers, None)?;
108 let (points, flags) = (outline.points(), outline.flags());
109 let mut start = 0;
110 for end in outline.contours() {
111 let end = *end as usize;
112 if end < start || end >= points.len() {
113 return Err(Error::Malformed);
114 }
115 sink.start_contour();
116 for (point, flags) in points[start..=end].iter().zip(&flags[start..=end]) {
117 sink.point(point.x, point.y, flags.without_markers());
118 }
119 sink.end_contour();
120 start = end + 1;
121 }
122 Ok(DrawnMetrics {
123 h_advance: Some(outline.adjusted_advance_width() as f32),
124 x_bearing: Some(outline.adjusted_lsb() as f32),
125 has_overlaps: self.plan.has_overlaps,
126 ..Default::default()
127 })
128 }
129}
130
131pub(crate) fn plan_buffer_size(plan: &OutlinePlan<'_>) -> usize {
137 plan.buffer_lengths::<Scale26Dot6>()
138 .packed_len::<Scale26Dot6>()
139}
140
141pub(crate) fn draw_plan<'a>(
144 plan: &OutlinePlan<'a>,
145 context: &'a dyn OutlineContext<'a>,
146 options: &DrawOptions,
147 precision: Precision,
148 buf: &mut [u8],
149 sink: &mut dyn PathSink,
150) -> Result<DrawnMetrics, Error> {
151 let units_per_em = context.units_per_em();
152 match precision {
153 Precision::Fixed => load_and_draw(
154 plan,
155 context,
156 &Scale26Dot6::new(options.ppem, units_per_em),
157 options,
158 buf,
159 sink,
160 ),
161 Precision::Float => load_and_draw(
162 plan,
163 context,
164 &ScaleF32::new(options.ppem, units_per_em),
165 options,
166 buf,
167 sink,
168 ),
169 }
170}
171
172fn load_and_draw<'a, S: Scale>(
173 plan: &OutlinePlan<'a>,
174 context: &'a dyn OutlineContext<'a>,
175 scale: &S,
176 options: &DrawOptions,
177 buf: &mut [u8],
178 mut sink: &mut dyn PathSink,
179) -> Result<DrawnMetrics, Error> {
180 let lengths = plan.buffer_lengths::<S>();
181 let buffers = Buffers::from_bytes(buf, &lengths)?;
182 let outline = plan.load(context, scale, buffers, None)?;
183 let metrics = DrawnMetrics {
184 h_advance: Some(outline.adjusted_advance_width().to_f32()),
185 x_bearing: Some(outline.adjusted_lsb().to_f32()),
186 has_overlaps: plan.has_overlaps,
187 ..Default::default()
188 };
189 if !outline.to_path(options.contour_start, &mut sink) {
190 return Err(Error::Malformed);
191 }
192 Ok(metrics)
193}
194
195#[derive(Clone, Copy)]
201pub(crate) struct GlyfContext<'a> {
202 pub(crate) font: &'a Font,
203 tables: &'a (Glyf<'a>, Loca<'a>),
204 gvar: Option<&'a SelectedGvar<'a>>,
205 h_metrics: &'a GlyphMetricRecords<'a>,
206 v_metrics: &'a GlyphMetricRecords<'a>,
207 coords: &'a [F2Dot14],
208 gvar_scalars: &'a [Fixed],
209 h_line: (i32, i32),
212 num_glyphs: u32,
213 units_per_em: u16,
214 has_hvar: bool,
215}
216
217impl<'a> GlyfContext<'a> {
218 pub(crate) fn new(font: &'a Font) -> Option<Self> {
220 let tables = font.selected_glyf_loca()?;
221 let v_metrics = font.v_metric_records();
222 let h_line = if v_metrics.is_empty() {
223 OutlineContext::h_line_metrics(&font)
224 } else {
225 (0, 0)
226 };
227 Some(Self {
228 font,
229 tables,
230 gvar: font.selected_gvar(),
231 h_metrics: font.h_metric_records(),
232 v_metrics,
233 coords: font.normalized_coords(),
234 gvar_scalars: font.gvar_scalars(),
235 h_line,
236 num_glyphs: font.num_glyphs(),
237 units_per_em: font.units_per_em(),
238 has_hvar: font.hvar().is_some(),
239 })
240 }
241
242 fn metrics(&self, records: &GlyphMetricRecords<'_>, glyph: GlyphId) -> (i32, i32) {
244 (
245 records
246 .stated_side_bearing(glyph)
247 .unwrap_or_default()
248 .to_i32(),
249 records.stated_advance(self.num_glyphs, glyph).to_i32(),
250 )
251 }
252}
253
254impl<'a> OutlineContext<'a> for GlyfContext<'a> {
255 fn glyph(&self, glyph: GlyphId) -> Option<LocaGlyph<'a>> {
256 let (glyf, loca) = self.tables;
257 loca.get(glyph, glyf)
258 }
259
260 fn glyph_variation_data(&self, glyph: GlyphId) -> Option<GlyphVariationData<'a>> {
261 self.gvar?.glyph_variation_data(glyph).ok()?
262 }
263
264 fn has_gvar(&self) -> bool {
265 self.gvar.is_some()
266 }
267
268 fn phantom_point_deltas(&self, glyph: GlyphId) -> Option<[Point<Fixed>; PHANTOM_POINT_COUNT]> {
269 let (glyf, loca) = self.tables;
270 self.gvar?.phantom_point_deltas_with_scalars(
271 glyf,
272 loca,
273 self.coords,
274 self.gvar_scalars,
275 glyph,
276 )
277 }
278
279 fn gvar_scalars(&self) -> &[Fixed] {
280 self.gvar_scalars
281 }
282
283 fn coords(&self) -> &[F2Dot14] {
284 self.coords
285 }
286
287 fn units_per_em(&self) -> u16 {
288 self.units_per_em
289 }
290
291 fn h_metrics(&self, glyph: GlyphId) -> (i32, i32) {
292 self.metrics(self.h_metrics, glyph)
293 }
294
295 fn v_metrics(&self, glyph: GlyphId) -> Option<(i32, i32)> {
296 (!self.v_metrics.is_empty()).then(|| self.metrics(self.v_metrics, glyph))
297 }
298
299 fn h_line_metrics(&self) -> (i32, i32) {
300 self.h_line
301 }
302
303 fn has_hvar(&self) -> bool {
304 self.has_hvar
305 }
306}
307
308#[derive(Clone, Copy)]
314pub(crate) struct FontAt<'a> {
315 pub(crate) context: GlyfContext<'a>,
316 pub(crate) coords: &'a [F2Dot14],
317}
318
319impl<'a> OutlineContext<'a> for FontAt<'a> {
320 fn glyph(&self, glyph: GlyphId) -> Option<LocaGlyph<'a>> {
321 self.context.glyph(glyph)
322 }
323
324 fn glyph_variation_data(&self, glyph: GlyphId) -> Option<GlyphVariationData<'a>> {
325 self.context.glyph_variation_data(glyph)
326 }
327
328 fn has_gvar(&self) -> bool {
329 self.context.has_gvar()
330 }
331
332 fn phantom_point_deltas(&self, glyph: GlyphId) -> Option<[Point<Fixed>; PHANTOM_POINT_COUNT]> {
333 let (glyf, loca) = self.context.tables;
334 self.context
335 .gvar?
336 .phantom_point_deltas_with_scalars(glyf, loca, self.coords, &[], glyph)
337 }
338
339 fn coords(&self) -> &[F2Dot14] {
340 self.coords
341 }
342
343 fn units_per_em(&self) -> u16 {
344 self.context.units_per_em
345 }
346
347 fn h_metrics(&self, glyph: GlyphId) -> (i32, i32) {
348 self.context.h_metrics(glyph)
349 }
350
351 fn v_metrics(&self, glyph: GlyphId) -> Option<(i32, i32)> {
352 self.context.v_metrics(glyph)
353 }
354
355 fn h_line_metrics(&self) -> (i32, i32) {
356 self.context.h_line
357 }
358
359 fn has_hvar(&self) -> bool {
360 self.context.has_hvar
361 }
362}