1use alloc::vec::Vec;
4
5use super::{instance::Size, metrics::GlyphMetrics, MetadataProvider};
6use crate::prelude::LocationRef;
7use raw::{
8 tables::{bitmap, cbdt, cblc, ebdt, eblc, sbix},
9 types::{GlyphId, Tag},
10 FontData, FontRef, TableProvider,
11};
12
13#[derive(Clone)]
15pub struct BitmapStrikes<'a>(StrikesKind<'a>);
16
17impl<'a> BitmapStrikes<'a> {
18 pub fn new(font: &FontRef<'a>) -> Self {
24 for format in [BitmapFormat::Sbix, BitmapFormat::Cbdt, BitmapFormat::Ebdt] {
25 if let Some(strikes) = Self::with_format(font, format) {
26 return strikes;
27 }
28 }
29 Self(StrikesKind::None)
30 }
31
32 pub fn with_format(font: &FontRef<'a>, format: BitmapFormat) -> Option<Self> {
36 let kind = match format {
37 BitmapFormat::Sbix => StrikesKind::Sbix(
38 font.sbix().ok()?,
39 font.glyph_metrics(Size::unscaled(), LocationRef::default()),
40 ),
41 BitmapFormat::Cbdt => {
42 StrikesKind::Cbdt(CbdtTables::new(font.cblc().ok()?, font.cbdt().ok()?))
43 }
44 BitmapFormat::Ebdt => {
45 StrikesKind::Ebdt(EbdtTables::new(font.eblc().ok()?, font.ebdt().ok()?))
46 }
47 };
48 Some(Self(kind))
49 }
50
51 pub fn format(&self) -> Option<BitmapFormat> {
54 match &self.0 {
55 StrikesKind::None => None,
56 StrikesKind::Sbix(..) => Some(BitmapFormat::Sbix),
57 StrikesKind::Cbdt(..) => Some(BitmapFormat::Cbdt),
58 StrikesKind::Ebdt(..) => Some(BitmapFormat::Ebdt),
59 }
60 }
61
62 pub fn len(&self) -> usize {
64 match &self.0 {
65 StrikesKind::None => 0,
66 StrikesKind::Sbix(sbix, _) => sbix.strikes().len(),
67 StrikesKind::Cbdt(cbdt) => cbdt.location.bitmap_sizes().len(),
68 StrikesKind::Ebdt(ebdt) => ebdt.location.bitmap_sizes().len(),
69 }
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.len() == 0
75 }
76
77 pub fn get(&self, index: usize) -> Option<BitmapStrike<'a>> {
79 let kind = match &self.0 {
80 StrikesKind::None => return None,
81 StrikesKind::Sbix(sbix, metrics) => {
82 StrikeKind::Sbix(sbix.strikes().get(index).ok()?, metrics.clone())
83 }
84 StrikesKind::Cbdt(tables) => StrikeKind::Cbdt(
85 tables.location.bitmap_sizes().get(index).copied()?,
86 tables.clone(),
87 ),
88 StrikesKind::Ebdt(tables) => StrikeKind::Ebdt(
89 tables.location.bitmap_sizes().get(index).copied()?,
90 tables.clone(),
91 ),
92 };
93 Some(BitmapStrike(kind))
94 }
95
96 pub fn glyph_for_size(&self, size: Size, glyph_id: GlyphId) -> Option<BitmapGlyph<'a>> {
102 let size = size.ppem().unwrap_or(f32::MAX);
104 self.iter()
105 .fold(None, |best: Option<BitmapGlyph<'a>>, entry| {
106 let entry_size = entry.ppem();
107 if let Some(best) = best {
108 let best_size = best.ppem_y;
109 if (entry_size >= size && entry_size < best_size)
110 || (best_size < size && entry_size > best_size)
111 {
112 entry.get(glyph_id).or(Some(best))
113 } else {
114 Some(best)
115 }
116 } else {
117 entry.get(glyph_id)
118 }
119 })
120 }
121
122 pub fn iter(&self) -> impl Iterator<Item = BitmapStrike<'a>> + 'a + Clone {
124 let this = self.clone();
125 (0..this.len()).filter_map(move |ix| this.get(ix))
126 }
127}
128
129#[derive(Clone)]
130enum StrikesKind<'a> {
131 None,
132 Sbix(sbix::Sbix<'a>, GlyphMetrics<'a>),
133 Cbdt(CbdtTables<'a>),
134 Ebdt(EbdtTables<'a>),
135}
136
137#[derive(Clone)]
139pub struct BitmapStrike<'a>(StrikeKind<'a>);
140
141impl<'a> BitmapStrike<'a> {
142 pub fn ppem(&self) -> f32 {
144 match &self.0 {
145 StrikeKind::Sbix(sbix, _) => sbix.ppem() as f32,
146 StrikeKind::Cbdt(size, _) => size.ppem_y() as f32,
149 StrikeKind::Ebdt(size, _) => size.ppem_y() as f32,
150 }
151 }
152
153 pub fn get(&self, glyph_id: GlyphId) -> Option<BitmapGlyph<'a>> {
155 match &self.0 {
156 StrikeKind::Sbix(sbix, metrics) => {
157 let glyph = sbix.glyph_data(glyph_id).ok()??;
158 if glyph.graphic_type() != Tag::new(b"png ") {
159 return None;
160 }
161
162 let glyf_bb = metrics.bounds(glyph_id).unwrap_or_default();
166 let lsb = metrics.left_side_bearing(glyph_id).unwrap_or_default();
167 let ppem = sbix.ppem() as f32;
168 let png_data = glyph.data();
169 let reader = FontData::new(png_data);
172 let width = reader.read_at::<u32>(16).ok()?;
173 let height = reader.read_at::<u32>(20).ok()?;
174 Some(BitmapGlyph {
175 data: BitmapData::Png(glyph.data()),
176 bearing_x: lsb,
177 bearing_y: glyf_bb.y_min,
178 inner_bearing_x: glyph.origin_offset_x() as f32,
179 inner_bearing_y: glyph.origin_offset_y() as f32,
180 ppem_x: ppem,
181 ppem_y: ppem,
182 width,
183 height,
184 advance: None,
185 placement_origin: Origin::BottomLeft,
186 })
187 }
188 StrikeKind::Cbdt(size, tables) => {
189 let location = size
190 .location(tables.location.offset_data(), glyph_id)
191 .ok()?;
192 let data = tables.data.data(&location).ok()?;
193 BitmapGlyph::from_bdt(size, &data)
194 }
195 StrikeKind::Ebdt(size, tables) => {
196 let location = size
197 .location(tables.location.offset_data(), glyph_id)
198 .ok()?;
199 let data = tables.data.data(&location).ok()?;
200 BitmapGlyph::from_bdt(size, &data)
201 }
202 }
203 }
204}
205
206#[derive(Clone)]
207enum StrikeKind<'a> {
208 Sbix(sbix::Strike<'a>, GlyphMetrics<'a>),
209 Cbdt(bitmap::BitmapSize, CbdtTables<'a>),
210 Ebdt(bitmap::BitmapSize, EbdtTables<'a>),
211}
212
213#[derive(Clone)]
214struct BdtTables<L, D> {
215 location: L,
216 data: D,
217}
218
219impl<L, D> BdtTables<L, D> {
220 fn new(location: L, data: D) -> Self {
221 Self { location, data }
222 }
223}
224
225type CbdtTables<'a> = BdtTables<cblc::Cblc<'a>, cbdt::Cbdt<'a>>;
226type EbdtTables<'a> = BdtTables<eblc::Eblc<'a>, ebdt::Ebdt<'a>>;
227
228#[derive(Clone)]
230pub struct BitmapGlyph<'a> {
231 pub data: BitmapData<'a>,
233 pub bearing_x: f32,
235 pub bearing_y: f32,
237 pub inner_bearing_x: f32,
240 pub inner_bearing_y: f32,
243 pub ppem_x: f32,
245 pub ppem_y: f32,
247 pub advance: Option<f32>,
249 pub width: u32,
251 pub height: u32,
253 pub placement_origin: Origin,
255}
256
257impl<'a> BitmapGlyph<'a> {
258 fn from_bdt(
259 bitmap_size: &bitmap::BitmapSize,
260 bitmap_data: &bitmap::BitmapData<'a>,
261 ) -> Option<Self> {
262 let metrics = BdtMetrics::new(bitmap_data);
263 let (ppem_x, ppem_y) = (bitmap_size.ppem_x() as f32, bitmap_size.ppem_y() as f32);
264 let bpp = bitmap_size.bit_depth();
265 let data = match bpp {
266 32 => {
267 match &bitmap_data.content {
268 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::Png, bytes) => {
269 BitmapData::Png(bytes)
270 }
271 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
273 BitmapData::Bgra(bytes)
274 }
275 _ => return None,
276 }
277 }
278 1 | 2 | 4 | 8 => {
279 let (data, is_packed) = match &bitmap_data.content {
280 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
281 (bytes, false)
282 }
283 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::BitAligned, bytes) => {
284 (bytes, true)
285 }
286 _ => return None,
287 };
288 BitmapData::Mask(MaskData {
289 bpp,
290 is_packed,
291 data,
292 })
293 }
294 _ => return None,
296 };
297 Some(Self {
298 data,
299 bearing_x: 0.0,
300 bearing_y: 0.0,
301 inner_bearing_x: metrics.inner_bearing_x,
302 inner_bearing_y: metrics.inner_bearing_y,
303 ppem_x,
304 ppem_y,
305 width: metrics.width,
306 height: metrics.height,
307 advance: Some(metrics.advance),
308 placement_origin: Origin::TopLeft,
309 })
310 }
311}
312
313struct BdtMetrics {
314 inner_bearing_x: f32,
315 inner_bearing_y: f32,
316 advance: f32,
317 width: u32,
318 height: u32,
319}
320
321impl BdtMetrics {
322 fn new(data: &bitmap::BitmapData) -> Self {
323 match data.metrics {
324 bitmap::BitmapMetrics::Small(metrics) => Self {
325 inner_bearing_x: metrics.bearing_x() as f32,
326 inner_bearing_y: metrics.bearing_y() as f32,
327 advance: metrics.advance() as f32,
328 width: metrics.width() as u32,
329 height: metrics.height() as u32,
330 },
331 bitmap::BitmapMetrics::Big(metrics) => Self {
332 inner_bearing_x: metrics.hori_bearing_x() as f32,
333 inner_bearing_y: metrics.hori_bearing_y() as f32,
334 advance: metrics.hori_advance() as f32,
335 width: metrics.width() as u32,
336 height: metrics.height() as u32,
337 },
338 }
339 }
340}
341
342#[derive(Copy, Clone, PartialEq, Eq, Debug)]
344pub enum Origin {
345 TopLeft,
347 BottomLeft,
349}
350
351#[derive(Clone)]
353pub enum BitmapData<'a> {
354 Bgra(&'a [u8]),
357 Png(&'a [u8]),
359 Mask(MaskData<'a>),
361}
362
363#[derive(Clone)]
365pub struct MaskData<'a> {
366 pub bpp: u8,
368 pub is_packed: bool,
371 pub data: &'a [u8],
373}
374
375#[derive(Copy, Clone, PartialEq, Eq, Debug)]
377pub enum MaskDataDecodeError {
378 SizeOverflow,
380 InvalidDimensions,
382}
383
384impl MaskData<'_> {
385 pub fn decode_to_slice(
391 &self,
392 width: u32,
393 height: u32,
394 dst: &mut [u8],
395 ) -> Result<(), MaskDataDecodeError> {
396 let w = width as usize;
397 let h = height as usize;
398 let total_pixels = w.checked_mul(h).ok_or(MaskDataDecodeError::SizeOverflow)?;
399 if total_pixels == 0 {
400 return Ok(());
401 }
402 let bits = self.bpp as usize;
403 if dst.len() < total_pixels {
404 return Err(MaskDataDecodeError::InvalidDimensions);
405 }
406 let dst = &mut dst[..total_pixels];
407 if !self.is_packed {
408 let row_bytes = (w * bits).div_ceil(8);
410 let expected_data_len = row_bytes
411 .checked_mul(h)
412 .ok_or(MaskDataDecodeError::SizeOverflow)?;
413 if self.data.len() < expected_data_len {
414 return Err(MaskDataDecodeError::InvalidDimensions);
415 }
416 let mut dst_idx = 0;
417 match self.bpp {
418 1 => {
419 for row in self.data.chunks(row_bytes) {
420 for x in 0..w {
421 dst[dst_idx] = ((row[x >> 3] >> (!x & 7)) & 1) * 255;
422 dst_idx += 1;
423 }
424 }
425 }
426 2 => {
427 for row in self.data.chunks(row_bytes) {
428 for x in 0..w {
429 dst[dst_idx] = ((row[x >> 2] >> (!(x * 2) & 6)) & 3) * 85;
430 dst_idx += 1;
431 }
432 }
433 }
434 4 => {
435 for row in self.data.chunks(row_bytes) {
436 for x in 0..w {
437 dst[dst_idx] = ((row[x >> 1] >> (!(x * 4) & 4)) & 15) * 17;
438 dst_idx += 1;
439 }
440 }
441 }
442 8 => {
443 for row in self.data.chunks(row_bytes) {
444 dst[dst_idx..dst_idx + w].copy_from_slice(&row[..w]);
445 dst_idx += w;
446 }
447 }
448 _ => return Err(MaskDataDecodeError::InvalidDimensions),
449 }
450 } else {
451 let total_bits = total_pixels
453 .checked_mul(bits)
454 .ok_or(MaskDataDecodeError::SizeOverflow)?;
455 let expected_data_len = total_bits.div_ceil(8);
456 if self.data.len() < expected_data_len {
457 return Err(MaskDataDecodeError::InvalidDimensions);
458 }
459 match self.bpp {
460 1 => {
461 for (x, pixel) in dst.iter_mut().enumerate() {
462 *pixel = ((self.data[x >> 3] >> (!x & 7)) & 1) * 255;
463 }
464 }
465 2 => {
466 for (x, pixel) in dst.iter_mut().enumerate() {
467 *pixel = ((self.data[x >> 2] >> (!(x * 2) & 6)) & 3) * 85;
468 }
469 }
470 4 => {
471 for (x, pixel) in dst.iter_mut().enumerate() {
472 *pixel = ((self.data[x >> 1] >> (!(x * 4) & 4)) & 15) * 17;
473 }
474 }
475 8 => {
476 dst.copy_from_slice(&self.data[..total_pixels]);
477 }
478 _ => return Err(MaskDataDecodeError::InvalidDimensions),
479 }
480 }
481 Ok(())
482 }
483
484 pub fn decode(&self, width: u32, height: u32) -> Result<Vec<u8>, MaskDataDecodeError> {
489 let w = width as usize;
490 let h = height as usize;
491 let total_pixels = w.checked_mul(h).ok_or(MaskDataDecodeError::SizeOverflow)?;
492 let mut dst = vec![0u8; total_pixels];
493 self.decode_to_slice(width, height, &mut dst)?;
494 Ok(dst)
495 }
496}
497
498#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
500pub enum BitmapFormat {
501 Sbix,
502 Cbdt,
503 Ebdt,
504}
505
506#[cfg(test)]
507mod tests {
508 use crate::bitmap::{BitmapData, MaskData, MaskDataDecodeError, StrikesKind};
509 use crate::prelude::Size;
510 use crate::{GlyphId, MetadataProvider};
511 use raw::FontRef;
512
513 #[test]
514 fn cbdt_metadata() {
515 let font = FontRef::new(font_test_data::CBDT).unwrap();
516 let strikes = font.bitmap_strikes();
517
518 assert!(matches!(strikes.0, StrikesKind::Cbdt(_)));
519 assert!(matches!(strikes.len(), 3));
520
521 assert!(matches!(strikes.get(0).unwrap().ppem(), 16.0));
523 assert!(matches!(strikes.get(1).unwrap().ppem(), 64.0));
524 assert!(matches!(strikes.get(2).unwrap().ppem(), 128.0));
525 }
526
527 #[test]
528 fn cbdt_glyph_metrics() {
529 let font = FontRef::new(font_test_data::CBDT).unwrap();
530 let strike_0 = font.bitmap_strikes().get(0).unwrap();
531
532 let zero = strike_0.get(GlyphId::new(0)).unwrap();
533 assert_eq!(zero.width, 11);
534 assert_eq!(zero.height, 13);
535 assert_eq!(zero.bearing_x, 0.0);
536 assert_eq!(zero.bearing_y, 0.0);
537 assert_eq!(zero.inner_bearing_x, 1.0);
538 assert_eq!(zero.inner_bearing_y, 13.0);
539 assert_eq!(zero.advance, Some(12.0));
540
541 let strike_1 = font.bitmap_strikes().get(1).unwrap();
542
543 let zero = strike_1.get(GlyphId::new(2)).unwrap();
544 assert_eq!(zero.width, 39);
545 assert_eq!(zero.height, 52);
546 assert_eq!(zero.bearing_x, 0.0);
547 assert_eq!(zero.bearing_y, 0.0);
548 assert_eq!(zero.inner_bearing_x, 6.0);
549 assert_eq!(zero.inner_bearing_y, 52.0);
550 assert_eq!(zero.advance, Some(51.0));
551 }
552
553 #[test]
554 fn cbdt_glyph_selection() {
555 let font = FontRef::new(font_test_data::CBDT).unwrap();
556 let strikes = font.bitmap_strikes();
557
558 let g1 = strikes
559 .glyph_for_size(Size::new(12.0), GlyphId::new(2))
560 .unwrap();
561 assert_eq!(g1.ppem_x, 16.0);
562
563 let g2 = strikes
564 .glyph_for_size(Size::new(17.0), GlyphId::new(2))
565 .unwrap();
566 assert_eq!(g2.ppem_x, 64.0);
567
568 let g3 = strikes
569 .glyph_for_size(Size::new(60.0), GlyphId::new(2))
570 .unwrap();
571 assert_eq!(g3.ppem_x, 64.0);
572
573 let g4 = strikes
574 .glyph_for_size(Size::unscaled(), GlyphId::new(2))
575 .unwrap();
576 assert_eq!(g4.ppem_x, 128.0);
577 }
578
579 #[test]
580 fn sbix_metadata() {
581 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
582 let strikes = font.bitmap_strikes();
583
584 assert!(matches!(strikes.0, StrikesKind::Sbix(_, _)));
585 assert!(matches!(strikes.len(), 1));
586
587 assert!(matches!(strikes.get(0).unwrap().ppem(), 109.0));
588 }
589
590 #[test]
591 fn sbix_glyph_metrics() {
592 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
593 let strike_0 = font.bitmap_strikes().get(0).unwrap();
594
595 let g0 = strike_0.get(GlyphId::new(7)).unwrap();
596 assert_eq!(g0.bearing_x, 0.0);
598 assert_eq!(g0.bearing_y, 0.0);
602 assert_eq!(g0.inner_bearing_x, 4.0);
604 assert_eq!(g0.inner_bearing_y, -27.0);
605 assert!(matches!(g0.data, BitmapData::Png(_)))
606 }
607
608 #[test]
609 fn decode_1bpp_non_packed() {
610 let mask = MaskData {
614 bpp: 1,
615 is_packed: false,
616 data: &[0xA0, 0x50],
617 };
618 let decoded = mask.decode(4, 2).unwrap();
619 assert_eq!(decoded, [255, 0, 255, 0, 0, 255, 0, 255],);
620 }
621
622 #[test]
623 fn decode_2bpp_non_packed() {
624 let mask = MaskData {
628 bpp: 2,
629 is_packed: false,
630 data: &[0xE4],
631 };
632 let decoded = mask.decode(4, 1).unwrap();
633 assert_eq!(decoded, [255, 170, 85, 0]);
634 }
635
636 #[test]
637 fn decode_4bpp_non_packed() {
638 let mask = MaskData {
648 bpp: 4,
649 is_packed: false,
650 data: &[0xF8, 0x40, 0x05, 0xA0],
651 };
652 let decoded = mask.decode(3, 2).unwrap();
653 assert_eq!(decoded, [255, 136, 68, 0, 85, 170]);
654 }
655
656 #[test]
657 fn decode_8bpp_non_packed() {
658 let mask = MaskData {
660 bpp: 8,
661 is_packed: false,
662 data: &[10, 20, 30, 40, 50, 60],
663 };
664 let decoded = mask.decode(3, 2).unwrap();
665 assert_eq!(decoded, [10, 20, 30, 40, 50, 60]);
666 }
667
668 #[test]
669 fn decode_1bpp_packed() {
670 let mask = MaskData {
677 bpp: 1,
678 is_packed: true,
679 data: &[0xAB, 0x00],
680 };
681 let decoded = mask.decode(3, 3).unwrap();
682 assert_eq!(decoded, [255, 0, 255, 0, 255, 0, 255, 255, 0],);
683 }
684
685 #[test]
686 fn decode_2bpp_packed() {
687 let mask = MaskData {
695 bpp: 2,
696 is_packed: true,
697 data: &[0xE4, 0xC6, 0xC0],
698 };
699 let decoded = mask.decode(5, 2).unwrap();
700 assert_eq!(decoded, [255, 170, 85, 0, 255, 0, 85, 170, 255, 0]);
701 }
702
703 #[test]
704 fn decode_4bpp_packed() {
705 let mask = MaskData {
713 bpp: 4,
714 is_packed: true,
715 data: &[0xF0, 0x84, 0xA5],
716 };
717 let decoded = mask.decode(3, 2).unwrap();
718 assert_eq!(decoded, [255, 0, 136, 68, 170, 85]);
719 }
720
721 #[test]
722 fn decode_8bpp_packed() {
723 let mask = MaskData {
726 bpp: 8,
727 is_packed: true,
728 data: &[100, 200, 50, 0, 128, 255],
729 };
730 let decoded = mask.decode(3, 2).unwrap();
731 assert_eq!(decoded, [100, 200, 50, 0, 128, 255]);
732 }
733
734 #[test]
735 fn decode_error_cases() {
736 let mask = MaskData {
738 bpp: 8,
739 is_packed: false,
740 data: &[],
741 };
742 assert!(mask.decode(0, 0).unwrap().is_empty());
743 assert!(mask.decode(0, 5).unwrap().is_empty());
744 assert!(mask.decode(5, 0).unwrap().is_empty());
745
746 let mask = MaskData {
748 bpp: 8,
749 is_packed: false,
750 data: &[1, 2, 3],
751 };
752 assert_eq!(
753 mask.decode(4, 2),
754 Err(MaskDataDecodeError::InvalidDimensions)
755 );
756
757 let mask = MaskData {
759 bpp: 1,
760 is_packed: true,
761 data: &[0xFF],
762 };
763 assert_eq!(
764 mask.decode(3, 3),
765 Err(MaskDataDecodeError::InvalidDimensions)
766 );
767 }
768
769 #[test]
770 fn decode_to_slice_basic_and_errors() {
771 let mask = MaskData {
772 bpp: 8,
773 is_packed: false,
774 data: &[10, 20, 30, 40, 50, 60],
775 };
776
777 let mut buf = [0u8; 6];
779 mask.decode_to_slice(3, 2, &mut buf).unwrap();
780 assert_eq!(buf, [10, 20, 30, 40, 50, 60]);
781
782 let mut small_buf = [0u8; 4];
784 assert_eq!(
785 mask.decode_to_slice(3, 2, &mut small_buf),
786 Err(MaskDataDecodeError::InvalidDimensions)
787 );
788
789 let empty = MaskData {
791 bpp: 8,
792 is_packed: false,
793 data: &[],
794 };
795 let mut empty_buf = [0u8; 0];
796 empty.decode_to_slice(0, 0, &mut empty_buf).unwrap();
797 }
798}