1mod deltas;
4mod hint;
5mod memory;
6mod outline;
7
8#[cfg(feature = "libm")]
9#[allow(unused_imports)]
10use core_maths::CoreFloat;
11
12pub use hint::{HintError, HintInstance, HintOutline};
13pub use outline::{Outline, ScaledOutline};
14use raw::{FontRef, ReadError};
15
16use super::{DrawError, GlyphHMetrics, Hinting};
17use crate::GLYF_COMPOSITE_RECURSION_LIMIT;
18use memory::{FreeTypeOutlineMemory, HarfBuzzOutlineMemory};
19
20use read_fonts::{
21 tables::{
22 glyf::{
23 Anchor, CompositeGlyph, CompositeGlyphFlags, Glyf, Glyph, PointMarker, SimpleGlyph,
24 },
25 gvar::Gvar,
26 hdmx::Hdmx,
27 loca::Loca,
28 },
29 types::{F26Dot6, F2Dot14, Fixed, GlyphId, Point, Tag},
30 TableProvider,
31};
32
33pub const PHANTOM_POINT_COUNT: usize = 4;
35
36#[derive(Clone)]
38pub struct Outlines<'a> {
39 pub(crate) font: FontRef<'a>,
40 pub(crate) glyph_metrics: GlyphHMetrics<'a>,
41 loca: Loca<'a>,
42 glyf: Glyf<'a>,
43 gvar: Option<Gvar<'a>>,
44 hdmx: Option<Hdmx<'a>>,
45 fpgm: &'a [u8],
46 prep: &'a [u8],
47 cvt_len: u32,
48 max_function_defs: u16,
49 max_instruction_defs: u16,
50 max_twilight_points: u16,
51 max_stack_elements: u16,
52 max_storage: u16,
53 glyph_count: u16,
54 units_per_em: u16,
55 os2_vmetrics: [i16; 2],
56 prefer_interpreter: bool,
57}
58
59impl<'a> Outlines<'a> {
60 pub fn new(font: &FontRef<'a>) -> Option<Self> {
61 let loca = font.loca(None).ok()?;
62 let glyf = font.glyf().ok()?;
63 let glyph_metrics = GlyphHMetrics::new(font)?;
64 let (
65 glyph_count,
66 max_function_defs,
67 max_instruction_defs,
68 max_twilight_points,
69 max_stack_elements,
70 max_storage,
71 max_instructions,
72 ) = font
73 .maxp()
74 .map(|maxp| {
75 (
76 maxp.num_glyphs(),
77 maxp.max_function_defs().unwrap_or_default(),
78 maxp.max_instruction_defs().unwrap_or_default(),
79 maxp.max_twilight_points()
82 .unwrap_or_default()
83 .saturating_add(4),
84 maxp.max_stack_elements()
87 .unwrap_or_default()
88 .saturating_add(32),
89 maxp.max_storage().unwrap_or_default(),
90 maxp.max_size_of_instructions().unwrap_or_default(),
91 )
92 })
93 .unwrap_or_default();
94 let os2_vmetrics = font
95 .os2()
96 .map(|os2| [os2.s_typo_ascender(), os2.s_typo_descender()])
97 .unwrap_or_default();
98 let fpgm = font
99 .data_for_tag(Tag::new(b"fpgm"))
100 .unwrap_or_default()
101 .as_bytes();
102 let prep = font
103 .data_for_tag(Tag::new(b"prep"))
104 .unwrap_or_default()
105 .as_bytes();
106 let prefer_interpreter = !(max_instructions == 0 && fpgm.is_empty() && prep.is_empty());
109 let cvt_len = font.cvt().map(|cvt| cvt.len() as u32).unwrap_or_default();
110 Some(Self {
111 font: font.clone(),
112 glyph_metrics,
113 loca,
114 glyf,
115 gvar: font.gvar().ok(),
116 hdmx: font.hdmx().ok(),
117 fpgm,
118 prep,
119 cvt_len,
120 max_function_defs,
121 max_instruction_defs,
122 max_twilight_points,
123 max_stack_elements,
124 max_storage,
125 glyph_count,
126 units_per_em: font.head().ok()?.units_per_em(),
127 os2_vmetrics,
128 prefer_interpreter,
129 })
130 }
131
132 pub fn units_per_em(&self) -> u16 {
133 self.units_per_em
134 }
135
136 pub fn glyph_count(&self) -> usize {
137 self.glyph_count as usize
138 }
139
140 pub fn prefer_interpreter(&self) -> bool {
141 self.prefer_interpreter
142 }
143
144 pub fn outline(&self, glyph_id: GlyphId) -> Result<Outline<'a>, DrawError> {
145 let mut outline = Outline {
146 glyph_id,
147 has_variations: self.gvar.is_some(),
148 ..Default::default()
149 };
150 let glyph = self.loca.get_glyf(glyph_id, &self.glyf)?;
151 if let Some(glyph) = glyph.as_ref() {
152 self.outline_rec(glyph, &mut outline, 0, 0)?;
153 }
154 outline.points += PHANTOM_POINT_COUNT;
155 outline.max_stack = self.max_stack_elements as usize;
156 outline.cvt_count = self.cvt_len as usize;
157 outline.storage_count = self.max_storage as usize;
158 outline.max_twilight_points = self.max_twilight_points as usize;
159 outline.glyph = glyph;
160 Ok(outline)
161 }
162
163 pub fn compute_scale(&self, ppem: Option<f32>) -> (bool, F26Dot6) {
164 if let Some(ppem) = ppem {
165 if self.units_per_em > 0 {
166 return (
167 true,
168 F26Dot6::from_bits((ppem * 64.) as i32)
169 / F26Dot6::from_bits(self.units_per_em as i32),
170 );
171 }
172 }
173 (false, F26Dot6::from_bits(0x10000))
174 }
175}
176
177impl Outlines<'_> {
178 fn outline_rec(
179 &self,
180 glyph: &Glyph,
181 outline: &mut Outline,
182 component_depth: usize,
183 recurse_depth: usize,
184 ) -> Result<(), DrawError> {
185 if recurse_depth > GLYF_COMPOSITE_RECURSION_LIMIT {
186 return Err(DrawError::RecursionLimitExceeded(outline.glyph_id));
187 }
188 match glyph {
189 Glyph::Simple(simple) => {
190 let num_points = simple.num_points();
191 let num_points_with_phantom = num_points + PHANTOM_POINT_COUNT;
192 outline.max_simple_points = outline.max_simple_points.max(num_points_with_phantom);
193 outline.points += num_points;
194 outline.contours += simple.end_pts_of_contours().len();
195 outline.has_hinting = outline.has_hinting || simple.instruction_length() != 0;
196 outline.max_other_points = outline.max_other_points.max(num_points_with_phantom);
197 outline.has_overlaps |= simple.has_overlapping_contours();
198 }
199 Glyph::Composite(composite) => {
200 let (mut count, instructions) = composite.count_and_instructions();
201 count += PHANTOM_POINT_COUNT;
202 let point_base = outline.points;
203 for (component, flags) in composite.component_glyphs_and_flags() {
204 outline.has_overlaps |= flags.contains(CompositeGlyphFlags::OVERLAP_COMPOUND);
205 let component_glyph = self.loca.get_glyf(component.into(), &self.glyf)?;
206 let Some(component_glyph) = component_glyph else {
207 continue;
208 };
209 self.outline_rec(
210 &component_glyph,
211 outline,
212 component_depth + count,
213 recurse_depth + 1,
214 )?;
215 }
216 let has_hinting = !instructions.unwrap_or_default().is_empty();
217 if has_hinting {
218 let num_points_in_composite = outline.points - point_base + PHANTOM_POINT_COUNT;
221 outline.max_other_points =
222 outline.max_other_points.max(num_points_in_composite);
223 }
224 outline.max_component_delta_stack = outline
225 .max_component_delta_stack
226 .max(component_depth + count);
227 outline.has_hinting = outline.has_hinting || has_hinting;
228 }
229 }
230 Ok(())
231 }
232
233 fn hdmx_width(&self, ppem: f32, glyph_id: GlyphId) -> Option<u8> {
234 let hdmx = self.hdmx.as_ref()?;
235 let ppem_u8 = ppem as u8;
236 if ppem_u8 as f32 == ppem {
238 hdmx.record_for_size(ppem_u8)?
240 .widths
241 .get(glyph_id.to_u32() as usize)
242 .copied()
243 } else {
244 None
245 }
246 }
247}
248
249trait Scaler {
250 fn outlines(&self) -> &Outlines;
251 fn setup_phantom_points(
252 &mut self,
253 bounds: [i16; 4],
254 lsb: i32,
255 advance: i32,
256 tsb: i32,
257 vadvance: i32,
258 );
259 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError>;
260 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError>;
261 fn load_composite(
262 &mut self,
263 glyph: &CompositeGlyph,
264 glyph_id: GlyphId,
265 recurse_depth: usize,
266 ) -> Result<(), DrawError>;
267
268 fn load(
269 &mut self,
270 glyph: &Option<Glyph>,
271 glyph_id: GlyphId,
272 recurse_depth: usize,
273 ) -> Result<(), DrawError> {
274 if recurse_depth > GLYF_COMPOSITE_RECURSION_LIMIT {
275 return Err(DrawError::RecursionLimitExceeded(glyph_id));
276 }
277 let bounds = match &glyph {
278 Some(glyph) => [glyph.x_min(), glyph.x_max(), glyph.y_min(), glyph.y_max()],
279 _ => [0; 4],
280 };
281 let outlines = self.outlines();
282 let lsb = outlines.glyph_metrics.lsb(glyph_id, &[]);
283 let advance = outlines.glyph_metrics.advance_width(glyph_id, &[]);
284 let [ascent, descent] = outlines.os2_vmetrics.map(|x| x as i32);
285 let tsb = ascent - bounds[3] as i32;
286 let vadvance = ascent - descent;
287 self.setup_phantom_points(bounds, lsb, advance, tsb, vadvance);
288 match glyph {
289 Some(Glyph::Simple(simple)) => self.load_simple(simple, glyph_id),
290 Some(Glyph::Composite(composite)) => {
291 self.load_composite(composite, glyph_id, recurse_depth)
292 }
293 None => self.load_empty(glyph_id),
294 }
295 }
296}
297
298pub(crate) struct HarfBuzzScaler<'a> {
300 outlines: &'a Outlines<'a>,
301 memory: HarfBuzzOutlineMemory<'a>,
302 coords: &'a [F2Dot14],
303 point_count: usize,
304 contour_count: usize,
305 component_delta_count: usize,
306 ppem: f32,
307 scale: F26Dot6,
308 is_scaled: bool,
309 phantom: [Point<f32>; PHANTOM_POINT_COUNT],
315}
316
317impl<'a> HarfBuzzScaler<'a> {
318 pub(crate) fn unhinted(
319 outlines: &'a Outlines<'a>,
320 outline: &'a Outline,
321 buf: &'a mut [u8],
322 ppem: Option<f32>,
323 coords: &'a [F2Dot14],
324 ) -> Result<Self, DrawError> {
325 outline.ensure_point_count_limit()?;
326 let (is_scaled, scale) = outlines.compute_scale(ppem);
327 let memory =
328 HarfBuzzOutlineMemory::new(outline, buf).ok_or(DrawError::InsufficientMemory)?;
329 Ok(Self {
330 outlines,
331 memory,
332 coords,
333 point_count: 0,
334 contour_count: 0,
335 component_delta_count: 0,
336 ppem: ppem.unwrap_or_default(),
337 scale,
338 is_scaled,
339 phantom: Default::default(),
340 })
341 }
342
343 pub(crate) fn scale(
344 mut self,
345 glyph: &Option<Glyph>,
346 glyph_id: GlyphId,
347 ) -> Result<ScaledOutline<'a, f32>, DrawError> {
348 self.load(glyph, glyph_id, 0)?;
349 Ok(ScaledOutline::new(
350 &mut self.memory.points[..self.point_count],
351 self.phantom,
352 &mut self.memory.flags[..self.point_count],
353 &mut self.memory.contours[..self.contour_count],
354 self.outlines.hdmx_width(self.ppem, glyph_id),
355 ))
356 }
357}
358
359pub(crate) struct FreeTypeScaler<'a> {
361 outlines: &'a Outlines<'a>,
362 memory: FreeTypeOutlineMemory<'a>,
363 coords: &'a [F2Dot14],
364 point_count: usize,
365 contour_count: usize,
366 component_delta_count: usize,
367 ppem: f32,
368 scale: F26Dot6,
369 is_scaled: bool,
370 is_hinted: bool,
371 pedantic_hinting: bool,
372 phantom: [Point<F26Dot6>; PHANTOM_POINT_COUNT],
378 hinter: Option<&'a HintInstance>,
379}
380
381impl<'a> FreeTypeScaler<'a> {
382 pub(crate) fn unhinted(
383 outlines: &'a Outlines<'a>,
384 outline: &'a Outline,
385 buf: &'a mut [u8],
386 ppem: Option<f32>,
387 coords: &'a [F2Dot14],
388 ) -> Result<Self, DrawError> {
389 outline.ensure_point_count_limit()?;
390 let (is_scaled, scale) = outlines.compute_scale(ppem);
391 let memory = FreeTypeOutlineMemory::new(outline, buf, Hinting::None)
392 .ok_or(DrawError::InsufficientMemory)?;
393 Ok(Self {
394 outlines,
395 memory,
396 coords,
397 point_count: 0,
398 contour_count: 0,
399 component_delta_count: 0,
400 ppem: ppem.unwrap_or_default(),
401 scale,
402 is_scaled,
403 is_hinted: false,
404 pedantic_hinting: false,
405 phantom: Default::default(),
406 hinter: None,
407 })
408 }
409
410 pub(crate) fn hinted(
411 outlines: &'a Outlines<'a>,
412 outline: &'a Outline,
413 buf: &'a mut [u8],
414 ppem: Option<f32>,
415 coords: &'a [F2Dot14],
416 hinter: &'a HintInstance,
417 pedantic_hinting: bool,
418 ) -> Result<Self, DrawError> {
419 outline.ensure_point_count_limit()?;
420 let (is_scaled, scale) = outlines.compute_scale(ppem);
421 let memory = FreeTypeOutlineMemory::new(outline, buf, Hinting::Embedded)
422 .ok_or(DrawError::InsufficientMemory)?;
423 Ok(Self {
424 outlines,
425 memory,
426 coords,
427 point_count: 0,
428 contour_count: 0,
429 component_delta_count: 0,
430 ppem: ppem.unwrap_or_default(),
431 scale,
432 is_scaled,
433 is_hinted: is_scaled,
435 pedantic_hinting,
436 phantom: Default::default(),
437 hinter: Some(hinter),
438 })
439 }
440
441 pub(crate) fn scale(
442 mut self,
443 glyph: &Option<Glyph>,
444 glyph_id: GlyphId,
445 ) -> Result<ScaledOutline<'a, F26Dot6>, DrawError> {
446 self.load(glyph, glyph_id, 0)?;
447 let hdmx_width = if self.is_hinted
451 && self
452 .hinter
453 .as_ref()
454 .map(|hinter| !hinter.backward_compatibility())
455 .unwrap_or(true)
456 {
457 self.outlines.hdmx_width(self.ppem, glyph_id)
458 } else {
459 None
460 };
461 Ok(ScaledOutline::new(
462 &mut self.memory.scaled[..self.point_count],
463 self.phantom,
464 &mut self.memory.flags[..self.point_count],
465 &mut self.memory.contours[..self.contour_count],
466 hdmx_width,
467 ))
468 }
469}
470
471impl Scaler for FreeTypeScaler<'_> {
472 fn setup_phantom_points(
473 &mut self,
474 bounds: [i16; 4],
475 lsb: i32,
476 advance: i32,
477 tsb: i32,
478 vadvance: i32,
479 ) {
480 self.phantom[0].x = F26Dot6::from_bits(bounds[0] as i32 - lsb);
484 self.phantom[0].y = F26Dot6::ZERO;
485 self.phantom[1].x = self.phantom[0].x + F26Dot6::from_bits(advance);
486 self.phantom[1].y = F26Dot6::ZERO;
487 self.phantom[2].x = F26Dot6::ZERO;
489 self.phantom[2].y = F26Dot6::from_bits(bounds[3] as i32 + tsb);
490 self.phantom[3].x = F26Dot6::ZERO;
491 self.phantom[3].y = self.phantom[2].y - F26Dot6::from_bits(vadvance);
492 }
493
494 fn outlines(&self) -> &Outlines {
495 self.outlines
496 }
497
498 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError> {
499 let scale = self.scale;
502 let mut unscaled = self.phantom.map(|point| point.map(|x| x.to_bits()));
503 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
504 if let Ok(Some(deltas)) = self.outlines.gvar.as_ref().unwrap().phantom_point_deltas(
505 &self.outlines.glyf,
506 &self.outlines.loca,
507 self.coords,
508 glyph_id,
509 ) {
510 unscaled[0] += deltas[0].map(Fixed::to_i32);
511 unscaled[1] += deltas[1].map(Fixed::to_i32);
512 }
513 }
514 if self.is_scaled {
515 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
516 *phantom = unscaled.map(F26Dot6::from_bits) * scale;
517 }
518 } else {
519 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
520 *phantom = unscaled.map(F26Dot6::from_i32);
521 }
522 }
523 Ok(())
524 }
525
526 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError> {
527 use DrawError::InsufficientMemory;
528 let points_start = self.point_count;
530 let point_count = glyph.num_points();
531 let phantom_start = point_count;
532 let points_end = points_start + point_count + PHANTOM_POINT_COUNT;
533 let point_range = points_start..points_end;
534 let other_points_end = point_count + PHANTOM_POINT_COUNT;
535 let scaled = self
537 .memory
538 .scaled
539 .get_mut(point_range.clone())
540 .ok_or(InsufficientMemory)?;
541 let flags = self
542 .memory
543 .flags
544 .get_mut(point_range)
545 .ok_or(InsufficientMemory)?;
546 let unscaled = self
550 .memory
551 .unscaled
552 .get_mut(..other_points_end)
553 .ok_or(InsufficientMemory)?;
554 glyph.read_points_fast(&mut unscaled[..point_count], &mut flags[..point_count])?;
557 let contours_start = self.contour_count;
559 let contour_end_pts = glyph.end_pts_of_contours();
560 let contour_count = contour_end_pts.len();
561 let contours_end = contours_start + contour_count;
562 let contours = self
563 .memory
564 .contours
565 .get_mut(contours_start..contours_end)
566 .ok_or(InsufficientMemory)?;
567 let mut last_end_pt = 0;
570 for (end_pt, contour) in contour_end_pts.iter().zip(contours.iter_mut()) {
571 let end_pt = end_pt.get();
572 if end_pt < last_end_pt {
573 return Err(ReadError::MalformedData(
574 "unordered contour end points in TrueType glyph",
575 )
576 .into());
577 }
578 last_end_pt = end_pt;
579 *contour = end_pt;
580 }
581 self.point_count += point_count;
583 self.contour_count += contour_count;
584 for (i, phantom) in self.phantom.iter().enumerate() {
586 unscaled[phantom_start + i] = phantom.map(|x| x.to_bits());
587 flags[phantom_start + i] = Default::default();
588 }
589 let mut have_deltas = false;
590 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
591 let gvar = self.outlines.gvar.as_ref().unwrap();
592 let glyph = deltas::SimpleGlyph {
593 points: &mut unscaled[..],
594 flags: &mut flags[..],
595 contours,
596 };
597 let deltas = self
598 .memory
599 .deltas
600 .get_mut(..point_count + PHANTOM_POINT_COUNT)
601 .ok_or(InsufficientMemory)?;
602 let iup_buffer = self
603 .memory
604 .iup_buffer
605 .get_mut(..point_count + PHANTOM_POINT_COUNT)
606 .ok_or(InsufficientMemory)?;
607 if deltas::simple_glyph(gvar, glyph_id, self.coords, glyph, iup_buffer, deltas).is_ok()
608 {
609 have_deltas = true;
610 }
611 }
612 let ins = glyph.instructions();
613 let is_hinted = self.is_hinted;
614 if self.is_scaled {
615 let scale = self.scale;
616 if have_deltas {
617 for ((point, unscaled), delta) in scaled
618 .iter_mut()
619 .zip(unscaled.iter())
620 .zip(self.memory.deltas.iter())
621 {
622 let delta = delta.map(Fixed::to_f26dot6);
623 let scaled = (unscaled.map(F26Dot6::from_i32) + delta) * scale;
624 *point = scaled.map(|v| F26Dot6::from_bits(v.to_i32()));
627 }
628 if self.outlines.glyph_metrics.hvar.is_some() {
632 for ((point, unscaled), delta) in scaled[phantom_start..]
633 .iter_mut()
634 .zip(&unscaled[phantom_start..])
635 .zip(&self.memory.deltas[phantom_start..])
636 {
637 let delta = delta.map(Fixed::to_i32).map(F26Dot6::from_i32);
638 let scaled = (unscaled.map(F26Dot6::from_i32) + delta) * scale;
639 *point = scaled.map(|v| F26Dot6::from_bits(v.to_i32()));
640 }
641 }
642 if is_hinted {
643 for (unscaled, delta) in unscaled.iter_mut().zip(self.memory.deltas.iter()) {
646 *unscaled += delta.map(Fixed::to_i32);
647 }
648 }
649 } else {
650 for (point, unscaled) in scaled.iter_mut().zip(unscaled.iter_mut()) {
651 *point = unscaled.map(|v| F26Dot6::from_bits(v) * scale);
652 }
653 }
654 } else {
655 if have_deltas {
656 for (unscaled, delta) in unscaled.iter_mut().zip(self.memory.deltas.iter()) {
658 *unscaled += delta.map(Fixed::to_i32);
659 }
660 }
661 for (point, unscaled) in scaled.iter_mut().zip(unscaled.iter()) {
663 *point = unscaled.map(F26Dot6::from_i32);
664 }
665 }
666 self.phantom.copy_from_slice(&scaled[phantom_start..]);
668 if let (Some(hinter), true) = (self.hinter.as_ref(), is_hinted) {
669 if !ins.is_empty() {
670 let original_scaled = self
672 .memory
673 .original_scaled
674 .get_mut(..other_points_end)
675 .ok_or(InsufficientMemory)?;
676 original_scaled.copy_from_slice(scaled);
677 for point in &mut scaled[phantom_start..] {
679 point.x = point.x.round();
680 point.y = point.y.round();
681 }
682 let mut input = HintOutline {
683 glyph_id,
684 unscaled,
685 scaled,
686 original_scaled,
687 flags,
688 contours,
689 bytecode: ins,
690 phantom: &mut self.phantom,
691 stack: self.memory.stack,
692 cvt: self.memory.cvt,
693 storage: self.memory.storage,
694 twilight_scaled: self.memory.twilight_scaled,
695 twilight_original_scaled: self.memory.twilight_original_scaled,
696 twilight_flags: self.memory.twilight_flags,
697 is_composite: false,
698 coords: self.coords,
699 };
700 let hint_res = hinter.hint(self.outlines, &mut input, self.pedantic_hinting);
701 if let (Err(e), true) = (hint_res, self.pedantic_hinting) {
702 return Err(e)?;
703 }
704 } else if !hinter.backward_compatibility() {
705 for (scaled, phantom) in scaled[phantom_start..].iter().zip(&mut self.phantom) {
713 *phantom = scaled.map(|x| x.round());
714 }
715 }
716 }
717 if points_start != 0 {
718 for contour_end in contours.iter_mut() {
720 *contour_end += points_start as u16;
721 }
722 }
723 Ok(())
724 }
725
726 fn load_composite(
727 &mut self,
728 glyph: &CompositeGlyph,
729 glyph_id: GlyphId,
730 recurse_depth: usize,
731 ) -> Result<(), DrawError> {
732 use DrawError::InsufficientMemory;
733 let scale = self.scale;
734 let point_base = self.point_count;
736 let contour_base = self.contour_count;
737 let mut have_deltas = false;
740 let delta_base = self.component_delta_count;
741 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
742 let gvar = self.outlines.gvar.as_ref().unwrap();
743 let count = glyph.components().count() + PHANTOM_POINT_COUNT;
744 let deltas = self
745 .memory
746 .composite_deltas
747 .get_mut(delta_base..delta_base + count)
748 .ok_or(InsufficientMemory)?;
749 if deltas::composite_glyph(gvar, glyph_id, self.coords, &mut deltas[..]).is_ok() {
750 for (phantom, delta) in self
752 .phantom
753 .iter_mut()
754 .zip(&deltas[deltas.len() - PHANTOM_POINT_COUNT..])
755 {
756 *phantom += delta.map(Fixed::to_i32).map(F26Dot6::from_bits);
757 }
758 have_deltas = true;
759 }
760 self.component_delta_count += count;
761 }
762 if self.is_scaled {
763 for point in self.phantom.iter_mut() {
764 *point *= scale;
765 }
766 } else {
767 for point in self.phantom.iter_mut() {
768 *point = point.map(|x| F26Dot6::from_i32(x.to_bits()));
769 }
770 }
771 for (i, component) in glyph.components().enumerate() {
772 let phantom = self.phantom;
775 let start_point = self.point_count;
777 let component_glyph = self
778 .outlines
779 .loca
780 .get_glyf(component.glyph.into(), &self.outlines.glyf)?;
781 self.load(&component_glyph, component.glyph.into(), recurse_depth + 1)?;
782 let end_point = self.point_count;
783 if !component
784 .flags
785 .contains(CompositeGlyphFlags::USE_MY_METRICS)
786 {
787 self.phantom = phantom;
790 }
791 fn scale_component(x: F2Dot14) -> F26Dot6 {
793 F26Dot6::from_bits(x.to_bits() as i32 * 4)
794 }
795 let xform = &component.transform;
796 let xx = scale_component(xform.xx);
797 let yx = scale_component(xform.yx);
798 let xy = scale_component(xform.xy);
799 let yy = scale_component(xform.yy);
800 let have_xform = component.flags.intersects(
801 CompositeGlyphFlags::WE_HAVE_A_SCALE
802 | CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
803 | CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO,
804 );
805 if have_xform {
806 let scaled = &mut self.memory.scaled[start_point..end_point];
807 if self.is_scaled {
808 for point in scaled {
809 let x = point.x * xx + point.y * xy;
810 let y = point.x * yx + point.y * yy;
811 point.x = x;
812 point.y = y;
813 }
814 } else {
815 for point in scaled {
816 let unscaled = point.map(|c| F26Dot6::from_bits(c.to_i32()));
819 let x = unscaled.x * xx + unscaled.y * xy;
820 let y = unscaled.x * yx + unscaled.y * yy;
821 *point = Point::new(x, y).map(|c| F26Dot6::from_i32(c.to_bits()));
822 }
823 }
824 }
825 let anchor_offset = match component.anchor {
826 Anchor::Offset { x, y } => {
827 let (mut x, mut y) = (x as i32, y as i32);
828 if have_xform
829 && component.flags
830 & (CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
831 | CompositeGlyphFlags::UNSCALED_COMPONENT_OFFSET)
832 == CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
833 {
834 fn hypot(a: F26Dot6, b: F26Dot6) -> Fixed {
838 let a = a.to_bits().abs();
839 let b = b.to_bits().abs();
840 Fixed::from_bits(if a > b {
841 a + ((3 * b) >> 3)
842 } else {
843 b + ((3 * a) >> 3)
844 })
845 }
846 x = (Fixed::from_bits(x) * hypot(xx, xy)).to_bits();
848 y = (Fixed::from_bits(y) * hypot(yy, yx)).to_bits();
849 }
850 if have_deltas {
851 let delta = self
852 .memory
853 .composite_deltas
854 .get(delta_base + i)
855 .copied()
856 .unwrap_or_default();
857 x += delta.x.to_i32();
860 y += delta.y.to_i32();
861 }
862 if self.is_scaled {
863 let mut offset = Point::new(x, y).map(F26Dot6::from_bits) * scale;
864 if self.is_hinted
865 && component
866 .flags
867 .contains(CompositeGlyphFlags::ROUND_XY_TO_GRID)
868 {
869 offset.y = offset.y.round();
871 }
872 offset
873 } else {
874 Point::new(x, y).map(F26Dot6::from_i32)
875 }
876 }
877 Anchor::Point { base, component } => {
878 let (base_offset, component_offset) = (base as usize, component as usize);
879 let base_point = self
880 .memory
881 .scaled
882 .get(point_base + base_offset)
883 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, base))?;
884 let component_point = self
885 .memory
886 .scaled
887 .get(start_point + component_offset)
888 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, component))?;
889 *base_point - *component_point
890 }
891 };
892 if anchor_offset.x != F26Dot6::ZERO || anchor_offset.y != F26Dot6::ZERO {
893 for point in &mut self.memory.scaled[start_point..end_point] {
894 *point += anchor_offset;
895 }
896 }
897 }
898 if have_deltas {
899 self.component_delta_count = delta_base;
900 }
901 if let (Some(hinter), true) = (self.hinter.as_ref(), self.is_hinted) {
902 let ins = glyph.instructions().unwrap_or_default();
903 if !ins.is_empty() {
904 let start_point = point_base;
907 let end_point = self.point_count + PHANTOM_POINT_COUNT;
908 let point_range = start_point..end_point;
909 let phantom_start = point_range.len() - PHANTOM_POINT_COUNT;
910 let scaled = &mut self.memory.scaled[point_range.clone()];
911 let flags = self
912 .memory
913 .flags
914 .get_mut(point_range.clone())
915 .ok_or(InsufficientMemory)?;
916 for (i, phantom) in self.phantom.iter().enumerate() {
918 scaled[phantom_start + i] = *phantom;
919 flags[phantom_start + i] = Default::default();
920 }
921 let other_points_end = point_range.len();
922 let unscaled = self
923 .memory
924 .unscaled
925 .get_mut(..other_points_end)
926 .ok_or(InsufficientMemory)?;
927 for (scaled, unscaled) in scaled.iter().zip(unscaled.iter_mut()) {
928 *unscaled = scaled.map(|x| x.to_bits());
929 }
930 let original_scaled = self
931 .memory
932 .original_scaled
933 .get_mut(..other_points_end)
934 .ok_or(InsufficientMemory)?;
935 original_scaled.copy_from_slice(scaled);
936 let contours = self
937 .memory
938 .contours
939 .get_mut(contour_base..self.contour_count)
940 .ok_or(InsufficientMemory)?;
941 for p in &mut scaled[phantom_start..] {
943 p.x = p.x.round();
944 p.y = p.y.round();
945 }
946 for flag in flags.iter_mut() {
948 flag.clear_marker(PointMarker::TOUCHED);
949 }
950 if point_base != 0 {
953 let delta = point_base as u16;
954 for contour in contours.iter_mut() {
955 *contour -= delta;
956 }
957 }
958 let mut input = HintOutline {
959 glyph_id,
960 unscaled,
961 scaled,
962 original_scaled,
963 flags,
964 contours,
965 bytecode: ins,
966 phantom: &mut self.phantom,
967 stack: self.memory.stack,
968 cvt: self.memory.cvt,
969 storage: self.memory.storage,
970 twilight_scaled: self.memory.twilight_scaled,
971 twilight_original_scaled: self.memory.twilight_original_scaled,
972 twilight_flags: self.memory.twilight_flags,
973 is_composite: true,
974 coords: self.coords,
975 };
976 let hint_res = hinter.hint(self.outlines, &mut input, self.pedantic_hinting);
977 if let (Err(e), true) = (hint_res, self.pedantic_hinting) {
978 return Err(e)?;
979 }
980 if point_base != 0 {
982 let delta = point_base as u16;
983 for contour in contours.iter_mut() {
984 *contour += delta;
985 }
986 }
987 }
988 }
989 Ok(())
990 }
991}
992
993impl Scaler for HarfBuzzScaler<'_> {
994 fn setup_phantom_points(
995 &mut self,
996 bounds: [i16; 4],
997 lsb: i32,
998 advance: i32,
999 tsb: i32,
1000 vadvance: i32,
1001 ) {
1002 self.phantom[0].x = bounds[0] as f32 - lsb as f32;
1005 self.phantom[0].y = 0.0;
1006 self.phantom[1].x = self.phantom[0].x + advance as f32;
1007 self.phantom[1].y = 0.0;
1008 self.phantom[2].x = 0.0;
1010 self.phantom[2].y = bounds[3] as f32 + tsb as f32;
1011 self.phantom[3].x = 0.0;
1012 self.phantom[3].y = self.phantom[2].y - vadvance as f32;
1013 }
1014
1015 fn outlines(&self) -> &Outlines {
1016 self.outlines
1017 }
1018
1019 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError> {
1020 let scale = self.scale.to_f32();
1023 let mut unscaled = self.phantom;
1024 if self.outlines.glyph_metrics.hvar.is_none()
1025 && self.outlines.gvar.is_some()
1026 && !self.coords.is_empty()
1027 {
1028 if let Ok(Some(deltas)) = self.outlines.gvar.as_ref().unwrap().phantom_point_deltas(
1029 &self.outlines.glyf,
1030 &self.outlines.loca,
1031 self.coords,
1032 glyph_id,
1033 ) {
1034 unscaled[0] += deltas[0].map(Fixed::to_f32);
1035 unscaled[1] += deltas[1].map(Fixed::to_f32);
1036 }
1037 }
1038 if self.is_scaled {
1039 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
1040 *phantom = *unscaled * scale;
1041 }
1042 } else {
1043 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
1044 *phantom = *unscaled;
1045 }
1046 }
1047 Ok(())
1048 }
1049
1050 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError> {
1051 use DrawError::InsufficientMemory;
1052 let points_start = self.point_count;
1054 let point_count = glyph.num_points();
1055 let phantom_start = point_count;
1056 let points_end = points_start + point_count + PHANTOM_POINT_COUNT;
1057 let point_range = points_start..points_end;
1058 let points = self
1060 .memory
1061 .points
1062 .get_mut(point_range.clone())
1063 .ok_or(InsufficientMemory)?;
1064 let flags = self
1065 .memory
1066 .flags
1067 .get_mut(point_range)
1068 .ok_or(InsufficientMemory)?;
1069 glyph.read_points_fast(&mut points[..point_count], &mut flags[..point_count])?;
1070 let contours_start = self.contour_count;
1072 let contour_end_pts = glyph.end_pts_of_contours();
1073 let contour_count = contour_end_pts.len();
1074 let contours_end = contours_start + contour_count;
1075 let contours = self
1076 .memory
1077 .contours
1078 .get_mut(contours_start..contours_end)
1079 .ok_or(InsufficientMemory)?;
1080 for (end_pt, contour) in contour_end_pts.iter().zip(contours.iter_mut()) {
1082 *contour = end_pt.get();
1083 }
1084 self.point_count += point_count;
1086 self.contour_count += contour_count;
1087 for (i, phantom) in self.phantom.iter().enumerate() {
1089 points[phantom_start + i] = *phantom;
1090 flags[phantom_start + i] = Default::default();
1091 }
1092 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
1094 let gvar = self.outlines.gvar.as_ref().unwrap();
1095 let glyph = deltas::SimpleGlyph {
1096 points: &mut points[..],
1097 flags: &mut flags[..],
1098 contours,
1099 };
1100 let deltas = self
1101 .memory
1102 .deltas
1103 .get_mut(..point_count + PHANTOM_POINT_COUNT)
1104 .ok_or(InsufficientMemory)?;
1105 let iup_buffer = self
1106 .memory
1107 .iup_buffer
1108 .get_mut(..point_count + PHANTOM_POINT_COUNT)
1109 .ok_or(InsufficientMemory)?;
1110 if deltas::simple_glyph(gvar, glyph_id, self.coords, glyph, iup_buffer, deltas).is_ok()
1111 {
1112 for (point, delta) in points.iter_mut().zip(deltas) {
1113 *point += *delta;
1114 }
1115 }
1116 }
1117 if self.is_scaled {
1119 let scale = self.scale.to_f32();
1120 for point in points.iter_mut() {
1121 *point = point.map(|c| c * scale);
1122 }
1123 }
1124
1125 if points_start != 0 {
1126 for contour_end in contours.iter_mut() {
1128 *contour_end += points_start as u16;
1129 }
1130 }
1131 Ok(())
1132 }
1133
1134 fn load_composite(
1135 &mut self,
1136 glyph: &CompositeGlyph,
1137 glyph_id: GlyphId,
1138 recurse_depth: usize,
1139 ) -> Result<(), DrawError> {
1140 use DrawError::InsufficientMemory;
1141 let scale = self.scale.to_f32();
1142 let point_base = self.point_count;
1144 let mut have_deltas = false;
1147 let delta_base = self.component_delta_count;
1148 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
1149 let gvar = self.outlines.gvar.as_ref().unwrap();
1150 let count = glyph.components().count() + PHANTOM_POINT_COUNT;
1151 let deltas = self
1152 .memory
1153 .composite_deltas
1154 .get_mut(delta_base..delta_base + count)
1155 .ok_or(InsufficientMemory)?;
1156 if deltas::composite_glyph(gvar, glyph_id, self.coords, &mut deltas[..]).is_ok() {
1157 for (phantom, delta) in self
1159 .phantom
1160 .iter_mut()
1161 .zip(&deltas[deltas.len() - PHANTOM_POINT_COUNT..])
1162 {
1163 *phantom += *delta;
1164 }
1165 have_deltas = true;
1166 }
1167 self.component_delta_count += count;
1168 }
1169 if self.is_scaled {
1170 for point in self.phantom.iter_mut() {
1171 *point *= scale;
1172 }
1173 }
1174 for (i, component) in glyph.components().enumerate() {
1175 let phantom = self.phantom;
1178 let start_point = self.point_count;
1180 let component_glyph = self
1181 .outlines
1182 .loca
1183 .get_glyf(component.glyph.into(), &self.outlines.glyf)?;
1184 self.load(&component_glyph, component.glyph.into(), recurse_depth + 1)?;
1185 let end_point = self.point_count;
1186 if !component
1187 .flags
1188 .contains(CompositeGlyphFlags::USE_MY_METRICS)
1189 {
1190 self.phantom = phantom;
1193 }
1194 let have_xform = component.flags.intersects(
1195 CompositeGlyphFlags::WE_HAVE_A_SCALE
1196 | CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
1197 | CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO,
1198 );
1199 let mut transform = if have_xform {
1200 let xform = &component.transform;
1201 [
1202 xform.xx,
1203 xform.yx,
1204 xform.xy,
1205 xform.yy,
1206 F2Dot14::ZERO,
1207 F2Dot14::ZERO,
1208 ]
1209 .map(|x| x.to_f32())
1210 } else {
1211 [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] };
1213
1214 let anchor_offset = match component.anchor {
1215 Anchor::Offset { x, y } => {
1216 let (mut x, mut y) = (x as f32, y as f32);
1217 if have_xform
1218 && component.flags
1219 & (CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
1220 | CompositeGlyphFlags::UNSCALED_COMPONENT_OFFSET)
1221 == CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
1222 {
1223 x *= hypot(transform[0], transform[2]);
1226 y *= hypot(transform[1], transform[3]);
1227 }
1228 Point::new(x, y)
1229 + self
1230 .memory
1231 .composite_deltas
1232 .get(delta_base + i)
1233 .copied()
1234 .unwrap_or_default()
1235 }
1236 Anchor::Point { base, component } => {
1237 let (base_offset, component_offset) = (base as usize, component as usize);
1238 let base_point = self
1239 .memory
1240 .points
1241 .get(point_base + base_offset)
1242 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, base))?;
1243 let component_point = self
1244 .memory
1245 .points
1246 .get(start_point + component_offset)
1247 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, component))?;
1248 *base_point - *component_point
1249 }
1250 };
1251 transform[4] = anchor_offset.x;
1252 transform[5] = anchor_offset.y;
1253
1254 let points = &mut self.memory.points[start_point..end_point];
1255 for point in points.iter_mut() {
1256 *point = map_point(transform, *point);
1257 }
1258 }
1259 if have_deltas {
1260 self.component_delta_count = delta_base;
1261 }
1262 Ok(())
1263 }
1264}
1265
1266fn hypot(x: f32, y: f32) -> f32 {
1268 x.hypot(y)
1269}
1270
1271fn map_point(transform: [f32; 6], p: Point<f32>) -> Point<f32> {
1272 Point {
1273 x: transform[0] * p.x + transform[2] * p.y + transform[4],
1274 y: transform[1] * p.x + transform[3] * p.y + transform[5],
1275 }
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280 use super::*;
1281 use crate::MetadataProvider;
1282 use raw::{
1283 tables::{
1284 glyf::{CompositeGlyphFlags, Glyf, SimpleGlyphFlags},
1285 loca::Loca,
1286 },
1287 FontRead, FontRef, TableProvider,
1288 };
1289
1290 #[test]
1291 fn overlap_flags() {
1292 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1293 let scaler = Outlines::new(&font).unwrap();
1294 let glyph_count = font.maxp().unwrap().num_glyphs();
1295 let expected_gids_with_overlap = vec![2, 3];
1298 assert_eq!(
1299 expected_gids_with_overlap,
1300 (0..glyph_count)
1301 .filter(|gid| scaler.outline(GlyphId::from(*gid)).unwrap().has_overlaps)
1302 .collect::<Vec<_>>()
1303 );
1304 }
1305
1306 #[test]
1307 fn interpreter_preference() {
1308 let font = FontRef::new(font_test_data::COLRV0V1).unwrap();
1310 let outlines = Outlines::new(&font).unwrap();
1311 assert!(!outlines.prefer_interpreter());
1313 let font = FontRef::new(font_test_data::TTHINT_SUBSET).unwrap();
1315 let outlines = Outlines::new(&font).unwrap();
1316 assert!(outlines.prefer_interpreter());
1318 }
1319
1320 #[test]
1321 fn empty_glyph_advance() {
1322 let font = FontRef::new(font_test_data::HVAR_WITH_TRUNCATED_ADVANCE_INDEX_MAP).unwrap();
1323 let outlines = Outlines::new(&font).unwrap();
1324 let coords = [F2Dot14::from_f32(0.5)];
1325 let ppem = Some(24.0);
1326 let gid = font.charmap().map(' ').unwrap();
1327 let outline = outlines.outline(gid).unwrap();
1328 assert!(outline.glyph.is_none());
1330 let mut buf = [0u8; 128];
1331 let scaler =
1332 FreeTypeScaler::unhinted(&outlines, &outline, &mut buf, ppem, &coords).unwrap();
1333 let scaled = scaler.scale(&outline.glyph, gid).unwrap();
1334 let advance = scaled.adjusted_advance_width();
1335 assert!(advance != F26Dot6::ZERO);
1336 }
1337
1338 #[test]
1339 fn empty_glyphs_have_phantom_points_too() {
1340 let font = FontRef::new(font_test_data::HVAR_WITH_TRUNCATED_ADVANCE_INDEX_MAP).unwrap();
1341 let outlines = Outlines::new(&font).unwrap();
1342 let gid = font.charmap().map(' ').unwrap();
1343 let outline = outlines.outline(gid).unwrap();
1344 assert!(outline.glyph.is_none());
1345 assert_eq!(outline.points, PHANTOM_POINT_COUNT);
1346 }
1347
1348 #[test]
1351 fn composite_with_too_many_points() {
1352 let font = FontRef::new(font_test_data::GLYF_COMPONENTS).unwrap();
1353 let mut outlines = Outlines::new(&font).unwrap();
1354 let mut glyf_buf = font_test_data::bebuffer::BeBuffer::new();
1357 let simple_glyph_point_count = 40000;
1360 glyf_buf = glyf_buf.push(1u16); glyf_buf = glyf_buf.extend([0i16; 4]); glyf_buf = glyf_buf.push((simple_glyph_point_count - 1) as u16); glyf_buf = glyf_buf.push(0u16); for _ in 0..simple_glyph_point_count {
1365 glyf_buf =
1366 glyf_buf.push(SimpleGlyphFlags::X_SHORT_VECTOR | SimpleGlyphFlags::Y_SHORT_VECTOR);
1367 }
1368 for _ in 0..simple_glyph_point_count * 2 {
1370 glyf_buf = glyf_buf.push(0u8);
1371 }
1372 let glyph0_end = glyf_buf.len();
1373 glyf_buf = glyf_buf.push(-1i16); glyf_buf = glyf_buf.extend([0i16; 4]); for i in 0..2 {
1377 let flags = if i == 0 {
1378 CompositeGlyphFlags::MORE_COMPONENTS | CompositeGlyphFlags::ARGS_ARE_XY_VALUES
1379 } else {
1380 CompositeGlyphFlags::ARGS_ARE_XY_VALUES
1381 };
1382 glyf_buf = glyf_buf.push(flags); glyf_buf = glyf_buf.push(0u16); glyf_buf = glyf_buf.extend([0u8; 2]); }
1386 let glyph1_end = glyf_buf.len();
1387 outlines.glyf = Glyf::read(glyf_buf.data().into()).unwrap();
1388 let mut loca_buf = font_test_data::bebuffer::BeBuffer::new();
1390 loca_buf = loca_buf.extend([0u32, glyph0_end as u32, glyph1_end as u32]);
1391 outlines.loca = Loca::read(loca_buf.data().into(), true).unwrap();
1392 let gid = GlyphId::new(1);
1393 let outline = outlines.outline(gid).unwrap();
1394 let mut mem_buf = vec![0u8; outline.required_buffer_size(Default::default())];
1395 assert!(outline.points > u16::MAX as usize);
1397 let result = FreeTypeScaler::unhinted(&outlines, &outline, &mut mem_buf, None, &[]);
1398 assert!(matches!(result, Err(DrawError::TooManyPoints(_))));
1400 }
1401}