1use super::internal::*;
4use super::{FontRef, GlyphId};
5
6#[cfg(feature = "scale")]
7use alloc::vec::Vec;
8#[cfg(all(feature = "libm", feature = "scale"))]
9use core_maths::CoreFloat;
10
11#[derive(Copy, Clone)]
13pub struct BitmapStrikesProxy {
14 bitmaps: (u32, u32),
15 color_bitmaps: (u32, u32),
16 upem: u16,
17 is_apple: bool,
18}
19
20impl BitmapStrikesProxy {
21 pub fn from_font<'a>(font: &FontRef<'a>) -> Self {
23 let upem = font.head().map(|h| h.units_per_em()).unwrap_or(1);
24 let mut bitmaps = (0, 0);
25 let eblc = font.table_offset(raw_tag(b"EBLC"));
26 if eblc != 0 {
27 let ebdt = font.table_offset(raw_tag(b"EBDT"));
28 if ebdt != 0 {
29 bitmaps = (eblc, ebdt);
30 }
31 }
32 let mut color_bitmaps = (0, 0);
33 let sbix = font.table_offset(raw_tag(b"sbix"));
34 let mut is_apple = false;
35 if sbix != 0 {
36 color_bitmaps = (sbix, sbix);
37 use super::string::StringId::Family;
38 if let Some(name) = font.localized_strings().find_by_id(Family, None) {
39 is_apple = name.chars().eq("Apple Color Emoji".chars());
40 }
41 } else {
42 let cblc = font.table_offset(raw_tag(b"CBLC"));
43 if cblc != 0 {
44 let cbdt = font.table_offset(raw_tag(b"CBDT"));
45 if cbdt != 0 {
46 color_bitmaps = (cblc, cbdt);
47 }
48 }
49 }
50 Self {
51 bitmaps,
52 color_bitmaps,
53 upem,
54 is_apple,
55 }
56 }
57
58 pub fn has_alpha(&self) -> bool {
60 self.bitmaps.0 != 0
61 }
62
63 pub fn has_color(&self) -> bool {
65 self.color_bitmaps.0 != 0
66 }
67
68 pub fn materialize_alpha<'a>(&self, font: &FontRef<'a>) -> BitmapStrikes<'a> {
71 self.materialize_impl(font.data, self.bitmaps.0, self.bitmaps.1, self.upem, false)
72 }
73
74 pub fn materialize_color<'a>(&self, font: &FontRef<'a>) -> BitmapStrikes<'a> {
77 self.materialize_impl(
78 font.data,
79 self.color_bitmaps.0,
80 self.color_bitmaps.1,
81 self.upem,
82 self.is_apple,
83 )
84 }
85
86 fn materialize_impl<'a>(
87 &self,
88 data: &'a [u8],
89 loc: u32,
90 dat: u32,
91 upem: u16,
92 is_apple: bool,
93 ) -> BitmapStrikes<'a> {
94 if loc == 0 {
95 BitmapStrikes::new(&[], &[], upem, false, false)
96 } else if loc == dat {
97 let loc = data.get(loc as usize..).unwrap_or(&[]);
98 BitmapStrikes::new(loc, loc, upem, true, is_apple)
99 } else {
100 let loc = data.get(loc as usize..).unwrap_or(&[]);
101 let dat = data.get(dat as usize..).unwrap_or(&[]);
102 BitmapStrikes::new(loc, dat, upem, false, false)
103 }
104 }
105}
106
107#[derive(Copy, Clone)]
109pub struct BitmapStrikes<'a> {
110 data: Bytes<'a>,
111 bitmap_data: &'a [u8],
112 is_sbix: bool,
113 is_apple: bool,
114 upem: u16,
115 len: usize,
116 pos: usize,
117}
118
119impl<'a> BitmapStrikes<'a> {
120 fn new(
121 data: &'a [u8],
122 bitmap_data: &'a [u8],
123 upem: u16,
124 is_sbix: bool,
125 is_apple: bool,
126 ) -> Self {
127 let data = Bytes::new(data);
128 Self {
129 data,
130 bitmap_data,
131 upem,
132 is_sbix,
133 is_apple,
134 len: data.read_or_default::<u32>(4) as usize,
135 pos: 0,
136 }
137 }
138
139 fn get(&self, index: usize) -> Option<BitmapStrike<'a>> {
141 if index >= self.len {
142 return None;
143 }
144 let offset = if self.is_sbix {
145 self.data.read::<u32>(8 + index * 4)? as usize
146 } else {
147 8 + index * 48
148 };
149 Some(BitmapStrike {
150 data: self.data,
151 bitmap_data: self.bitmap_data,
152 upem: self.upem,
153 is_sbix: self.is_sbix,
154 is_apple: self.is_apple,
155 offset,
156 })
157 }
158
159 pub fn find_by_nearest_ppem(&self, ppem: u16, glyph_id: GlyphId) -> Option<BitmapStrike<'a>> {
167 let mut best = None;
168 let mut best_size = 0;
169 for i in 0..self.len {
170 let strike = match self.get(i) {
171 Some(strike) => strike,
172 _ => continue,
173 };
174 if !strike.contains(glyph_id) {
175 continue;
176 }
177 best = Some(strike);
178 let strike_ppem = strike.ppem();
179 if strike_ppem > best_size {
180 best = Some(strike);
181 best_size = strike_ppem;
182 }
183 if strike_ppem >= ppem {
184 return Some(strike);
185 }
186 }
187 best
188 }
189
190 pub fn find_by_exact_ppem(&self, ppem: u16, glyph_id: GlyphId) -> Option<BitmapStrike<'a>> {
197 for i in 0..self.len {
198 let strike = match self.get(i) {
199 Some(strike) => strike,
200 _ => continue,
201 };
202 if !strike.contains(glyph_id) {
203 continue;
204 }
205 if strike.ppem() == ppem {
206 return Some(strike);
207 }
208 }
209 None
210 }
211
212 pub fn find_by_largest_ppem(&self, glyph_id: GlyphId) -> Option<BitmapStrike<'a>> {
219 let mut largest = None;
220 let mut largest_ppem = 0;
221 for i in 0..self.len {
222 let strike = match self.get(i) {
223 Some(strike) => strike,
224 _ => continue,
225 };
226 if !strike.contains(glyph_id) {
227 continue;
228 }
229 let strike_ppem = strike.ppem();
230 if largest.is_none() || strike_ppem > largest_ppem {
231 largest = Some(strike);
232 largest_ppem = strike_ppem;
233 }
234 }
235 largest
236 }
237}
238
239impl_iter!(BitmapStrikes, BitmapStrike);
240
241#[derive(Copy, Clone)]
243#[allow(dead_code)]
244pub struct BitmapStrike<'a> {
245 data: Bytes<'a>,
246 bitmap_data: &'a [u8],
247 offset: usize,
248 upem: u16,
249 is_sbix: bool,
250 is_apple: bool,
251}
252
253impl<'a> BitmapStrike<'a> {
254 pub fn ppi(&self) -> u16 {
256 if self.is_sbix {
257 self.data.read_or_default::<u16>(self.offset + 2)
258 } else {
259 72
260 }
261 }
262
263 pub fn bit_depth(&self) -> u8 {
265 if self.is_sbix {
266 return 32;
267 }
268 self.data.read_or_default::<u8>(self.offset + 46)
269 }
270
271 pub fn ppem(&self) -> u16 {
273 if self.is_sbix {
274 self.data.read_or_default::<u16>(self.offset)
275 } else {
276 self.data.read_or_default::<u8>(self.offset + 45) as u16
277 }
278 }
279
280 pub fn contains(&self, glyph_id: GlyphId) -> bool {
282 get_coverage(&self.data, self.offset, self.is_sbix, glyph_id).unwrap_or(false)
283 }
284
285 #[cfg(feature = "scale")]
287 pub(crate) fn get(&self, glyph_id: GlyphId) -> Option<Bitmap<'a>> {
288 let loc = get_location(&self.data, self.offset, self.is_sbix, glyph_id)?;
289 loc.get(self.bitmap_data, self.upem, self.is_apple)
290 }
291}
292
293#[cfg(feature = "scale")]
295#[derive(Copy, Clone, PartialEq, Eq, Debug)]
296pub enum BitmapFormat {
297 Alpha(u8),
299 Packed(u8),
301 Color,
303 Png,
305}
306
307#[cfg(feature = "scale")]
308impl BitmapFormat {
309 pub fn channels(&self) -> u32 {
311 match self {
312 Self::Alpha(..) | Self::Packed(..) => 1,
313 _ => 4,
314 }
315 }
316
317 pub fn buffer_size(&self, width: u32, height: u32) -> usize {
320 (width * height * self.channels()) as usize
321 }
322}
323
324#[cfg(feature = "scale")]
326#[derive(Copy, Clone)]
327pub struct Bitmap<'a> {
328 pub format: BitmapFormat,
329 pub ppem: u16,
330 pub width: u32,
331 pub height: u32,
332 pub left: i32,
333 pub top: i32,
334 pub data: &'a [u8],
335}
336
337#[cfg(feature = "scale")]
338impl<'a> Bitmap<'a> {
339 fn new(data: &BitmapData<'a>, upem: u16, is_apple: bool) -> Option<Self> {
340 let format = if data.is_packed {
341 BitmapFormat::Packed(data.bit_depth)
342 } else if data.is_png {
343 BitmapFormat::Png
344 } else if data.bit_depth == 32 {
345 BitmapFormat::Color
346 } else {
347 BitmapFormat::Alpha(data.bit_depth)
348 };
349 let (width, height, left, top) = if data.is_png {
350 let png = Bytes::new(data.data);
351 let width = png.read::<u32>(16)?;
352 let height = png.read::<u32>(20)?;
353 let (left, mut top) = (data.metrics.x as i32, data.metrics.y as i32);
354 if data.is_sbix {
355 if top == 0 && is_apple {
356 let s = data.ppem as f32 / upem as f32;
357 top = (-100. * s).round() as i32;
358 }
359 top += height as i32;
360 }
361 (width, height, left, top)
362 } else {
363 (
364 data.width as u32,
365 data.height as u32,
366 data.metrics.x as i32,
367 data.metrics.y as i32,
368 )
369 };
370 Some(Bitmap {
371 format,
372 ppem: data.ppem,
373 width,
374 height,
375 left,
376 top,
377 data: data.data,
378 })
379 }
380
381 pub fn decoded_size(&self) -> usize {
383 self.format.buffer_size(self.width, self.height)
384 }
385
386 pub fn scaled_size(&self, size: f32) -> (u32, u32, usize) {
388 let mut w = self.width;
389 let mut h = self.height;
390 if size != 0. {
391 let scale = size / self.ppem as f32;
392 w = (w as f32 * scale) as u32;
393 h = (h as f32 * scale) as u32;
394 }
395 (w, h, self.format.buffer_size(w, h))
396 }
397
398 pub fn decode(&self, scratch: Option<&mut Vec<u8>>, target: &mut [u8]) -> bool {
400 let mut tmp = Vec::new();
401 let scratch = if let Some(scratch) = scratch {
402 scratch
403 } else {
404 &mut tmp
405 };
406 let size = self.decoded_size();
407 if target.len() < size {
408 return false;
409 }
410 let w = self.width as usize;
411 let h = self.height as usize;
412 let src = self.data;
413 let dst = &mut *target;
414 match self.format {
415 BitmapFormat::Packed(bits) => match bits {
416 1 => {
417 for x in 0..(w * h) {
418 dst[x] = (src[x >> 3] >> (!x & 7) & 1) * 255;
419 }
420 }
421 2 => {
422 for x in 0..(w * h) {
423 dst[x] = (src[x >> 2] >> (!(x * 2) & 2) & 3) * 85;
424 }
425 }
426 4 => {
427 for x in 0..(w * h) {
428 dst[x] = (src[x >> 1] >> (!(x * 4) & 4) & 15) * 17;
429 }
430 }
431 8 | 32 => {
432 dst.copy_from_slice(src);
433 }
434 _ => return false,
435 },
436 BitmapFormat::Alpha(bits) => match bits {
437 1 => {
438 let mut dst_idx = 0;
439 for row in src.chunks(((w * bits as usize) + 7) / 8) {
440 for x in 0..w {
441 dst[dst_idx] = (row[x >> 3] >> (!x & 7) & 1) * 255;
442 dst_idx += 1;
443 }
444 }
445 }
446 2 => {
447 let mut dst_idx = 0;
448 for row in src.chunks(((w * bits as usize) + 7) / 8) {
449 for x in 0..w {
450 dst[dst_idx] = (row[x >> 2] >> (!(x * 2) & 2) & 3) * 85;
451 dst_idx += 1;
452 }
453 }
454 }
455 4 => {
456 let mut dst_idx = 0;
457 for row in src.chunks(((w * bits as usize) + 7) / 8) {
458 for x in 0..w {
459 dst[dst_idx] = (row[x >> 1] >> (!(x * 4) & 4) & 15) * 17;
460 dst_idx += 1;
461 }
462 }
463 }
464 8 | 32 => {
465 dst.copy_from_slice(src);
466 }
467 _ => return false,
468 },
469
470 BitmapFormat::Color => {
471 dst.copy_from_slice(src);
472 }
473 BitmapFormat::Png => {
474 use super::scale::decode_png;
475 scratch.clear();
476 if decode_png(src, scratch, target).is_none() {
477 return false;
478 }
479 }
480 }
481 true
482 }
483}
484
485#[cfg(feature = "scale")]
487#[derive(Copy, Clone)]
488struct Location {
489 format: u8,
490 flags: u8,
491 offset: u32,
492 size: u32,
493 ppem: u16,
494 bit_depth: u8,
495 width: u8,
496 height: u8,
497 metrics: Metrics,
498 vertical_metrics: Metrics,
499}
500
501#[cfg(feature = "scale")]
502impl Location {
503 pub fn get<'a>(&self, data: &'a [u8], upem: u16, is_apple: bool) -> Option<Bitmap<'a>> {
505 Bitmap::new(&get_data(data, self)?, upem, is_apple)
506 }
507}
508
509fn get_coverage(table: &[u8], strike_base: usize, is_sbix: bool, glyph_id: u16) -> Option<bool> {
510 if is_sbix {
511 return Some(sbix_range(table, strike_base, glyph_id, 0).is_some());
512 }
513 let b = Bytes::with_offset(table, strike_base)?;
514 if glyph_id < b.read(40)? || glyph_id > b.read(42)? {
515 return None;
516 }
517 let count = b.read::<u32>(8)? as usize;
518 let array_offset = b.read::<u32>(0)? as usize;
519 let b = Bytes::with_offset(table, array_offset)?;
520 for i in 0..count {
521 let offset = i * 8;
522 let first = b.read::<u16>(offset)?;
523 if glyph_id < first {
524 return None;
525 }
526 if glyph_id > b.read::<u16>(offset + 2)? {
527 continue;
528 }
529 return Some(true);
530 }
531 None
532}
533
534#[cfg(feature = "scale")]
535fn get_location(
536 table: &[u8],
537 strike_base: usize,
538 is_sbix: bool,
539 glyph_id: u16,
540) -> Option<Location> {
541 let d = Bytes::new(table);
542 if is_sbix {
543 let (start, end) = sbix_range(table, strike_base, glyph_id, 0)?;
544 let len = (end - start) as usize;
545 let start = start as usize;
546 let x = d.read::<i16>(start)?;
547 let y = d.read::<i16>(start + 2)?;
548 let ppem = d.read::<u16>(strike_base)?;
549 return Some(Location {
550 ppem,
551 bit_depth: 32,
552 width: 0,
553 height: 0,
554 metrics: Metrics {
555 x: x as i8,
556 y: y as i8,
557 advance: 0,
558 },
559 vertical_metrics: Metrics::default(),
560 format: 0xFF,
561 flags: 1,
562 offset: start as u32 + 8,
563 size: len as u32 - 8,
564 });
565 }
566 if glyph_id < d.read(strike_base + 40)? || glyph_id > d.read(strike_base + 42)? {
567 return None;
568 }
569 let count = d.read::<u32>(strike_base + 8)? as usize;
570 let ppem = d.read::<u8>(strike_base + 45)? as u16;
571 let bit_depth = d.read::<u8>(strike_base + 46)?;
572 let flags = d.read::<u8>(strike_base + 47)?;
573 let array_offset = d.read::<u32>(strike_base)? as usize;
574 for i in 0..count {
575 let offset = array_offset + i * 8;
576 let first = d.read::<u16>(offset)?;
577 if glyph_id < first {
578 return None;
579 }
580 if glyph_id > d.read::<u16>(offset + 2)? {
581 continue;
582 }
583 let offset = array_offset + d.read::<u32>(offset + 4)? as usize;
584 let index_format = d.read::<u16>(offset)?;
585 let image_format = d.read::<u16>(offset + 2)? as u8;
586 let image_offset = d.read::<u32>(offset + 4)?;
587 let base = offset + 8;
588 let mut loc = Location {
589 ppem,
590 bit_depth,
591 width: 0,
592 height: 0,
593 metrics: Metrics::default(),
594 vertical_metrics: Metrics::default(),
595 format: image_format,
596 flags,
597 offset: 0,
598 size: 0,
599 };
600 match index_format {
601 1 => {
602 loc.offset =
603 image_offset + d.read::<u32>(base + (glyph_id - first) as usize * 4)?;
604 return Some(loc);
605 }
606 2 => {
607 loc.size = d.read::<u32>(base)?;
608 loc.offset = image_offset + loc.size * (glyph_id - first) as u32;
609 let (w, h) = get_metrics(
610 &d,
611 base + 4,
612 flags,
613 true,
614 &mut loc.metrics,
615 &mut loc.vertical_metrics,
616 )?;
617 loc.width = w;
618 loc.height = h;
619 return Some(loc);
620 }
621 3 => {
622 loc.offset =
623 image_offset + d.read::<u16>(base + (glyph_id - first) as usize * 2)? as u32;
624 return Some(loc);
625 }
626 4 => {
627 let mut l = 0;
628 let mut h = d.read::<u32>(base)? as usize;
629 while l < h {
630 use core::cmp::Ordering::*;
631 let i = (l + h) / 2;
632 let rec = base + i * 4;
633 let id = d.read::<u16>(rec)?;
634 match glyph_id.cmp(&id) {
635 Less => h = i,
636 Greater => l = i + i,
637 Equal => {
638 let offset1 = d.read::<u16>(rec + 2)? as u32;
639 let offset2 = d.read::<u16>(rec + 6)? as u32;
640 if offset2 <= offset1 {
641 return None;
642 }
643 loc.offset = image_offset + offset1;
644 loc.size = offset2 - offset1;
645 return Some(loc);
646 }
647 }
648 }
649 }
650 _ => {
651 return None;
652 }
653 }
654 }
655 None
656}
657
658#[cfg(feature = "scale")]
659fn get_data<'a>(table: &'a [u8], loc: &Location) -> Option<BitmapData<'a>> {
660 let depth = loc.bit_depth as usize;
661 let mut bitmap = BitmapData {
662 data: &[],
663 ppem: loc.ppem,
664 bit_depth: loc.bit_depth,
665 width: loc.width,
666 height: loc.height,
667 metrics: loc.metrics,
668 vertical_metrics: loc.vertical_metrics,
669 is_packed: false,
670 is_png: false,
671 is_sbix: false,
672 };
673 let d = &Bytes::new(table);
674 let offset = loc.offset as usize;
675 let flags = loc.flags;
676 let size = loc.size as usize;
677 match loc.format {
678 0xFF => {
679 bitmap.data = d.read_bytes(offset, size)?;
680 bitmap.is_png = true;
681 bitmap.is_sbix = true;
682 Some(bitmap)
683 }
684 1 => {
685 bitmap.read_metrics(d, offset, flags, false)?;
686 let w = (bitmap.width as usize * depth + 7) / 8;
687 let h = bitmap.height as usize;
688 bitmap.data = d.read_bytes(offset + 5, w * h)?;
689 Some(bitmap)
690 }
691 2 => {
692 bitmap.read_metrics(d, offset, flags, false)?;
693 let w = bitmap.width as usize * depth;
694 let h = bitmap.height as usize;
695 bitmap.data = d.read_bytes(offset + 5, (w * h + 7) / 8)?;
696 bitmap.is_packed = true;
697 Some(bitmap)
698 }
699 5 => {
700 bitmap.data = d.read_bytes(offset, size)?;
701 bitmap.is_packed = true;
702 Some(bitmap)
703 }
704 6 => {
705 bitmap.read_metrics(d, offset, flags, true)?;
706 let w = (bitmap.width as usize * depth + 7) / 8;
707 let h = bitmap.height as usize;
708 bitmap.data = d.read_bytes(offset + 8, w * h)?;
709 Some(bitmap)
710 }
711 7 => {
712 bitmap.read_metrics(d, offset, flags, true)?;
713 let w = bitmap.width as usize * depth;
714 let h = bitmap.height as usize;
715 bitmap.data = d.read_bytes(offset + 8, (w * h + 7) / 8)?;
716 bitmap.is_packed = true;
717 Some(bitmap)
718 }
719 17 => {
720 bitmap.read_metrics(d, offset, flags, false)?;
721 let size = d.read::<u32>(offset + 5)? as usize;
722 bitmap.data = d.read_bytes(offset + 9, size)?;
723 bitmap.is_png = true;
724 Some(bitmap)
725 }
726 18 => {
727 bitmap.read_metrics(d, offset, flags, true)?;
728 let size = d.read::<u32>(offset + 8)? as usize;
729 bitmap.data = d.read_bytes(offset + 12, size)?;
730 bitmap.is_png = true;
731 Some(bitmap)
732 }
733 19 => {
734 let size = d.read::<u32>(offset)? as usize;
735 bitmap.data = d.read_bytes(offset + 4, size)?;
736 bitmap.is_png = true;
737 Some(bitmap)
738 }
739 _ => None,
740 }
741}
742
743fn sbix_range(table: &[u8], strike_base: usize, glyph_id: u16, recurse: i32) -> Option<(u32, u32)> {
744 const DUPE: RawTag = raw_tag(b"dupe");
745 const PNG: RawTag = raw_tag(b"png ");
746 if recurse > 1 {
747 return None;
748 }
749 let b = Bytes::new(table);
750 let id = glyph_id as usize;
751 let base = strike_base + 4;
752 let mut start = b.read::<u32>(base + id * 4)?;
753 let mut end = b.read::<u32>(base + (id + 1) * 4)?;
754 if end <= start {
755 return None;
756 }
757 start += strike_base as u32;
758 end += strike_base as u32;
759 let tag = b.read::<u32>(start as usize + 4)?;
760 if tag == DUPE {
761 let dupe = b.read::<u16>(start as usize + 8)?;
762 sbix_range(table, strike_base, dupe, recurse + 1)
763 } else if tag == PNG {
764 Some((start, end))
765 } else {
766 None
767 }
768}
769
770#[cfg(feature = "scale")]
771#[derive(Copy, Clone)]
772struct BitmapData<'a> {
773 pub data: &'a [u8],
774 pub ppem: u16,
775 pub bit_depth: u8,
776 pub width: u8,
777 pub height: u8,
778 pub metrics: Metrics,
779 pub vertical_metrics: Metrics,
780 pub is_packed: bool,
781 pub is_png: bool,
782 pub is_sbix: bool,
783}
784
785#[cfg(feature = "scale")]
786impl<'a> BitmapData<'a> {
787 fn read_metrics(&mut self, d: &Bytes, offset: usize, flags: u8, big: bool) -> Option<()> {
788 let (w, h) = get_metrics(
789 d,
790 offset,
791 flags,
792 big,
793 &mut self.metrics,
794 &mut self.vertical_metrics,
795 )?;
796 self.width = w;
797 self.height = h;
798 Some(())
799 }
800}
801
802#[cfg(feature = "scale")]
803#[derive(Copy, Clone, Default)]
804struct Metrics {
805 pub x: i8,
806 pub y: i8,
807 pub advance: u8,
808}
809
810#[cfg(feature = "scale")]
811fn get_metrics(
812 d: &Bytes,
813 offset: usize,
814 flags: u8,
815 big: bool,
816 h: &mut Metrics,
817 v: &mut Metrics,
818) -> Option<(u8, u8)> {
819 let width = d.read::<u8>(offset + 1)?;
820 let height = d.read::<u8>(offset)?;
821 if big {
822 h.x = d.read::<i8>(offset + 2)?;
823 h.y = d.read::<i8>(offset + 3)?;
824 h.advance = d.read::<u8>(offset + 4)?;
825 v.x = d.read::<i8>(offset + 5)?;
826 v.y = d.read::<i8>(offset + 6)?;
827 v.advance = d.read::<u8>(offset + 7)?;
828 } else {
829 let m = if flags & 2 != 0 { v } else { h };
830 m.x = d.read::<i8>(offset + 2)?;
831 m.y = d.read::<i8>(offset + 3)?;
832 m.advance = d.read::<u8>(offset + 4)?;
833 }
834 Some((width, height))
835}