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 pub(crate) fractional_size_hinting: bool,
58}
59
60impl<'a> Outlines<'a> {
61 pub fn new(font: &FontRef<'a>) -> Option<Self> {
62 let head = font.head().ok()?;
63 let fractional_size_hinting = !head
66 .flags()
67 .contains(read_fonts::tables::head::Flags::FORCE_INTEGER_PPEM);
68 let loca = font.loca(Some(head.index_to_loc_format() == 1)).ok()?;
69 let glyf = font.glyf().ok()?;
70 let glyph_metrics = GlyphHMetrics::new(font)?;
71 let (
72 glyph_count,
73 max_function_defs,
74 max_instruction_defs,
75 max_twilight_points,
76 max_stack_elements,
77 max_storage,
78 max_instructions,
79 ) = font
80 .maxp()
81 .map(|maxp| {
82 (
83 maxp.num_glyphs(),
84 maxp.max_function_defs().unwrap_or_default(),
85 maxp.max_instruction_defs().unwrap_or_default(),
86 maxp.max_twilight_points()
89 .unwrap_or_default()
90 .saturating_add(4),
91 maxp.max_stack_elements()
94 .unwrap_or_default()
95 .saturating_add(32),
96 maxp.max_storage().unwrap_or_default(),
97 maxp.max_size_of_instructions().unwrap_or_default(),
98 )
99 })
100 .unwrap_or_default();
101 let os2_vmetrics = font
102 .os2()
103 .map(|os2| [os2.s_typo_ascender(), os2.s_typo_descender()])
104 .unwrap_or_default();
105 let fpgm = font
106 .data_for_tag(Tag::new(b"fpgm"))
107 .unwrap_or_default()
108 .as_bytes();
109 let prep = font
110 .data_for_tag(Tag::new(b"prep"))
111 .unwrap_or_default()
112 .as_bytes();
113 let prefer_interpreter = !(max_instructions == 0 && fpgm.is_empty() && prep.is_empty());
116 let cvt_len = font.cvt().map(|cvt| cvt.len() as u32).unwrap_or_default();
117 Some(Self {
118 font: font.clone(),
119 glyph_metrics,
120 loca,
121 glyf,
122 gvar: font.gvar().ok(),
123 hdmx: font.hdmx().ok(),
124 fpgm,
125 prep,
126 cvt_len,
127 max_function_defs,
128 max_instruction_defs,
129 max_twilight_points,
130 max_stack_elements,
131 max_storage,
132 glyph_count,
133 units_per_em: font.head().ok()?.units_per_em(),
134 os2_vmetrics,
135 prefer_interpreter,
136 fractional_size_hinting,
137 })
138 }
139
140 pub fn units_per_em(&self) -> u16 {
141 self.units_per_em
142 }
143
144 pub fn glyph_count(&self) -> usize {
145 self.glyph_count as usize
146 }
147
148 pub fn prefer_interpreter(&self) -> bool {
149 self.prefer_interpreter
150 }
151
152 pub fn outline(&self, glyph_id: GlyphId) -> Result<Outline<'a>, DrawError> {
153 let mut outline = Outline {
154 glyph_id,
155 has_variations: self.gvar.is_some(),
156 ..Default::default()
157 };
158 let glyph = self.loca.get_glyf(glyph_id, &self.glyf)?;
159 if let Some(glyph) = glyph.as_ref() {
160 self.outline_rec(glyph, &mut outline, 0, 0)?;
161 }
162 outline.points += PHANTOM_POINT_COUNT;
163 outline.max_stack = self.max_stack_elements as usize;
164 outline.cvt_count = self.cvt_len as usize;
165 outline.storage_count = self.max_storage as usize;
166 outline.max_twilight_points = self.max_twilight_points as usize;
167 outline.glyph = glyph;
168 Ok(outline)
169 }
170
171 pub fn compute_scale(&self, ppem: Option<f32>) -> (bool, F26Dot6) {
172 if let Some(ppem) = ppem {
173 if self.units_per_em > 0 {
174 return (
175 true,
176 F26Dot6::from_bits((ppem * 64.) as i32)
177 / F26Dot6::from_bits(self.units_per_em as i32),
178 );
179 }
180 }
181 (false, F26Dot6::from_bits(0x10000))
182 }
183
184 pub fn compute_hinted_scale(&self, ppem: Option<f32>) -> (bool, F26Dot6) {
185 if let Some(ppem) = ppem {
186 if !self.fractional_size_hinting {
187 return self.compute_scale(Some(F26Dot6::from_f64(ppem as f64).round().to_f32()));
192 }
193 }
194 self.compute_scale(ppem)
195 }
196}
197
198impl Outlines<'_> {
199 fn outline_rec(
200 &self,
201 glyph: &Glyph,
202 outline: &mut Outline,
203 component_depth: usize,
204 recurse_depth: usize,
205 ) -> Result<(), DrawError> {
206 if recurse_depth > GLYF_COMPOSITE_RECURSION_LIMIT {
207 return Err(DrawError::RecursionLimitExceeded(outline.glyph_id));
208 }
209 match glyph {
210 Glyph::Simple(simple) => {
211 let num_points = simple.num_points();
212 let num_points_with_phantom = num_points + PHANTOM_POINT_COUNT;
213 outline.max_simple_points = outline.max_simple_points.max(num_points_with_phantom);
214 outline.points += num_points;
215 outline.contours += simple.end_pts_of_contours().len();
216 outline.has_hinting = outline.has_hinting || simple.instruction_length() != 0;
217 outline.max_other_points = outline.max_other_points.max(num_points_with_phantom);
218 outline.has_overlaps |= simple.has_overlapping_contours();
219 }
220 Glyph::Composite(composite) => {
221 let (mut count, instructions) = composite.count_and_instructions();
222 count += PHANTOM_POINT_COUNT;
223 let point_base = outline.points;
224 for (component, flags) in composite.component_glyphs_and_flags() {
225 outline.has_overlaps |= flags.contains(CompositeGlyphFlags::OVERLAP_COMPOUND);
226 let component_glyph = self.loca.get_glyf(component.into(), &self.glyf)?;
227 let Some(component_glyph) = component_glyph else {
228 continue;
229 };
230 self.outline_rec(
231 &component_glyph,
232 outline,
233 component_depth + count,
234 recurse_depth + 1,
235 )?;
236 }
237 let has_hinting = !instructions.unwrap_or_default().is_empty();
238 if has_hinting {
239 let num_points_in_composite = outline.points - point_base + PHANTOM_POINT_COUNT;
242 outline.max_other_points =
243 outline.max_other_points.max(num_points_in_composite);
244 }
245 outline.max_component_delta_stack = outline
246 .max_component_delta_stack
247 .max(component_depth + count);
248 outline.has_hinting = outline.has_hinting || has_hinting;
249 }
250 }
251 Ok(())
252 }
253
254 fn hdmx_width(&self, ppem: f32, glyph_id: GlyphId) -> Option<u8> {
255 let hdmx = self.hdmx.as_ref()?;
256 let ppem_u8 = ppem as u8;
257 if ppem_u8 as f32 == ppem {
259 hdmx.record_for_size(ppem_u8)?
261 .widths
262 .get(glyph_id.to_u32() as usize)
263 .copied()
264 } else {
265 None
266 }
267 }
268}
269
270trait Scaler {
271 fn outlines(&self) -> &Outlines<'_>;
272 fn setup_phantom_points(
273 &mut self,
274 bounds: [i16; 4],
275 lsb: i32,
276 advance: i32,
277 tsb: i32,
278 vadvance: i32,
279 );
280 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError>;
281 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError>;
282 fn load_composite(
283 &mut self,
284 glyph: &CompositeGlyph,
285 glyph_id: GlyphId,
286 recurse_depth: usize,
287 ) -> Result<(), DrawError>;
288
289 fn load(
290 &mut self,
291 glyph: &Option<Glyph>,
292 glyph_id: GlyphId,
293 recurse_depth: usize,
294 ) -> Result<(), DrawError> {
295 if recurse_depth > GLYF_COMPOSITE_RECURSION_LIMIT {
296 return Err(DrawError::RecursionLimitExceeded(glyph_id));
297 }
298 let bounds = match &glyph {
299 Some(glyph) => [glyph.x_min(), glyph.x_max(), glyph.y_min(), glyph.y_max()],
300 _ => [0; 4],
301 };
302 let outlines = self.outlines();
303 let lsb = outlines.glyph_metrics.lsb(glyph_id, &[]);
304 let advance = outlines.glyph_metrics.advance_width(glyph_id, &[]);
305 let [ascent, descent] = outlines.os2_vmetrics.map(|x| x as i32);
306 let tsb = ascent - bounds[3] as i32;
307 let vadvance = ascent - descent;
308 self.setup_phantom_points(bounds, lsb, advance, tsb, vadvance);
309 match glyph {
310 Some(Glyph::Simple(simple)) => self.load_simple(simple, glyph_id),
311 Some(Glyph::Composite(composite)) => {
312 self.load_composite(composite, glyph_id, recurse_depth)
313 }
314 None => self.load_empty(glyph_id),
315 }
316 }
317}
318
319pub(crate) struct HarfBuzzScaler<'a> {
321 outlines: &'a Outlines<'a>,
322 memory: HarfBuzzOutlineMemory<'a>,
323 coords: &'a [F2Dot14],
324 point_count: usize,
325 contour_count: usize,
326 component_delta_count: usize,
327 ppem: f32,
328 scale: F26Dot6,
329 is_scaled: bool,
330 phantom: [Point<f32>; PHANTOM_POINT_COUNT],
336}
337
338impl<'a> HarfBuzzScaler<'a> {
339 pub(crate) fn unhinted(
340 outlines: &'a Outlines<'a>,
341 outline: &'a Outline,
342 buf: &'a mut [u8],
343 ppem: Option<f32>,
344 coords: &'a [F2Dot14],
345 ) -> Result<Self, DrawError> {
346 outline.ensure_point_count_limit()?;
347 let (is_scaled, scale) = outlines.compute_scale(ppem);
348 let memory =
349 HarfBuzzOutlineMemory::new(outline, buf).ok_or(DrawError::InsufficientMemory)?;
350 Ok(Self {
351 outlines,
352 memory,
353 coords,
354 point_count: 0,
355 contour_count: 0,
356 component_delta_count: 0,
357 ppem: ppem.unwrap_or_default(),
358 scale,
359 is_scaled,
360 phantom: Default::default(),
361 })
362 }
363
364 pub(crate) fn scale(
365 mut self,
366 glyph: &Option<Glyph>,
367 glyph_id: GlyphId,
368 ) -> Result<ScaledOutline<'a, f32>, DrawError> {
369 self.load(glyph, glyph_id, 0)?;
370 Ok(ScaledOutline::new(
371 &mut self.memory.points[..self.point_count],
372 self.phantom,
373 &mut self.memory.flags[..self.point_count],
374 &mut self.memory.contours[..self.contour_count],
375 self.outlines.hdmx_width(self.ppem, glyph_id),
376 ))
377 }
378}
379
380pub(crate) struct FreeTypeScaler<'a> {
382 outlines: &'a Outlines<'a>,
383 memory: FreeTypeOutlineMemory<'a>,
384 coords: &'a [F2Dot14],
385 point_count: usize,
386 contour_count: usize,
387 component_delta_count: usize,
388 ppem: f32,
389 scale: F26Dot6,
390 is_scaled: bool,
391 is_hinted: bool,
392 pedantic_hinting: bool,
393 phantom: [Point<F26Dot6>; PHANTOM_POINT_COUNT],
399 hinter: Option<&'a HintInstance>,
400}
401
402impl<'a> FreeTypeScaler<'a> {
403 pub(crate) fn unhinted(
404 outlines: &'a Outlines<'a>,
405 outline: &'a Outline,
406 buf: &'a mut [u8],
407 ppem: Option<f32>,
408 coords: &'a [F2Dot14],
409 ) -> Result<Self, DrawError> {
410 outline.ensure_point_count_limit()?;
411 let (is_scaled, scale) = outlines.compute_scale(ppem);
412 let memory = FreeTypeOutlineMemory::new(outline, buf, Hinting::None)
413 .ok_or(DrawError::InsufficientMemory)?;
414 Ok(Self {
415 outlines,
416 memory,
417 coords,
418 point_count: 0,
419 contour_count: 0,
420 component_delta_count: 0,
421 ppem: ppem.unwrap_or_default(),
422 scale,
423 is_scaled,
424 is_hinted: false,
425 pedantic_hinting: false,
426 phantom: Default::default(),
427 hinter: None,
428 })
429 }
430
431 pub(crate) fn hinted(
432 outlines: &'a Outlines<'a>,
433 outline: &'a Outline,
434 buf: &'a mut [u8],
435 ppem: Option<f32>,
436 coords: &'a [F2Dot14],
437 hinter: &'a HintInstance,
438 pedantic_hinting: bool,
439 ) -> Result<Self, DrawError> {
440 outline.ensure_point_count_limit()?;
441 let (is_scaled, scale) = outlines.compute_hinted_scale(ppem);
442 let memory = FreeTypeOutlineMemory::new(outline, buf, Hinting::Embedded)
443 .ok_or(DrawError::InsufficientMemory)?;
444 Ok(Self {
445 outlines,
446 memory,
447 coords,
448 point_count: 0,
449 contour_count: 0,
450 component_delta_count: 0,
451 ppem: ppem.unwrap_or_default(),
452 scale,
453 is_scaled,
454 is_hinted: is_scaled,
456 pedantic_hinting,
457 phantom: Default::default(),
458 hinter: Some(hinter),
459 })
460 }
461
462 pub(crate) fn scale(
463 mut self,
464 glyph: &Option<Glyph>,
465 glyph_id: GlyphId,
466 ) -> Result<ScaledOutline<'a, F26Dot6>, DrawError> {
467 self.load(glyph, glyph_id, 0)?;
468 let hdmx_width = if self.is_hinted
472 && self
473 .hinter
474 .as_ref()
475 .map(|hinter| !hinter.backward_compatibility())
476 .unwrap_or(true)
477 {
478 self.outlines.hdmx_width(self.ppem, glyph_id)
479 } else {
480 None
481 };
482 Ok(ScaledOutline::new(
483 &mut self.memory.scaled[..self.point_count],
484 self.phantom,
485 &mut self.memory.flags[..self.point_count],
486 &mut self.memory.contours[..self.contour_count],
487 hdmx_width,
488 ))
489 }
490}
491
492impl Scaler for FreeTypeScaler<'_> {
493 fn setup_phantom_points(
494 &mut self,
495 bounds: [i16; 4],
496 lsb: i32,
497 advance: i32,
498 tsb: i32,
499 vadvance: i32,
500 ) {
501 self.phantom[0].x = F26Dot6::from_bits(bounds[0] as i32 - lsb);
505 self.phantom[0].y = F26Dot6::ZERO;
506 self.phantom[1].x = self.phantom[0].x + F26Dot6::from_bits(advance);
507 self.phantom[1].y = F26Dot6::ZERO;
508 self.phantom[2].x = F26Dot6::ZERO;
510 self.phantom[2].y = F26Dot6::from_bits(bounds[3] as i32 + tsb);
511 self.phantom[3].x = F26Dot6::ZERO;
512 self.phantom[3].y = self.phantom[2].y - F26Dot6::from_bits(vadvance);
513 }
514
515 fn outlines(&self) -> &Outlines<'_> {
516 self.outlines
517 }
518
519 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError> {
520 let scale = self.scale;
523 let mut unscaled = self.phantom.map(|point| point.map(|x| x.to_bits()));
524 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
525 if let Ok(Some(deltas)) = self.outlines.gvar.as_ref().unwrap().phantom_point_deltas(
526 &self.outlines.glyf,
527 &self.outlines.loca,
528 self.coords,
529 glyph_id,
530 ) {
531 unscaled[0] += deltas[0].map(Fixed::to_i32);
532 unscaled[1] += deltas[1].map(Fixed::to_i32);
533 }
534 }
535 if self.is_scaled {
536 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
537 *phantom = unscaled.map(F26Dot6::from_bits) * scale;
538 }
539 } else {
540 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
541 *phantom = unscaled.map(F26Dot6::from_i32);
542 }
543 }
544 Ok(())
545 }
546
547 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError> {
548 use DrawError::InsufficientMemory;
549 let points_start = self.point_count;
551 let point_count = glyph.num_points();
552 let phantom_start = point_count;
553 let points_end = points_start + point_count + PHANTOM_POINT_COUNT;
554 let point_range = points_start..points_end;
555 let other_points_end = point_count + PHANTOM_POINT_COUNT;
556 let scaled = self
558 .memory
559 .scaled
560 .get_mut(point_range.clone())
561 .ok_or(InsufficientMemory)?;
562 let flags = self
563 .memory
564 .flags
565 .get_mut(point_range)
566 .ok_or(InsufficientMemory)?;
567 let unscaled = self
571 .memory
572 .unscaled
573 .get_mut(..other_points_end)
574 .ok_or(InsufficientMemory)?;
575 glyph.read_points_fast(&mut unscaled[..point_count], &mut flags[..point_count])?;
578 let contours_start = self.contour_count;
580 let contour_end_pts = glyph.end_pts_of_contours();
581 let contour_count = contour_end_pts.len();
582 let contours_end = contours_start + contour_count;
583 let contours = self
584 .memory
585 .contours
586 .get_mut(contours_start..contours_end)
587 .ok_or(InsufficientMemory)?;
588 let mut last_end_pt = 0;
591 for (end_pt, contour) in contour_end_pts.iter().zip(contours.iter_mut()) {
592 let end_pt = end_pt.get();
593 if end_pt < last_end_pt {
594 return Err(ReadError::MalformedData(
595 "unordered contour end points in TrueType glyph",
596 )
597 .into());
598 }
599 last_end_pt = end_pt;
600 *contour = end_pt;
601 }
602 self.point_count += point_count;
604 self.contour_count += contour_count;
605 for (i, phantom) in self.phantom.iter().enumerate() {
607 unscaled[phantom_start + i] = phantom.map(|x| x.to_bits());
608 flags[phantom_start + i] = Default::default();
609 }
610 let mut have_deltas = false;
611 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
612 let gvar = self.outlines.gvar.as_ref().unwrap();
613 let glyph = deltas::SimpleGlyph {
614 points: &mut unscaled[..],
615 flags: &mut flags[..],
616 contours,
617 };
618 let deltas = self
619 .memory
620 .deltas
621 .get_mut(..point_count + PHANTOM_POINT_COUNT)
622 .ok_or(InsufficientMemory)?;
623 let iup_buffer = self
624 .memory
625 .iup_buffer
626 .get_mut(..point_count + PHANTOM_POINT_COUNT)
627 .ok_or(InsufficientMemory)?;
628 if deltas::simple_glyph(gvar, glyph_id, self.coords, glyph, iup_buffer, deltas).is_ok()
629 {
630 have_deltas = true;
631 }
632 }
633 let ins = glyph.instructions();
634 let is_hinted = self.is_hinted;
635 if self.is_scaled {
636 let scale = self.scale;
637 if have_deltas {
638 for ((point, unscaled), delta) in scaled
639 .iter_mut()
640 .zip(unscaled.iter())
641 .zip(self.memory.deltas.iter())
642 {
643 let delta = delta.map(Fixed::to_f26dot6);
644 let scaled = (unscaled.map(F26Dot6::from_i32) + delta) * scale;
645 *point = scaled.map(|v| F26Dot6::from_bits(v.to_i32()));
648 }
649 if self.outlines.glyph_metrics.hvar.is_some() {
653 for ((point, unscaled), delta) in scaled[phantom_start..]
654 .iter_mut()
655 .zip(&unscaled[phantom_start..])
656 .zip(&self.memory.deltas[phantom_start..])
657 {
658 let delta = delta.map(Fixed::to_i32).map(F26Dot6::from_i32);
659 let scaled = (unscaled.map(F26Dot6::from_i32) + delta) * scale;
660 *point = scaled.map(|v| F26Dot6::from_bits(v.to_i32()));
661 }
662 }
663 if is_hinted {
664 for (unscaled, delta) in unscaled.iter_mut().zip(self.memory.deltas.iter()) {
667 *unscaled += delta.map(Fixed::to_i32);
668 }
669 }
670 } else {
671 for (point, unscaled) in scaled.iter_mut().zip(unscaled.iter_mut()) {
672 *point = unscaled.map(|v| F26Dot6::from_bits(v) * scale);
673 }
674 }
675 } else {
676 if have_deltas {
677 for (unscaled, delta) in unscaled.iter_mut().zip(self.memory.deltas.iter()) {
679 *unscaled += delta.map(Fixed::to_i32);
680 }
681 }
682 for (point, unscaled) in scaled.iter_mut().zip(unscaled.iter()) {
684 *point = unscaled.map(F26Dot6::from_i32);
685 }
686 }
687 self.phantom.copy_from_slice(&scaled[phantom_start..]);
689 if let (Some(hinter), true) = (self.hinter.as_ref(), is_hinted) {
690 if !ins.is_empty() {
691 let original_scaled = self
693 .memory
694 .original_scaled
695 .get_mut(..other_points_end)
696 .ok_or(InsufficientMemory)?;
697 original_scaled.copy_from_slice(scaled);
698 for point in &mut scaled[phantom_start..] {
700 point.x = point.x.round();
701 point.y = point.y.round();
702 }
703 let mut input = HintOutline {
704 glyph_id,
705 unscaled,
706 scaled,
707 original_scaled,
708 flags,
709 contours,
710 bytecode: ins,
711 phantom: &mut self.phantom,
712 stack: self.memory.stack,
713 cvt: self.memory.cvt,
714 storage: self.memory.storage,
715 twilight_scaled: self.memory.twilight_scaled,
716 twilight_original_scaled: self.memory.twilight_original_scaled,
717 twilight_flags: self.memory.twilight_flags,
718 is_composite: false,
719 coords: self.coords,
720 };
721 let hint_res = hinter.hint(self.outlines, &mut input, self.pedantic_hinting);
722 if let (Err(e), true) = (hint_res, self.pedantic_hinting) {
723 return Err(e)?;
724 }
725 } else if !hinter.backward_compatibility() {
726 for (scaled, phantom) in scaled[phantom_start..].iter().zip(&mut self.phantom) {
734 *phantom = scaled.map(|x| x.round());
735 }
736 }
737 }
738 if points_start != 0 {
739 for contour_end in contours.iter_mut() {
741 *contour_end += points_start as u16;
742 }
743 }
744 Ok(())
745 }
746
747 fn load_composite(
748 &mut self,
749 glyph: &CompositeGlyph,
750 glyph_id: GlyphId,
751 recurse_depth: usize,
752 ) -> Result<(), DrawError> {
753 use DrawError::InsufficientMemory;
754 let scale = self.scale;
755 let point_base = self.point_count;
757 let contour_base = self.contour_count;
758 let mut have_deltas = false;
761 let delta_base = self.component_delta_count;
762 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
763 let gvar = self.outlines.gvar.as_ref().unwrap();
764 let count = glyph.components().count() + PHANTOM_POINT_COUNT;
765 let deltas = self
766 .memory
767 .composite_deltas
768 .get_mut(delta_base..delta_base + count)
769 .ok_or(InsufficientMemory)?;
770 if deltas::composite_glyph(gvar, glyph_id, self.coords, &mut deltas[..]).is_ok() {
771 for (phantom, delta) in self
773 .phantom
774 .iter_mut()
775 .zip(&deltas[deltas.len() - PHANTOM_POINT_COUNT..])
776 {
777 *phantom += delta.map(Fixed::to_i32).map(F26Dot6::from_bits);
778 }
779 have_deltas = true;
780 }
781 self.component_delta_count += count;
782 }
783 if self.is_scaled {
784 for point in self.phantom.iter_mut() {
785 *point *= scale;
786 }
787 } else {
788 for point in self.phantom.iter_mut() {
789 *point = point.map(|x| F26Dot6::from_i32(x.to_bits()));
790 }
791 }
792 for (i, component) in glyph.components().enumerate() {
793 let phantom = self.phantom;
796 let start_point = self.point_count;
798 let component_glyph = self
799 .outlines
800 .loca
801 .get_glyf(component.glyph.into(), &self.outlines.glyf)?;
802 self.load(&component_glyph, component.glyph.into(), recurse_depth + 1)?;
803 let end_point = self.point_count;
804 if !component
805 .flags
806 .contains(CompositeGlyphFlags::USE_MY_METRICS)
807 {
808 self.phantom = phantom;
811 }
812 fn scale_component(x: F2Dot14) -> F26Dot6 {
814 F26Dot6::from_bits(x.to_bits() as i32 * 4)
815 }
816 let xform = &component.transform;
817 let xx = scale_component(xform.xx);
818 let yx = scale_component(xform.yx);
819 let xy = scale_component(xform.xy);
820 let yy = scale_component(xform.yy);
821 let have_xform = component.flags.intersects(
822 CompositeGlyphFlags::WE_HAVE_A_SCALE
823 | CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
824 | CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO,
825 );
826 if have_xform {
827 let scaled = &mut self.memory.scaled[start_point..end_point];
828 if self.is_scaled {
829 for point in scaled {
830 let x = point.x * xx + point.y * xy;
831 let y = point.x * yx + point.y * yy;
832 point.x = x;
833 point.y = y;
834 }
835 } else {
836 for point in scaled {
837 let unscaled = point.map(|c| F26Dot6::from_bits(c.to_i32()));
840 let x = unscaled.x * xx + unscaled.y * xy;
841 let y = unscaled.x * yx + unscaled.y * yy;
842 *point = Point::new(x, y).map(|c| F26Dot6::from_i32(c.to_bits()));
843 }
844 }
845 }
846 let anchor_offset = match component.anchor {
847 Anchor::Offset { x, y } => {
848 let (mut x, mut y) = (x as i32, y as i32);
849 if have_xform
850 && component.flags
851 & (CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
852 | CompositeGlyphFlags::UNSCALED_COMPONENT_OFFSET)
853 == CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
854 {
855 fn hypot(a: F26Dot6, b: F26Dot6) -> Fixed {
859 let a = a.to_bits().abs();
860 let b = b.to_bits().abs();
861 Fixed::from_bits(if a > b {
862 a + ((3 * b) >> 3)
863 } else {
864 b + ((3 * a) >> 3)
865 })
866 }
867 x = (Fixed::from_bits(x) * hypot(xx, xy)).to_bits();
869 y = (Fixed::from_bits(y) * hypot(yy, yx)).to_bits();
870 }
871 if have_deltas {
872 let delta = self
873 .memory
874 .composite_deltas
875 .get(delta_base + i)
876 .copied()
877 .unwrap_or_default();
878 x += delta.x.to_i32();
881 y += delta.y.to_i32();
882 }
883 if self.is_scaled {
884 let mut offset = Point::new(x, y).map(F26Dot6::from_bits) * scale;
885 if self.is_hinted
886 && component
887 .flags
888 .contains(CompositeGlyphFlags::ROUND_XY_TO_GRID)
889 {
890 offset.y = offset.y.round();
892 }
893 offset
894 } else {
895 Point::new(x, y).map(F26Dot6::from_i32)
896 }
897 }
898 Anchor::Point { base, component } => {
899 let (base_offset, component_offset) = (base as usize, component as usize);
900 let base_point = self
901 .memory
902 .scaled
903 .get(point_base + base_offset)
904 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, base))?;
905 let component_point = self
906 .memory
907 .scaled
908 .get(start_point + component_offset)
909 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, component))?;
910 *base_point - *component_point
911 }
912 };
913 if anchor_offset.x != F26Dot6::ZERO || anchor_offset.y != F26Dot6::ZERO {
914 for point in &mut self.memory.scaled[start_point..end_point] {
915 *point += anchor_offset;
916 }
917 }
918 }
919 if have_deltas {
920 self.component_delta_count = delta_base;
921 }
922 if let (Some(hinter), true) = (self.hinter.as_ref(), self.is_hinted) {
923 let ins = glyph.instructions().unwrap_or_default();
924 if !ins.is_empty() {
925 let start_point = point_base;
928 let end_point = self.point_count + PHANTOM_POINT_COUNT;
929 let point_range = start_point..end_point;
930 let phantom_start = point_range.len() - PHANTOM_POINT_COUNT;
931 let scaled = &mut self.memory.scaled[point_range.clone()];
932 let flags = self
933 .memory
934 .flags
935 .get_mut(point_range.clone())
936 .ok_or(InsufficientMemory)?;
937 for (i, phantom) in self.phantom.iter().enumerate() {
939 scaled[phantom_start + i] = *phantom;
940 flags[phantom_start + i] = Default::default();
941 }
942 let other_points_end = point_range.len();
943 let unscaled = self
944 .memory
945 .unscaled
946 .get_mut(..other_points_end)
947 .ok_or(InsufficientMemory)?;
948 for (scaled, unscaled) in scaled.iter().zip(unscaled.iter_mut()) {
949 *unscaled = scaled.map(|x| x.to_bits());
950 }
951 let original_scaled = self
952 .memory
953 .original_scaled
954 .get_mut(..other_points_end)
955 .ok_or(InsufficientMemory)?;
956 original_scaled.copy_from_slice(scaled);
957 let contours = self
958 .memory
959 .contours
960 .get_mut(contour_base..self.contour_count)
961 .ok_or(InsufficientMemory)?;
962 for p in &mut scaled[phantom_start..] {
964 p.x = p.x.round();
965 p.y = p.y.round();
966 }
967 for flag in flags.iter_mut() {
969 flag.clear_marker(PointMarker::TOUCHED);
970 }
971 if point_base != 0 {
974 let delta = point_base as u16;
975 for contour in contours.iter_mut() {
976 *contour -= delta;
977 }
978 }
979 let mut input = HintOutline {
980 glyph_id,
981 unscaled,
982 scaled,
983 original_scaled,
984 flags,
985 contours,
986 bytecode: ins,
987 phantom: &mut self.phantom,
988 stack: self.memory.stack,
989 cvt: self.memory.cvt,
990 storage: self.memory.storage,
991 twilight_scaled: self.memory.twilight_scaled,
992 twilight_original_scaled: self.memory.twilight_original_scaled,
993 twilight_flags: self.memory.twilight_flags,
994 is_composite: true,
995 coords: self.coords,
996 };
997 let hint_res = hinter.hint(self.outlines, &mut input, self.pedantic_hinting);
998 if let (Err(e), true) = (hint_res, self.pedantic_hinting) {
999 return Err(e)?;
1000 }
1001 if point_base != 0 {
1003 let delta = point_base as u16;
1004 for contour in contours.iter_mut() {
1005 *contour += delta;
1006 }
1007 }
1008 }
1009 }
1010 Ok(())
1011 }
1012}
1013
1014impl Scaler for HarfBuzzScaler<'_> {
1015 fn setup_phantom_points(
1016 &mut self,
1017 bounds: [i16; 4],
1018 lsb: i32,
1019 advance: i32,
1020 tsb: i32,
1021 vadvance: i32,
1022 ) {
1023 self.phantom[0].x = bounds[0] as f32 - lsb as f32;
1026 self.phantom[0].y = 0.0;
1027 self.phantom[1].x = self.phantom[0].x + advance as f32;
1028 self.phantom[1].y = 0.0;
1029 self.phantom[2].x = 0.0;
1031 self.phantom[2].y = bounds[3] as f32 + tsb as f32;
1032 self.phantom[3].x = 0.0;
1033 self.phantom[3].y = self.phantom[2].y - vadvance as f32;
1034 }
1035
1036 fn outlines(&self) -> &Outlines<'_> {
1037 self.outlines
1038 }
1039
1040 fn load_empty(&mut self, glyph_id: GlyphId) -> Result<(), DrawError> {
1041 let scale = self.scale.to_f32();
1044 let mut unscaled = self.phantom;
1045 if self.outlines.glyph_metrics.hvar.is_none()
1046 && self.outlines.gvar.is_some()
1047 && !self.coords.is_empty()
1048 {
1049 if let Ok(Some(deltas)) = self.outlines.gvar.as_ref().unwrap().phantom_point_deltas(
1050 &self.outlines.glyf,
1051 &self.outlines.loca,
1052 self.coords,
1053 glyph_id,
1054 ) {
1055 unscaled[0] += deltas[0].map(Fixed::to_f32);
1056 unscaled[1] += deltas[1].map(Fixed::to_f32);
1057 }
1058 }
1059 if self.is_scaled {
1060 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
1061 *phantom = *unscaled * scale;
1062 }
1063 } else {
1064 for (phantom, unscaled) in self.phantom.iter_mut().zip(&unscaled) {
1065 *phantom = *unscaled;
1066 }
1067 }
1068 Ok(())
1069 }
1070
1071 fn load_simple(&mut self, glyph: &SimpleGlyph, glyph_id: GlyphId) -> Result<(), DrawError> {
1072 use DrawError::InsufficientMemory;
1073 let points_start = self.point_count;
1075 let point_count = glyph.num_points();
1076 let phantom_start = point_count;
1077 let points_end = points_start + point_count + PHANTOM_POINT_COUNT;
1078 let point_range = points_start..points_end;
1079 let points = self
1081 .memory
1082 .points
1083 .get_mut(point_range.clone())
1084 .ok_or(InsufficientMemory)?;
1085 let flags = self
1086 .memory
1087 .flags
1088 .get_mut(point_range)
1089 .ok_or(InsufficientMemory)?;
1090 glyph.read_points_fast(&mut points[..point_count], &mut flags[..point_count])?;
1091 let contours_start = self.contour_count;
1093 let contour_end_pts = glyph.end_pts_of_contours();
1094 let contour_count = contour_end_pts.len();
1095 let contours_end = contours_start + contour_count;
1096 let contours = self
1097 .memory
1098 .contours
1099 .get_mut(contours_start..contours_end)
1100 .ok_or(InsufficientMemory)?;
1101 for (end_pt, contour) in contour_end_pts.iter().zip(contours.iter_mut()) {
1103 *contour = end_pt.get();
1104 }
1105 self.point_count += point_count;
1107 self.contour_count += contour_count;
1108 for (i, phantom) in self.phantom.iter().enumerate() {
1110 points[phantom_start + i] = *phantom;
1111 flags[phantom_start + i] = Default::default();
1112 }
1113 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
1115 let gvar = self.outlines.gvar.as_ref().unwrap();
1116 let glyph = deltas::SimpleGlyph {
1117 points: &mut points[..],
1118 flags: &mut flags[..],
1119 contours,
1120 };
1121 let deltas = self
1122 .memory
1123 .deltas
1124 .get_mut(..point_count + PHANTOM_POINT_COUNT)
1125 .ok_or(InsufficientMemory)?;
1126 let iup_buffer = self
1127 .memory
1128 .iup_buffer
1129 .get_mut(..point_count + PHANTOM_POINT_COUNT)
1130 .ok_or(InsufficientMemory)?;
1131 if deltas::simple_glyph(gvar, glyph_id, self.coords, glyph, iup_buffer, deltas).is_ok()
1132 {
1133 for (point, delta) in points.iter_mut().zip(deltas) {
1134 *point += *delta;
1135 }
1136 }
1137 }
1138 if self.is_scaled {
1140 let scale = self.scale.to_f32();
1141 for point in points.iter_mut() {
1142 *point = point.map(|c| c * scale);
1143 }
1144 }
1145
1146 if points_start != 0 {
1147 for contour_end in contours.iter_mut() {
1149 *contour_end += points_start as u16;
1150 }
1151 }
1152 Ok(())
1153 }
1154
1155 fn load_composite(
1156 &mut self,
1157 glyph: &CompositeGlyph,
1158 glyph_id: GlyphId,
1159 recurse_depth: usize,
1160 ) -> Result<(), DrawError> {
1161 use DrawError::InsufficientMemory;
1162 let scale = self.scale.to_f32();
1163 let point_base = self.point_count;
1165 let mut have_deltas = false;
1168 let delta_base = self.component_delta_count;
1169 if self.outlines.gvar.is_some() && !self.coords.is_empty() {
1170 let gvar = self.outlines.gvar.as_ref().unwrap();
1171 let count = glyph.components().count() + PHANTOM_POINT_COUNT;
1172 let deltas = self
1173 .memory
1174 .composite_deltas
1175 .get_mut(delta_base..delta_base + count)
1176 .ok_or(InsufficientMemory)?;
1177 if deltas::composite_glyph(gvar, glyph_id, self.coords, &mut deltas[..]).is_ok() {
1178 for (phantom, delta) in self
1180 .phantom
1181 .iter_mut()
1182 .zip(&deltas[deltas.len() - PHANTOM_POINT_COUNT..])
1183 {
1184 *phantom += *delta;
1185 }
1186 have_deltas = true;
1187 }
1188 self.component_delta_count += count;
1189 }
1190 if self.is_scaled {
1191 for point in self.phantom.iter_mut() {
1192 *point *= scale;
1193 }
1194 }
1195 for (i, component) in glyph.components().enumerate() {
1196 let phantom = self.phantom;
1199 let start_point = self.point_count;
1201 let component_glyph = self
1202 .outlines
1203 .loca
1204 .get_glyf(component.glyph.into(), &self.outlines.glyf)?;
1205 self.load(&component_glyph, component.glyph.into(), recurse_depth + 1)?;
1206 let end_point = self.point_count;
1207 if !component
1208 .flags
1209 .contains(CompositeGlyphFlags::USE_MY_METRICS)
1210 {
1211 self.phantom = phantom;
1214 }
1215 let have_xform = component.flags.intersects(
1216 CompositeGlyphFlags::WE_HAVE_A_SCALE
1217 | CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
1218 | CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO,
1219 );
1220 let mut transform = if have_xform {
1221 let xform = &component.transform;
1222 [
1223 xform.xx,
1224 xform.yx,
1225 xform.xy,
1226 xform.yy,
1227 F2Dot14::ZERO,
1228 F2Dot14::ZERO,
1229 ]
1230 .map(|x| x.to_f32())
1231 } else {
1232 [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] };
1234
1235 let anchor_offset = match component.anchor {
1236 Anchor::Offset { x, y } => {
1237 let (mut x, mut y) = (x as f32, y as f32);
1238 if have_xform
1239 && component.flags
1240 & (CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
1241 | CompositeGlyphFlags::UNSCALED_COMPONENT_OFFSET)
1242 == CompositeGlyphFlags::SCALED_COMPONENT_OFFSET
1243 {
1244 x *= hypot(transform[0], transform[2]);
1247 y *= hypot(transform[1], transform[3]);
1248 }
1249 Point::new(x, y)
1250 + self
1251 .memory
1252 .composite_deltas
1253 .get(delta_base + i)
1254 .copied()
1255 .unwrap_or_default()
1256 }
1257 Anchor::Point { base, component } => {
1258 let (base_offset, component_offset) = (base as usize, component as usize);
1259 let base_point = self
1260 .memory
1261 .points
1262 .get(point_base + base_offset)
1263 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, base))?;
1264 let component_point = self
1265 .memory
1266 .points
1267 .get(start_point + component_offset)
1268 .ok_or(DrawError::InvalidAnchorPoint(glyph_id, component))?;
1269 *base_point - *component_point
1270 }
1271 };
1272 transform[4] = anchor_offset.x;
1273 transform[5] = anchor_offset.y;
1274
1275 let points = &mut self.memory.points[start_point..end_point];
1276 for point in points.iter_mut() {
1277 *point = map_point(transform, *point);
1278 }
1279 }
1280 if have_deltas {
1281 self.component_delta_count = delta_base;
1282 }
1283 Ok(())
1284 }
1285}
1286
1287fn hypot(x: f32, y: f32) -> f32 {
1289 x.hypot(y)
1290}
1291
1292fn map_point(transform: [f32; 6], p: Point<f32>) -> Point<f32> {
1293 Point {
1294 x: transform[0] * p.x + transform[2] * p.y + transform[4],
1295 y: transform[1] * p.x + transform[3] * p.y + transform[5],
1296 }
1297}
1298
1299#[cfg(test)]
1300mod tests {
1301 use super::*;
1302 use crate::MetadataProvider;
1303 use raw::{
1304 tables::{
1305 glyf::{CompositeGlyphFlags, Glyf, SimpleGlyphFlags},
1306 loca::Loca,
1307 },
1308 FontRead, FontRef, TableProvider,
1309 };
1310
1311 #[test]
1312 fn overlap_flags() {
1313 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1314 let scaler = Outlines::new(&font).unwrap();
1315 let glyph_count = font.maxp().unwrap().num_glyphs();
1316 let expected_gids_with_overlap = vec![2, 3];
1319 assert_eq!(
1320 expected_gids_with_overlap,
1321 (0..glyph_count)
1322 .filter(|gid| scaler.outline(GlyphId::from(*gid)).unwrap().has_overlaps)
1323 .collect::<Vec<_>>()
1324 );
1325 }
1326
1327 #[test]
1328 fn interpreter_preference() {
1329 let font = FontRef::new(font_test_data::COLRV0V1).unwrap();
1331 let outlines = Outlines::new(&font).unwrap();
1332 assert!(!outlines.prefer_interpreter());
1334 let font = FontRef::new(font_test_data::TTHINT_SUBSET).unwrap();
1336 let outlines = Outlines::new(&font).unwrap();
1337 assert!(outlines.prefer_interpreter());
1339 }
1340
1341 #[test]
1342 fn empty_glyph_advance() {
1343 let font = FontRef::new(font_test_data::HVAR_WITH_TRUNCATED_ADVANCE_INDEX_MAP).unwrap();
1344 let outlines = Outlines::new(&font).unwrap();
1345 let coords = [F2Dot14::from_f32(0.5)];
1346 let ppem = Some(24.0);
1347 let gid = font.charmap().map(' ').unwrap();
1348 let outline = outlines.outline(gid).unwrap();
1349 assert!(outline.glyph.is_none());
1351 let mut buf = [0u8; 128];
1352 let scaler =
1353 FreeTypeScaler::unhinted(&outlines, &outline, &mut buf, ppem, &coords).unwrap();
1354 let scaled = scaler.scale(&outline.glyph, gid).unwrap();
1355 let advance = scaled.adjusted_advance_width();
1356 assert!(advance != F26Dot6::ZERO);
1357 }
1358
1359 #[test]
1360 fn empty_glyphs_have_phantom_points_too() {
1361 let font = FontRef::new(font_test_data::HVAR_WITH_TRUNCATED_ADVANCE_INDEX_MAP).unwrap();
1362 let outlines = Outlines::new(&font).unwrap();
1363 let gid = font.charmap().map(' ').unwrap();
1364 let outline = outlines.outline(gid).unwrap();
1365 assert!(outline.glyph.is_none());
1366 assert_eq!(outline.points, PHANTOM_POINT_COUNT);
1367 }
1368
1369 #[test]
1372 fn composite_with_too_many_points() {
1373 let font = FontRef::new(font_test_data::GLYF_COMPONENTS).unwrap();
1374 let mut outlines = Outlines::new(&font).unwrap();
1375 let mut glyf_buf = font_test_data::bebuffer::BeBuffer::new();
1378 let simple_glyph_point_count = 40000;
1381 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 {
1386 glyf_buf =
1387 glyf_buf.push(SimpleGlyphFlags::X_SHORT_VECTOR | SimpleGlyphFlags::Y_SHORT_VECTOR);
1388 }
1389 for _ in 0..simple_glyph_point_count * 2 {
1391 glyf_buf = glyf_buf.push(0u8);
1392 }
1393 let glyph0_end = glyf_buf.len();
1394 glyf_buf = glyf_buf.push(-1i16); glyf_buf = glyf_buf.extend([0i16; 4]); for i in 0..2 {
1398 let flags = if i == 0 {
1399 CompositeGlyphFlags::MORE_COMPONENTS | CompositeGlyphFlags::ARGS_ARE_XY_VALUES
1400 } else {
1401 CompositeGlyphFlags::ARGS_ARE_XY_VALUES
1402 };
1403 glyf_buf = glyf_buf.push(flags); glyf_buf = glyf_buf.push(0u16); glyf_buf = glyf_buf.extend([0u8; 2]); }
1407 let glyph1_end = glyf_buf.len();
1408 outlines.glyf = Glyf::read(glyf_buf.data().into()).unwrap();
1409 let mut loca_buf = font_test_data::bebuffer::BeBuffer::new();
1411 loca_buf = loca_buf.extend([0u32, glyph0_end as u32, glyph1_end as u32]);
1412 outlines.loca = Loca::read(loca_buf.data().into(), true).unwrap();
1413 let gid = GlyphId::new(1);
1414 let outline = outlines.outline(gid).unwrap();
1415 let mut mem_buf = vec![0u8; outline.required_buffer_size(Default::default())];
1416 assert!(outline.points > u16::MAX as usize);
1418 let result = FreeTypeScaler::unhinted(&outlines, &outline, &mut mem_buf, None, &[]);
1419 assert!(matches!(result, Err(DrawError::TooManyPoints(_))));
1421 }
1422
1423 #[test]
1424 fn fractional_size_hinting() {
1425 let font = FontRef::from_index(font_test_data::TINOS_SUBSET, 0).unwrap();
1426 let outlines = Outlines::new(&font).unwrap();
1427 assert!(!outlines.fractional_size_hinting);
1429 for size in [10.0, 10.2, 10.5, 10.8, 11.0] {
1432 assert_eq!(
1433 outlines.compute_hinted_scale(Some(size)),
1434 outlines.compute_hinted_scale(Some(size.round()))
1435 );
1436 }
1437 }
1438}