1use super::{
8 scale::{OffsetRounding, Scale, SimplePass},
9 Buffers, GlyphZone, Hinter, OutlineContext, OutlinePlan, OutlineRef,
10};
11use crate::model::Error;
12use crate::{
13 limits::MAX_RECURSION_DEPTH,
14 tables::{
15 glyf::{
16 Anchor, CompositeGlyph, CompositeGlyphFlags, Glyph, PointMarker, SimpleGlyph,
17 PHANTOM_POINT_COUNT,
18 },
19 gvar::DeltaBuffers,
20 },
21 types::{F2Dot14, Fixed, GlyphId, Point},
22};
23
24pub(super) fn load<'a, 's, 'buf, S: Scale>(
29 plan: &'s OutlinePlan<'a>,
30 context: &'a dyn OutlineContext<'a>,
31 scale: &'s S,
32 buffers: Buffers<'buf, S>,
33 hinter: Option<&mut dyn Hinter<S::Coord>>,
34) -> Result<OutlineRef<'buf, S::Coord>, Error> {
35 let coords = context.coords();
36 let varies = plan.applies_variations;
37 let is_hinted = hinter.is_some() && scale.is_scaled();
38 let mut pass = Pass {
39 context,
40 scale,
41 varies,
42 coords,
43 gvar_scalars: context.gvar_scalars(),
44 has_hvar: context.has_hvar(),
45 buffers,
46 point_count: 0,
47 contour_count: 0,
48 component_delta_count: 0,
49 phantom: Default::default(),
50 hinter,
51 is_hinted,
52 };
53 pass.load(&plan.glyph_data, plan.glyph, 0)?;
54 Ok(pass.finish())
55}
56
57trait TrySlice<T> {
60 fn try_mut<I>(&mut self, index: I) -> Result<&mut [T], Error>
61 where
62 I: core::slice::SliceIndex<[T], Output = [T]>;
63
64 fn try_ref<I>(&self, index: I) -> Result<&[T], Error>
65 where
66 I: core::slice::SliceIndex<[T], Output = [T]>;
67}
68
69impl<T> TrySlice<T> for [T] {
70 fn try_mut<I>(&mut self, index: I) -> Result<&mut [T], Error>
71 where
72 I: core::slice::SliceIndex<[T], Output = [T]>,
73 {
74 self.get_mut(index).ok_or(Error::InsufficientMemory)
75 }
76
77 fn try_ref<I>(&self, index: I) -> Result<&[T], Error>
78 where
79 I: core::slice::SliceIndex<[T], Output = [T]>,
80 {
81 self.get(index).ok_or(Error::InsufficientMemory)
82 }
83}
84
85struct Pass<'a, 's, 'buf, 'hint, S: Scale> {
86 context: &'a dyn OutlineContext<'a>,
87 scale: &'s S,
88 varies: bool,
89 coords: &'s [F2Dot14],
90 gvar_scalars: &'s [Fixed],
91 has_hvar: bool,
92 buffers: Buffers<'buf, S>,
93 point_count: usize,
94 contour_count: usize,
95 component_delta_count: usize,
96 phantom: [Point<S::Coord>; PHANTOM_POINT_COUNT],
97 hinter: Option<&'hint mut dyn Hinter<S::Coord>>,
98 is_hinted: bool,
99}
100
101impl<'a, 's, 'buf, S: Scale> Pass<'a, 's, 'buf, '_, S> {
102 fn finish(self) -> OutlineRef<'buf, S::Coord> {
103 let Self {
104 buffers,
105 point_count,
106 contour_count,
107 phantom,
108 ..
109 } = self;
110 let points = &mut buffers.points[..point_count];
111 let x_shift = phantom[0].x;
113 if x_shift != S::Coord::default() {
114 for point in points.iter_mut() {
115 point.x = point.x - x_shift;
116 }
117 }
118 OutlineRef {
119 points,
120 flags: &buffers.flags[..point_count],
121 contours: &buffers.contours[..contour_count],
122 phantom,
123 }
124 }
125
126 fn load(
127 &mut self,
128 glyph: &Option<Glyph<'a>>,
129 gid: GlyphId,
130 recurse_depth: usize,
131 ) -> Result<(), Error> {
132 if recurse_depth > MAX_RECURSION_DEPTH {
135 return Err(Error::LimitExceeded);
136 }
137 self.setup_phantom_points(glyph, gid);
138 match glyph {
139 Some(Glyph::Simple(simple)) => self.load_simple(simple, gid),
140 Some(Glyph::Composite(composite)) => self.load_composite(composite, gid, recurse_depth),
141 None => self.load_empty(gid),
142 }
143 }
144
145 fn setup_phantom_points(&mut self, glyph: &Option<Glyph<'a>>, gid: GlyphId) {
151 let (x_min, y_max) = match glyph {
152 Some(glyph) => (glyph.x_min() as i32, glyph.y_max() as i32),
153 None => (0, 0),
154 };
155 let (lsb, advance) = self.context.h_metrics(gid);
156 let (tsb, vadvance) = self.context.v_metrics(gid).unwrap_or_else(|| {
157 let (ascent, descent) = self.context.h_line_metrics();
158 (ascent - y_max, ascent - descent)
159 });
160 let from = |value| self.scale.phantom_from_font_units(value);
161 self.phantom[0] = Point::new(from(x_min - lsb), from(0));
163 self.phantom[1] = Point::new(from(x_min - lsb + advance), from(0));
164 self.phantom[2] = Point::new(from(0), from(y_max + tsb));
166 self.phantom[3] = Point::new(from(0), from(y_max + tsb - vadvance));
167 }
168
169 fn load_empty(&mut self, gid: GlyphId) -> Result<(), Error> {
170 let deltas = if self.varies {
171 self.context.phantom_point_deltas(gid)
172 } else {
173 None
174 };
175 self.scale.load_empty_phantom(&mut self.phantom, deltas);
176 Ok(())
177 }
178
179 fn read_contours(&mut self, glyph: &SimpleGlyph<'a>) -> Result<core::ops::Range<usize>, Error> {
185 let end_pts = glyph.end_pts_of_contours();
186 let range = self.contour_count..self.contour_count + end_pts.len();
187 let contours = self.buffers.contours.try_mut(range.clone())?;
188 let mut previous = 0;
189 for (end_pt, contour) in end_pts.iter().zip(contours.iter_mut()) {
190 let end_pt = end_pt.get();
191 if end_pt < previous {
192 return Err(Error::Malformed);
194 }
195 previous = end_pt;
196 *contour = end_pt;
197 }
198 Ok(range)
199 }
200
201 fn load_simple(&mut self, glyph: &SimpleGlyph<'a>, gid: GlyphId) -> Result<(), Error> {
202 let points_start = self.point_count;
203 let point_count = glyph.num_points();
204 let with_phantom = point_count + PHANTOM_POINT_COUNT;
205 let point_range = points_start..points_start + with_phantom;
206
207 let contours_range = self.read_contours(glyph)?;
209
210 let var_data = if self.varies {
215 self.context.glyph_variation_data(gid)
216 } else {
217 None
218 };
219 let (is_hinted, phantom, coords, has_hvar, scale) = (
220 self.is_hinted,
221 self.phantom,
222 self.coords,
223 self.has_hvar,
224 self.scale,
225 );
226
227 let scaled = self.buffers.points.try_mut(point_range.clone())?;
228 let flags = self.buffers.flags.try_mut(point_range)?;
229 let unscaled = if S::NEEDS_UNSCALED {
230 self.buffers.unscaled.try_mut(..with_phantom)?
231 } else {
232 &mut []
233 };
234 let deltas = if self.varies {
235 DeltaBuffers {
236 deltas: self.buffers.deltas.try_mut(..with_phantom)?,
237 iup: self.buffers.iup.try_mut(..with_phantom)?,
238 }
239 } else {
240 DeltaBuffers {
241 deltas: &mut [],
242 iup: &mut [],
243 }
244 };
245 let contours = self.buffers.contours.try_ref(contours_range.clone())?;
246
247 self.phantom = scale.load_simple_points(SimplePass {
248 glyph,
249 scaled,
250 unscaled,
251 flags,
252 contours,
253 phantom,
254 deltas,
255 var_data,
256 varies: self.varies,
257 coords,
258 gvar_scalars: self.gvar_scalars,
259 has_hvar,
260 is_hinted,
261 })?;
262
263 self.point_count += point_count;
264 self.contour_count += contours_range.len();
265
266 if self.is_hinted {
267 self.hint_glyph(
268 glyph.instructions(),
269 points_start,
270 contours_range.clone(),
271 point_count,
272 gid,
273 false,
274 )?;
275 }
276
277 if points_start != 0 {
278 let contours = &mut self.buffers.contours[contours_range];
281 for contour_end in contours.iter_mut() {
282 *contour_end += points_start as u16;
283 }
284 }
285 Ok(())
286 }
287
288 fn hint_glyph(
294 &mut self,
295 bytecode: &'a [u8],
296 points_start: usize,
297 contours_range: core::ops::Range<usize>,
298 phantom_offset: usize,
299 gid: GlyphId,
300 is_composite: bool,
301 ) -> Result<(), Error> {
302 if !self.is_hinted {
303 return Ok(());
304 }
305 let Some(hinter) = self.hinter.as_deref_mut() else {
306 return Ok(());
307 };
308 let point_range = points_start..self.point_count + PHANTOM_POINT_COUNT;
309 if bytecode.is_empty() {
310 if !is_composite && !hinter.backward_compatibility() {
314 let scaled = &self.buffers.points[point_range.clone()];
315 for (scaled, phantom) in scaled[phantom_offset..].iter().zip(&mut self.phantom) {
316 *phantom = self.scale.round_phantom(*scaled);
317 }
318 }
319 return Ok(());
320 }
321 let scaled = self.buffers.points.try_mut(point_range.clone())?;
322 let flags = self.buffers.flags.try_mut(point_range)?;
323 let unscaled = self.buffers.unscaled.try_mut(..scaled.len())?;
324 if is_composite {
325 for (i, phantom) in self.phantom.iter().enumerate() {
330 scaled[phantom_offset + i] = *phantom;
331 flags[phantom_offset + i] = Default::default();
332 }
333 for (unscaled, scaled) in unscaled.iter_mut().zip(scaled.iter()) {
334 *unscaled = Point::new(
335 self.scale.coord_to_hinting_raw(scaled.x),
336 self.scale.coord_to_hinting_raw(scaled.y),
337 );
338 }
339 for flag in flags.iter_mut() {
340 flag.clear_marker(PointMarker::TOUCHED);
341 }
342 }
343 for point in &mut scaled[phantom_offset..] {
345 *point = self.scale.round_phantom(*point);
346 }
347 let rebase = if is_composite { points_start as u16 } else { 0 };
352 if rebase != 0 {
353 for contour in self.buffers.contours.try_mut(contours_range.clone())? {
354 *contour -= rebase;
355 }
356 }
357 let result = {
358 let contours = self.buffers.contours.try_ref(contours_range.clone())?;
359 let mut zone = GlyphZone {
360 glyph: gid,
361 bytecode,
362 points: scaled,
363 unscaled,
364 flags,
365 contours,
366 phantom: &mut self.phantom,
367 is_composite,
368 coords: self.coords,
369 };
370 hinter.hint(&mut zone)
371 };
372 if rebase != 0 {
373 for contour in self.buffers.contours.try_mut(contours_range)? {
374 *contour += rebase;
375 }
376 }
377 Ok(result?)
378 }
379
380 fn load_composite(
381 &mut self,
382 glyph: &CompositeGlyph<'a>,
383 gid: GlyphId,
384 recurse_depth: usize,
385 ) -> Result<(), Error> {
386 let point_base = self.point_count;
387 let contour_base = self.contour_count;
388 let delta_base = self.component_delta_count;
389 let mut have_deltas = false;
390 let mut counted_instructions = None;
393 let var_data = if self.varies {
394 self.context.glyph_variation_data(gid)
395 } else {
396 None
397 };
398 if let Some(var_data) = var_data {
399 let (count, instructions) = glyph.count_and_instructions();
400 counted_instructions = Some(instructions);
401 let count = count + PHANTOM_POINT_COUNT;
402 let deltas = self
403 .buffers
404 .composite_deltas
405 .try_mut(delta_base..delta_base + count)?;
406 if var_data
407 .composite_deltas_with_scalars(self.coords, self.gvar_scalars, deltas)
408 .is_some()
409 {
410 for (phantom, delta) in self
411 .phantom
412 .iter_mut()
413 .zip(&deltas[count - PHANTOM_POINT_COUNT..])
414 {
415 *phantom = self.scale.add_phantom_delta(*phantom, *delta);
416 }
417 have_deltas = true;
418 }
419 self.component_delta_count += count;
420 }
421 for point in self.phantom.iter_mut() {
422 *point = self.scale.scale_phantom(*point);
423 }
424 for (i, component) in glyph.components().enumerate() {
425 let phantom = self.phantom;
428 let start_point = self.point_count;
429 let component_glyph = self
430 .context
431 .glyph(component.glyph)
432 .ok_or(Error::MissingResource)?
433 .into_glyph();
434 self.load(&component_glyph, component.glyph, recurse_depth + 1)?;
435 let end_point = self.point_count;
436 if !component
437 .flags
438 .contains(CompositeGlyphFlags::USE_MY_METRICS)
439 {
440 self.phantom = phantom;
441 }
442 let have_xform = component.flags.intersects(
443 CompositeGlyphFlags::WE_HAVE_A_SCALE
444 | CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
445 | CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO,
446 );
447 if have_xform {
448 let points = &mut self.buffers.points[start_point..end_point];
449 self.scale.transform_points(points, &component.transform);
450 }
451 let offset = match component.anchor {
452 Anchor::Offset { x, y } => {
453 let scale_offset = have_xform
454 && component.flags
455 & (CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
456 | CompositeGlyphFlags::UNSCALED_COMPONENT_OFFSET)
457 == CompositeGlyphFlags::SCALED_COMPONENT_OFFSET;
458 let delta = have_deltas
459 .then(|| self.buffers.composite_deltas.get(delta_base + i).copied())
460 .flatten();
461 let rounding = if self.is_hinted
464 && component
465 .flags
466 .contains(CompositeGlyphFlags::ROUND_XY_TO_GRID)
467 {
468 OffsetRounding {
469 x: self
470 .hinter
471 .as_deref()
472 .is_some_and(|hinter| hinter.round_composite_x_offset()),
473 y: true,
474 }
475 } else {
476 OffsetRounding::default()
477 };
478 self.scale.component_offset(
479 Point::new(x as i32, y as i32),
480 &component.transform,
481 scale_offset,
482 delta,
483 rounding,
484 )
485 }
486 Anchor::Point { base, component } => {
487 let base_point = *self
488 .buffers
489 .points
490 .get(point_base + base as usize)
491 .ok_or(Error::Malformed)?;
492 let component_point = *self
493 .buffers
494 .points
495 .get(start_point + component as usize)
496 .ok_or(Error::Malformed)?;
497 base_point - component_point
498 }
499 };
500 if offset.x != S::Coord::default() || offset.y != S::Coord::default() {
501 for point in &mut self.buffers.points[start_point..end_point] {
502 *point += offset;
503 }
504 }
505 }
506 self.component_delta_count = delta_base;
511 if self.is_hinted {
514 let instructions = counted_instructions.unwrap_or_else(|| glyph.instructions());
515 self.hint_glyph(
516 instructions.unwrap_or_default(),
517 point_base,
518 contour_base..self.contour_count,
519 self.point_count - point_base,
520 gid,
521 true,
522 )?;
523 }
524 Ok(())
525 }
526}
527
528#[cfg(test)]
529mod tests {
530 use super::super::testing::build;
531 use super::*;
532 use crate::{
533 tables::glyf::outline::{Outline, OutlineTables, Scale26Dot6, Unscaled},
534 tables::glyf::PointFlags,
535 tables::{glyf::Glyf, gvar::Gvar, loca::Loca},
536 types::{F26Dot6, Fixed},
537 FontData, FontRead, FontRef,
538 };
539 use alloc::{vec, vec::Vec};
540
541 #[test]
551 fn a_malformed_composite_does_not_leak_the_delta_stack() {
552 fn empty_simple() -> Vec<u8> {
554 let mut out = vec![];
555 out.extend_from_slice(&0i16.to_be_bytes()); out.extend_from_slice(&[0u8; 8]); out.extend_from_slice(&0u16.to_be_bytes()); out
559 }
560 fn composite(components: &[u16]) -> Vec<u8> {
561 let mut out = vec![];
562 out.extend_from_slice(&(-1i16).to_be_bytes()); out.extend_from_slice(&[0u8; 8]); for (i, gid) in components.iter().enumerate() {
565 let last = i == components.len() - 1;
566 let flags = 0x0001u16 | 0x0002 | if last { 0 } else { 0x0020 };
568 out.extend_from_slice(&flags.to_be_bytes());
569 out.extend_from_slice(&gid.to_be_bytes());
570 out.extend_from_slice(&0i16.to_be_bytes()); out.extend_from_slice(&0i16.to_be_bytes()); }
573 out
574 }
575 fn tables_from_glyphs(glyphs: &[Vec<u8>]) -> (Vec<u8>, Vec<u8>) {
576 let mut glyf = vec![];
577 let mut loca = vec![];
578 for glyph in glyphs {
579 loca.extend_from_slice(&(glyf.len() as u32).to_be_bytes());
580 glyf.extend_from_slice(glyph);
581 }
582 loca.extend_from_slice(&(glyf.len() as u32).to_be_bytes());
583 (glyf, loca)
584 }
585 let (glyf, loca) = tables_from_glyphs(&[
588 composite(&[1, 2]),
589 composite(&[3]),
590 composite(&[3]),
591 empty_simple(),
592 ]);
593 let glyf = Glyf::read(FontData::new(&glyf)).unwrap();
594 let loca = Loca::read(FontData::new(&loca), true).unwrap();
595 let gvar_bytes = malformed_gvar_for_composites();
596 let gvar = Gvar::read(FontData::new(&gvar_bytes)).unwrap();
597 for gid in 0..3 {
599 assert!(
600 gvar.glyph_variation_data(GlyphId::new(gid))
601 .unwrap()
602 .unwrap()
603 .composite_deltas(
604 &[F2Dot14::from_f32(1.0)],
605 &mut [Point::<Fixed>::default(); 8]
606 )
607 .is_none(),
608 "gid {gid} parsed when it should not"
609 );
610 }
611 let coords = [F2Dot14::from_f32(1.0)];
612 let context = OutlineTables {
613 glyf,
614 loca,
615 gvar: Some(crate::tables::gvar::SelectedGvar::Original(gvar)),
616 hmtx: None,
617 os2: None,
618 hvar: None,
619 units_per_em: 1000,
620 coords: &coords,
621 gvar_scalars: &[],
622 };
623 let mut outline = Outline::<Unscaled>::new();
624 assert!(outline.load(&context, GlyphId::new(0)).is_ok());
627 }
628
629 fn malformed_gvar_for_composites() -> Vec<u8> {
632 use font_test_data::bebuffer::BeBuffer;
633 let mut g = BeBuffer::new();
636 g = g.push(1u16); g = g.push(10u16); g = g.push(2u16); g = g.push(0xA000u16); g = g.push(0x4000u16); g = g.push(0u8); g = g.push(0x3Fu8); let blob = g.to_vec();
644 let len = blob.len() as u32;
645
646 let mut buf = BeBuffer::new();
647 buf = buf.push(1u16).push(0u16); buf = buf.push(1u16); buf = buf.push(0u16).push(20u32);
651 buf = buf.push(4u16); buf = buf.push(1u16); buf = buf.push(0u32); buf = buf
656 .push(0u32)
657 .push(len)
658 .push(len * 2)
659 .push(len * 3)
660 .push(len * 3);
661 let mut bytes = buf.to_vec();
662 let array_start = bytes.len() as u32;
663 bytes[16..20].copy_from_slice(&array_start.to_be_bytes());
664 for _ in 0..3 {
665 bytes.extend_from_slice(&blob);
666 }
667 bytes
668 }
669
670 #[test]
673 fn unscaled_matches_26dot6_without_a_size() {
674 for gid in [0, 1, 5, 7] {
675 let fixed = build(
676 font_test_data::GLYF_COMPONENTS,
677 gid,
678 &Scale26Dot6::new(None, 1000),
679 );
680 let raw = build(font_test_data::GLYF_COMPONENTS, gid, &Unscaled);
681 assert_eq!(raw.contours, fixed.contours, "gid {gid}");
682 assert_eq!(raw.points.len(), fixed.points.len(), "gid {gid}");
683 for (r, f) in raw.points.iter().zip(&fixed.points) {
684 assert_eq!(r.x, f.x.to_bits() >> 6, "gid {gid}");
685 assert_eq!(r.y, f.y.to_bits() >> 6, "gid {gid}");
686 }
687 }
688 }
689
690 #[test]
692 fn composite_inherits_its_components() {
693 let scale = Scale26Dot6::new(None, 1000);
694 let simple = build(font_test_data::GLYF_COMPONENTS, 1, &scale).points;
695 let built = build(font_test_data::GLYF_COMPONENTS, 5, &scale);
697 let composite = built.points;
698 assert_eq!(composite.len(), simple.len() * 2);
699 assert_eq!(built.contours.len(), 2);
700 assert_ne!(composite[0], composite[simple.len()]);
702 }
703
704 #[test]
706 fn empty_glyph_has_metrics_but_no_points() {
707 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
708 let context = OutlineTables::new(&font).unwrap();
709 let mut outline = Outline::<Scale26Dot6>::new();
710 let out = outline.load(&context, GlyphId::new(0), Some(16.0)).unwrap();
711 assert!(out.points.is_empty());
712 assert!(out.contours.is_empty());
713 assert!(out.adjusted_advance_width() != F26Dot6::ZERO);
714 }
715
716 #[test]
719 fn short_buffers_are_rejected() {
720 let font = FontRef::new(font_test_data::GLYF_COMPONENTS).unwrap();
721 let context = OutlineTables::new(&font).unwrap();
722 let plan = OutlinePlan::new(&context, GlyphId::new(1)).unwrap();
723 let scale = Scale26Dot6::new(None, 1000);
724 let lengths = plan.buffer_lengths::<Scale26Dot6>();
725 let mut points = vec![Point::default(); 1];
728 let mut flags = vec![PointFlags::default(); lengths.points as usize];
729 let mut contours = vec![0u16; lengths.contours as usize];
730 let mut unscaled = vec![Point::default(); lengths.unscaled as usize];
731 let buffers = Buffers {
732 points: &mut points,
733 flags: &mut flags,
734 contours: &mut contours,
735 unscaled: &mut unscaled,
736 deltas: &mut [],
737 iup: &mut [],
738 composite_deltas: &mut [],
739 };
740 assert_eq!(
741 plan.load(&context, &scale, buffers, None).err(),
742 Some(Error::InsufficientMemory)
743 );
744 }
745}