1use crate::error::Result;
2use crate::stream::FontReader;
3use super::loca::LocaTable;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Point {
8 pub x: f32,
9 pub y: f32,
10}
11
12impl Point {
13 pub fn new(x: f32, y: f32) -> Self {
14 Self { x, y }
15 }
16
17 pub fn transform(&self, transform: &Transform) -> Point {
19 Point {
20 x: transform.xx * self.x + transform.xy * self.y + transform.dx,
21 y: transform.yx * self.x + transform.yy * self.y + transform.dy,
22 }
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq)]
28pub struct BoundingBox {
29 pub x_min: f32,
30 pub y_min: f32,
31 pub x_max: f32,
32 pub y_max: f32,
33}
34
35impl BoundingBox {
36 pub fn new(x_min: f32, y_min: f32, x_max: f32, y_max: f32) -> Self {
37 Self {
38 x_min,
39 y_min,
40 x_max,
41 y_max,
42 }
43 }
44
45 pub fn from_glyph(x_min: i16, y_min: i16, x_max: i16, y_max: i16) -> Self {
47 Self {
48 x_min: x_min as f32,
49 y_min: y_min as f32,
50 x_max: x_max as f32,
51 y_max: y_max as f32,
52 }
53 }
54
55 pub fn width(&self) -> f32 {
57 self.x_max - self.x_min
58 }
59
60 pub fn height(&self) -> f32 {
62 self.y_max - self.y_min
63 }
64
65 pub fn merge(&self, other: &BoundingBox) -> BoundingBox {
67 BoundingBox {
68 x_min: self.x_min.min(other.x_min),
69 y_min: self.y_min.min(other.y_min),
70 x_max: self.x_max.max(other.x_max),
71 y_max: self.y_max.max(other.y_max),
72 }
73 }
74}
75
76#[derive(Debug, Clone)]
78pub struct GlyfTable {
79 pub glyphs: Vec<Glyph>,
80}
81
82#[derive(Debug, Clone)]
83pub struct Glyph {
84 pub number_of_contours: i16,
85 pub x_min: i16,
86 pub y_min: i16,
87 pub x_max: i16,
88 pub y_max: i16,
89 pub data: GlyphData,
90}
91
92#[derive(Debug, Clone)]
93pub enum GlyphData {
94 Simple(SimpleGlyph),
95 Composite(CompositeGlyph),
96 Empty,
97}
98
99#[derive(Debug, Clone)]
100pub struct SimpleGlyph {
101 pub end_pts_of_contours: Vec<u16>,
102 pub instruction_length: u16,
103 pub instructions: Vec<u8>,
104 pub flags: Vec<u8>,
105 pub x_coordinates: Vec<i16>,
106 pub y_coordinates: Vec<i16>,
107}
108
109#[derive(Debug, Clone)]
110pub struct CompositeGlyph {
111 pub components: Vec<GlyphComponent>,
112}
113
114#[derive(Debug, Clone)]
115pub struct GlyphComponent {
116 pub flags: u16,
117 pub glyph_index: u16,
118 pub arg1: i16,
119 pub arg2: i16,
120 pub transform: Transform,
121}
122
123#[derive(Debug, Clone)]
124pub struct Transform {
125 pub xx: f32,
126 pub xy: f32,
127 pub yx: f32,
128 pub yy: f32,
129 pub dx: f32,
130 pub dy: f32,
131}
132
133impl Glyph {
134 pub fn is_simple(&self) -> bool {
135 matches!(self.data, GlyphData::Simple(_))
136 }
137
138 pub fn is_composite(&self) -> bool {
139 matches!(self.data, GlyphData::Composite(_))
140 }
141
142 pub fn is_empty(&self) -> bool {
143 matches!(self.data, GlyphData::Empty)
144 }
145
146 pub fn calculate_bounding_box(&self) -> Option<BoundingBox> {
148 if self.is_empty() {
149 return None;
150 }
151
152 if let GlyphData::Simple(simple) = &self.data {
154 if simple.x_coordinates.is_empty() {
155 return Some(BoundingBox::from_glyph(
156 self.x_min, self.y_min, self.x_max, self.y_max
157 ));
158 }
159
160 let mut x_min = f32::MAX;
161 let mut y_min = f32::MAX;
162 let mut x_max = f32::MIN;
163 let mut y_max = f32::MIN;
164
165 for i in 0..simple.x_coordinates.len() {
166 let x = simple.x_coordinates[i] as f32;
167 let y = simple.y_coordinates[i] as f32;
168 x_min = x_min.min(x);
169 y_min = y_min.min(y);
170 x_max = x_max.max(x);
171 y_max = y_max.max(y);
172 }
173
174 Some(BoundingBox::new(x_min, y_min, x_max, y_max))
175 } else if let GlyphData::Composite(composite) = &self.data {
176 Some(BoundingBox::from_glyph(
178 self.x_min, self.y_min, self.x_max, self.y_max
179 ))
180 } else {
181 None
182 }
183 }
184
185 pub fn transform(&mut self, transform: &Transform) -> Result<()> {
187 match &mut self.data {
188 GlyphData::Simple(simple) => {
189 for (x, y) in simple.x_coordinates.iter_mut().zip(simple.y_coordinates.iter_mut()) {
191 let old_x = *x as f32;
192 let old_y = *y as f32;
193 let new_x = transform.xx * old_x + transform.xy * old_y + transform.dx;
194 let new_y = transform.yx * old_x + transform.yy * old_y + transform.dy;
195 *x = new_x.round() as i16;
196 *y = new_y.round() as i16;
197 }
198
199 if let Some(bbox) = self.calculate_bounding_box() {
201 self.x_min = bbox.x_min.round() as i16;
202 self.y_min = bbox.y_min.round() as i16;
203 self.x_max = bbox.x_max.round() as i16;
204 self.y_max = bbox.y_max.round() as i16;
205 }
206 }
207 GlyphData::Composite(composite) => {
208 for component in &mut composite.components {
210 component.transform = Self::combine_transforms(&component.transform, transform);
211 }
212
213 if let Some(bbox) = self.calculate_bounding_box() {
215 self.x_min = bbox.x_min.round() as i16;
216 self.y_min = bbox.y_min.round() as i16;
217 self.x_max = bbox.x_max.round() as i16;
218 self.y_max = bbox.y_max.round() as i16;
219 }
220 }
221 GlyphData::Empty => {}
222 }
223 Ok(())
224 }
225
226 pub fn scale(&mut self, scale_x: f32, scale_y: f32) -> Result<()> {
228 let transform = Transform {
229 xx: scale_x,
230 xy: 0.0,
231 yx: 0.0,
232 yy: scale_y,
233 dx: 0.0,
234 dy: 0.0,
235 };
236 self.transform(&transform)
237 }
238
239 pub fn rotate(&mut self, angle: f32) -> Result<()> {
241 let cos_a = angle.cos();
242 let sin_a = angle.sin();
243 let transform = Transform {
244 xx: cos_a,
245 xy: -sin_a,
246 yx: sin_a,
247 yy: cos_a,
248 dx: 0.0,
249 dy: 0.0,
250 };
251 self.transform(&transform)
252 }
253
254 pub fn translate(&mut self, dx: f32, dy: f32) -> Result<()> {
256 let transform = Transform {
257 xx: 1.0,
258 xy: 0.0,
259 yx: 0.0,
260 yy: 1.0,
261 dx,
262 dy,
263 };
264 self.transform(&transform)
265 }
266
267 fn combine_transforms(first: &Transform, second: &Transform) -> Transform {
269 Transform {
270 xx: first.xx * second.xx + first.xy * second.yx,
271 xy: first.xx * second.xy + first.xy * second.yy,
272 yx: first.yx * second.xx + first.yy * second.yx,
273 yy: first.yx * second.xy + first.yy * second.yy,
274 dx: first.xx * second.dx + first.xy * second.dy + first.dx,
275 dy: first.yx * second.dx + first.yy * second.dy + first.dy,
276 }
277 }
278
279 pub fn simplify(&mut self, tolerance: f32) -> Result<()> {
282 if let GlyphData::Simple(simple) = &mut self.data {
283 if simple.x_coordinates.len() < 3 {
284 return Ok(());
285 }
286
287 let mut to_remove = vec![false; simple.x_coordinates.len()];
288
289 let mut contour_start = 0;
291 for &end_pt in &simple.end_pts_of_contours {
292 let end = end_pt as usize;
293
294 for i in (contour_start + 1)..end {
296 let prev = if i > contour_start { i - 1 } else { end };
297 let next = if i < end { i + 1 } else { contour_start };
298
299 let x1 = simple.x_coordinates[prev] as f32;
300 let y1 = simple.y_coordinates[prev] as f32;
301 let x2 = simple.x_coordinates[i] as f32;
302 let y2 = simple.y_coordinates[i] as f32;
303 let x3 = simple.x_coordinates[next] as f32;
304 let y3 = simple.y_coordinates[next] as f32;
305
306 let area = ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)).abs();
308
309 if area < tolerance {
310 let dist = ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt();
312 if dist < tolerance || ((x3 - x2).powi(2) + (y3 - y2).powi(2)).sqrt() < tolerance {
313 to_remove[i] = true;
314 }
315 }
316 }
317
318 contour_start = end + 1;
319 }
320
321 for i in (0..to_remove.len()).rev() {
323 if to_remove[i] {
324 simple.x_coordinates.remove(i);
325 simple.y_coordinates.remove(i);
326 simple.flags.remove(i);
327
328 for end_pt in &mut simple.end_pts_of_contours {
330 if *end_pt as usize > i {
331 *end_pt = (*end_pt as usize - 1) as u16;
332 }
333 }
334 }
335 }
336 }
337 Ok(())
338 }
339}
340
341impl Default for Transform {
342 fn default() -> Self {
343 Self {
344 xx: 1.0,
345 xy: 0.0,
346 yx: 0.0,
347 yy: 1.0,
348 dx: 0.0,
349 dy: 0.0,
350 }
351 }
352}
353
354impl GlyfTable {
355 pub fn from_reader(reader: &mut FontReader, _length: u32, loca: &LocaTable, num_glyphs: u16) -> Result<Self> {
356 let mut glyphs = Vec::with_capacity(num_glyphs as usize);
357
358 for i in 0..num_glyphs {
359 let offset = loca.get_offset(i as usize)?;
360 let next_offset = loca.get_offset(i as usize + 1)?;
361
362 if offset == next_offset {
363 glyphs.push(Glyph {
365 number_of_contours: 0,
366 x_min: 0,
367 y_min: 0,
368 x_max: 0,
369 y_max: 0,
370 data: GlyphData::Empty,
371 });
372 continue;
373 }
374
375 reader.set_position(offset as usize)?;
376
377 let number_of_contours = reader.read_i16()?;
378 let x_min = reader.read_i16()?;
379 let y_min = reader.read_i16()?;
380 let x_max = reader.read_i16()?;
381 let y_max = reader.read_i16()?;
382
383 let data = if number_of_contours > 0 {
384 GlyphData::Simple(SimpleGlyph::read(reader, number_of_contours as usize)?)
386 } else if number_of_contours < 0 {
387 GlyphData::Composite(CompositeGlyph::read(reader)?)
389 } else {
390 GlyphData::Empty
391 };
392
393 glyphs.push(Glyph {
394 number_of_contours,
395 x_min,
396 y_min,
397 x_max,
398 y_max,
399 data,
400 });
401 }
402
403 Ok(GlyfTable { glyphs })
404 }
405
406 pub fn get_glyph(&self, index: usize) -> Option<&Glyph> {
407 self.glyphs.get(index)
408 }
409
410 pub fn get_glyph_mut(&mut self, index: usize) -> Option<&mut Glyph> {
411 self.glyphs.get_mut(index)
412 }
413
414 pub fn resolve_composite(&self, glyph_index: usize) -> Result<Option<Glyph>> {
417 let glyph = self.get_glyph(glyph_index);
418 let glyph = match glyph {
419 Some(g) => g,
420 None => return Ok(None),
421 };
422
423 match &glyph.data {
424 GlyphData::Simple(_) | GlyphData::Empty => {
425 Ok(Some(glyph.clone()))
427 }
428 GlyphData::Composite(composite) => {
429 let mut all_points: Vec<(i16, i16)> = Vec::new();
431 let mut all_flags: Vec<u8> = Vec::new();
432 let mut all_contours: Vec<u16> = Vec::new();
433 let mut total_contours = 0;
434
435 for component in &composite.components {
436 let component_glyph = self.get_glyph(component.glyph_index as usize);
437 let component_glyph = match component_glyph {
438 Some(g) => g,
439 None => continue,
440 };
441
442 if let GlyphData::Simple(simple) = &component_glyph.data {
443 let transform = &component.transform;
444
445 let point_count = simple.x_coordinates.len();
447 for i in 0..point_count {
448 let x = simple.x_coordinates[i] as f32;
449 let y = simple.y_coordinates[i] as f32;
450
451 let new_x = transform.xx * x + transform.xy * y + transform.dx;
452 let new_y = transform.yx * x + transform.yy * y + transform.dy;
453
454 all_points.push((new_x.round() as i16, new_y.round() as i16));
455 all_flags.push(simple.flags.get(i).copied().unwrap_or(0));
456 }
457
458 for end_pt in &simple.end_pts_of_contours {
460 all_contours.push((*end_pt as usize + total_contours) as u16);
461 total_contours += *end_pt as usize + 1;
462 }
463 }
464 }
465
466 if !all_points.is_empty() {
468 let mut x_coordinates = Vec::new();
469 let mut y_coordinates = Vec::new();
470 for (x, y) in &all_points {
471 x_coordinates.push(*x);
472 y_coordinates.push(*y);
473 }
474
475 let x_min = x_coordinates.iter().min().unwrap();
477 let y_min = y_coordinates.iter().min().unwrap();
478 let x_max = x_coordinates.iter().max().unwrap();
479 let y_max = y_coordinates.iter().max().unwrap();
480
481 Ok(Some(Glyph {
482 number_of_contours: all_contours.len() as i16,
483 x_min: *x_min,
484 y_min: *y_min,
485 x_max: *x_max,
486 y_max: *y_max,
487 data: GlyphData::Simple(SimpleGlyph {
488 end_pts_of_contours: all_contours,
489 instruction_length: 0,
490 instructions: Vec::new(),
491 flags: all_flags,
492 x_coordinates,
493 y_coordinates,
494 }),
495 }))
496 } else {
497 Ok(None)
498 }
499 }
500 }
501 }
502}
503
504impl SimpleGlyph {
505 fn read(reader: &mut FontReader, num_contours: usize) -> Result<Self> {
506 let mut end_pts_of_contours = Vec::with_capacity(num_contours);
507 for _ in 0..num_contours {
508 end_pts_of_contours.push(reader.read_u16()?);
509 }
510
511 let instruction_length = reader.read_u16()?;
512 let mut instructions = Vec::with_capacity(instruction_length as usize);
513 for _ in 0..instruction_length {
514 instructions.push(reader.read_u8()?);
515 }
516
517 let num_points = if let Some(&last) = end_pts_of_contours.last() {
518 last as usize + 1
519 } else {
520 0
521 };
522
523 let mut flags = Vec::with_capacity(num_points);
524 let mut i = 0;
525 while i < num_points {
526 let flag = reader.read_u8()?;
527 flags.push(flag);
528 i += 1;
529
530 if flag & 0x8 != 0 {
532 let repeat_count = reader.read_u8()? as usize;
533 for _ in 0..repeat_count {
534 flags.push(flag);
535 i += 1;
536 }
537 }
538 }
539
540 let mut x_coordinates = Vec::with_capacity(num_points);
541 let mut x = 0i16;
542 for &flag in &flags {
543 if flag & 0x2 != 0 {
544 let val = reader.read_i8()?;
546 x += if flag & 0x10 != 0 { val as i16 } else { -(val as i16) };
547 } else if flag & 0x10 == 0 {
548 x += reader.read_i16()?;
550 }
551 x_coordinates.push(x);
553 }
554
555 let mut y_coordinates = Vec::with_capacity(num_points);
556 let mut y = 0i16;
557 for &flag in &flags {
558 if flag & 0x4 != 0 {
559 let val = reader.read_i8()?;
561 y += if flag & 0x20 != 0 { val as i16 } else { -(val as i16) };
562 } else if flag & 0x20 == 0 {
563 y += reader.read_i16()?;
565 }
566 y_coordinates.push(y);
568 }
569
570 Ok(SimpleGlyph {
571 end_pts_of_contours,
572 instruction_length,
573 instructions,
574 flags,
575 x_coordinates,
576 y_coordinates,
577 })
578 }
579}
580
581impl CompositeGlyph {
582 fn read(reader: &mut FontReader) -> Result<Self> {
583 let mut components = Vec::new();
584
585 loop {
586 let flags = reader.read_u16()?;
587 let glyph_index = reader.read_u16()?;
588
589 let arg1 = if flags & 0x1 != 0 {
590 reader.read_i16()?
591 } else {
592 reader.read_i8()? as i16
593 };
594
595 let arg2 = if flags & 0x1 != 0 {
596 reader.read_i16()?
597 } else {
598 reader.read_i8()? as i16
599 };
600
601 let mut transform = Transform::default();
602
603 transform.xx = if flags & 0x80 != 0 {
605 reader.read_f2dot14()?
606 } else {
607 1.0
608 };
609
610 transform.xy = if flags & 0x40 != 0 {
611 reader.read_f2dot14()?
612 } else {
613 0.0
614 };
615
616 transform.yx = if flags & 0x20 != 0 {
617 reader.read_f2dot14()?
618 } else {
619 0.0
620 };
621
622 transform.yy = if flags & 0x10 != 0 {
623 reader.read_f2dot14()?
624 } else {
625 1.0
626 };
627
628 if flags & 0x8 != 0 {
629 transform.dx = reader.read_i16()? as f32;
630 transform.dy = reader.read_i16()? as f32;
631 } else {
632 transform.dx = arg1 as f32;
634 transform.dy = arg2 as f32;
635 }
636
637 components.push(GlyphComponent {
638 flags,
639 glyph_index,
640 arg1,
641 arg2,
642 transform,
643 });
644
645 if flags & 0x20 == 0 {
646 break;
648 }
649 }
650
651 Ok(CompositeGlyph { components })
652 }
653}