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 (lsb, y_min) = if let Some(y_min) = metrics.glyf_y_min(glyph_id) {
166 (
167 metrics.left_side_bearing(glyph_id).unwrap_or_default(),
168 y_min as f32,
169 )
170 } else {
171 (0.0, 0.0)
172 };
173 let ppem = sbix.ppem() as f32;
174 let png_data = glyph.data();
175 let reader = FontData::new(png_data);
178 let width = reader.read_at::<u32>(16).ok()?;
179 let height = reader.read_at::<u32>(20).ok()?;
180 Some(BitmapGlyph {
181 data: BitmapData::Png(glyph.data()),
182 bearing_x: lsb,
183 bearing_y: y_min,
184 inner_bearing_x: glyph.origin_offset_x() as f32,
185 inner_bearing_y: glyph.origin_offset_y() as f32,
186 ppem_x: ppem,
187 ppem_y: ppem,
188 width,
189 height,
190 advance: None,
191 placement_origin: Origin::BottomLeft,
192 })
193 }
194 StrikeKind::Cbdt(size, tables) => {
195 let location = size
196 .location(tables.location.offset_data(), glyph_id)
197 .ok()?;
198 let data = tables.data.data(&location).ok()?;
199 BitmapGlyph::from_bdt(size, &data)
200 }
201 StrikeKind::Ebdt(size, tables) => {
202 let location = size
203 .location(tables.location.offset_data(), glyph_id)
204 .ok()?;
205 let data = tables.data.data(&location).ok()?;
206 BitmapGlyph::from_bdt(size, &data)
207 }
208 }
209 }
210}
211
212#[derive(Clone)]
213enum StrikeKind<'a> {
214 Sbix(sbix::Strike<'a>, GlyphMetrics<'a>),
215 Cbdt(bitmap::BitmapSize, CbdtTables<'a>),
216 Ebdt(bitmap::BitmapSize, EbdtTables<'a>),
217}
218
219#[derive(Clone)]
220struct BdtTables<L, D> {
221 location: L,
222 data: D,
223}
224
225impl<L, D> BdtTables<L, D> {
226 fn new(location: L, data: D) -> Self {
227 Self { location, data }
228 }
229}
230
231type CbdtTables<'a> = BdtTables<cblc::Cblc<'a>, cbdt::Cbdt<'a>>;
232type EbdtTables<'a> = BdtTables<eblc::Eblc<'a>, ebdt::Ebdt<'a>>;
233
234#[derive(Clone)]
236pub struct BitmapGlyph<'a> {
237 pub data: BitmapData<'a>,
239 pub bearing_x: f32,
241 pub bearing_y: f32,
243 pub inner_bearing_x: f32,
246 pub inner_bearing_y: f32,
249 pub ppem_x: f32,
251 pub ppem_y: f32,
253 pub advance: Option<f32>,
255 pub width: u32,
257 pub height: u32,
259 pub placement_origin: Origin,
261}
262
263impl<'a> BitmapGlyph<'a> {
264 fn from_bdt(
265 bitmap_size: &bitmap::BitmapSize,
266 bitmap_data: &bitmap::BitmapData<'a>,
267 ) -> Option<Self> {
268 let metrics = BdtMetrics::new(bitmap_data);
269 let (ppem_x, ppem_y) = (bitmap_size.ppem_x() as f32, bitmap_size.ppem_y() as f32);
270 let bpp = bitmap_size.bit_depth();
271 let data = match bpp {
272 32 => {
273 match &bitmap_data.content {
274 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::Png, bytes) => {
275 BitmapData::Png(bytes)
276 }
277 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
279 BitmapData::Bgra(bytes)
280 }
281 _ => return None,
282 }
283 }
284 1 | 2 | 4 | 8 => {
285 let (data, is_packed) = match &bitmap_data.content {
286 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
287 (bytes, false)
288 }
289 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::BitAligned, bytes) => {
290 (bytes, true)
291 }
292 _ => return None,
293 };
294 BitmapData::Mask(MaskData {
295 bpp,
296 is_packed,
297 data,
298 })
299 }
300 _ => return None,
302 };
303 Some(Self {
304 data,
305 bearing_x: 0.0,
306 bearing_y: 0.0,
307 inner_bearing_x: metrics.inner_bearing_x,
308 inner_bearing_y: metrics.inner_bearing_y,
309 ppem_x,
310 ppem_y,
311 width: metrics.width,
312 height: metrics.height,
313 advance: Some(metrics.advance),
314 placement_origin: Origin::TopLeft,
315 })
316 }
317}
318
319struct BdtMetrics {
320 inner_bearing_x: f32,
321 inner_bearing_y: f32,
322 advance: f32,
323 width: u32,
324 height: u32,
325}
326
327impl BdtMetrics {
328 fn new(data: &bitmap::BitmapData) -> Self {
329 match data.metrics {
330 bitmap::BitmapMetrics::Small(metrics) => Self {
331 inner_bearing_x: metrics.bearing_x() as f32,
332 inner_bearing_y: metrics.bearing_y() as f32,
333 advance: metrics.advance() as f32,
334 width: metrics.width() as u32,
335 height: metrics.height() as u32,
336 },
337 bitmap::BitmapMetrics::Big(metrics) => Self {
338 inner_bearing_x: metrics.hori_bearing_x() as f32,
339 inner_bearing_y: metrics.hori_bearing_y() as f32,
340 advance: metrics.hori_advance() as f32,
341 width: metrics.width() as u32,
342 height: metrics.height() as u32,
343 },
344 }
345 }
346}
347
348#[derive(Copy, Clone, PartialEq, Eq, Debug)]
350pub enum Origin {
351 TopLeft,
353 BottomLeft,
355}
356
357#[derive(Clone)]
359pub enum BitmapData<'a> {
360 Bgra(&'a [u8]),
363 Png(&'a [u8]),
365 Mask(MaskData<'a>),
367}
368
369#[derive(Clone)]
371pub struct MaskData<'a> {
372 pub bpp: u8,
374 pub is_packed: bool,
377 pub data: &'a [u8],
379}
380
381#[derive(Copy, Clone, PartialEq, Eq, Debug)]
383pub enum MaskDataDecodeError {
384 SizeOverflow,
386 InvalidDimensions,
388}
389
390impl MaskData<'_> {
391 pub fn decode_to_slice(
397 &self,
398 width: u32,
399 height: u32,
400 dst: &mut [u8],
401 ) -> Result<(), MaskDataDecodeError> {
402 let w = width as usize;
403 let h = height as usize;
404 let total_pixels = w.checked_mul(h).ok_or(MaskDataDecodeError::SizeOverflow)?;
405 if total_pixels == 0 {
406 return Ok(());
407 }
408 let bits = self.bpp as usize;
409 if dst.len() < total_pixels {
410 return Err(MaskDataDecodeError::InvalidDimensions);
411 }
412 let dst = &mut dst[..total_pixels];
413 if !self.is_packed {
414 let row_bytes = (w * bits).div_ceil(8);
416 let expected_data_len = row_bytes
417 .checked_mul(h)
418 .ok_or(MaskDataDecodeError::SizeOverflow)?;
419 if self.data.len() < expected_data_len {
420 return Err(MaskDataDecodeError::InvalidDimensions);
421 }
422 let mut dst_idx = 0;
423 match self.bpp {
424 1 => {
425 for row in self.data.chunks(row_bytes) {
426 for x in 0..w {
427 dst[dst_idx] = ((row[x >> 3] >> (!x & 7)) & 1) * 255;
428 dst_idx += 1;
429 }
430 }
431 }
432 2 => {
433 for row in self.data.chunks(row_bytes) {
434 for x in 0..w {
435 dst[dst_idx] = ((row[x >> 2] >> (!(x * 2) & 6)) & 3) * 85;
436 dst_idx += 1;
437 }
438 }
439 }
440 4 => {
441 for row in self.data.chunks(row_bytes) {
442 for x in 0..w {
443 dst[dst_idx] = ((row[x >> 1] >> (!(x * 4) & 4)) & 15) * 17;
444 dst_idx += 1;
445 }
446 }
447 }
448 8 => {
449 for row in self.data.chunks(row_bytes) {
450 dst[dst_idx..dst_idx + w].copy_from_slice(&row[..w]);
451 dst_idx += w;
452 }
453 }
454 _ => return Err(MaskDataDecodeError::InvalidDimensions),
455 }
456 } else {
457 let total_bits = total_pixels
459 .checked_mul(bits)
460 .ok_or(MaskDataDecodeError::SizeOverflow)?;
461 let expected_data_len = total_bits.div_ceil(8);
462 if self.data.len() < expected_data_len {
463 return Err(MaskDataDecodeError::InvalidDimensions);
464 }
465 match self.bpp {
466 1 => {
467 for (x, pixel) in dst.iter_mut().enumerate() {
468 *pixel = ((self.data[x >> 3] >> (!x & 7)) & 1) * 255;
469 }
470 }
471 2 => {
472 for (x, pixel) in dst.iter_mut().enumerate() {
473 *pixel = ((self.data[x >> 2] >> (!(x * 2) & 6)) & 3) * 85;
474 }
475 }
476 4 => {
477 for (x, pixel) in dst.iter_mut().enumerate() {
478 *pixel = ((self.data[x >> 1] >> (!(x * 4) & 4)) & 15) * 17;
479 }
480 }
481 8 => {
482 dst.copy_from_slice(&self.data[..total_pixels]);
483 }
484 _ => return Err(MaskDataDecodeError::InvalidDimensions),
485 }
486 }
487 Ok(())
488 }
489
490 pub fn decode(&self, width: u32, height: u32) -> Result<Vec<u8>, MaskDataDecodeError> {
495 let w = width as usize;
496 let h = height as usize;
497 let total_pixels = w.checked_mul(h).ok_or(MaskDataDecodeError::SizeOverflow)?;
498 let mut dst = vec![0u8; total_pixels];
499 self.decode_to_slice(width, height, &mut dst)?;
500 Ok(dst)
501 }
502}
503
504#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
506pub enum BitmapFormat {
507 Sbix,
508 Cbdt,
509 Ebdt,
510}
511
512#[cfg(test)]
513mod tests {
514 use crate::bitmap::{BitmapData, MaskData, MaskDataDecodeError, StrikesKind};
515 use crate::prelude::Size;
516 use crate::{GlyphId, MetadataProvider};
517 use raw::FontRef;
518
519 #[test]
520 fn cbdt_metadata() {
521 let font = FontRef::new(font_test_data::CBDT).unwrap();
522 let strikes = font.bitmap_strikes();
523
524 assert!(matches!(strikes.0, StrikesKind::Cbdt(_)));
525 assert!(matches!(strikes.len(), 3));
526
527 assert!(matches!(strikes.get(0).unwrap().ppem(), 16.0));
529 assert!(matches!(strikes.get(1).unwrap().ppem(), 64.0));
530 assert!(matches!(strikes.get(2).unwrap().ppem(), 128.0));
531 }
532
533 #[test]
534 fn cbdt_glyph_metrics() {
535 let font = FontRef::new(font_test_data::CBDT).unwrap();
536 let strike_0 = font.bitmap_strikes().get(0).unwrap();
537
538 let zero = strike_0.get(GlyphId::new(0)).unwrap();
539 assert_eq!(zero.width, 11);
540 assert_eq!(zero.height, 13);
541 assert_eq!(zero.bearing_x, 0.0);
542 assert_eq!(zero.bearing_y, 0.0);
543 assert_eq!(zero.inner_bearing_x, 1.0);
544 assert_eq!(zero.inner_bearing_y, 13.0);
545 assert_eq!(zero.advance, Some(12.0));
546
547 let strike_1 = font.bitmap_strikes().get(1).unwrap();
548
549 let zero = strike_1.get(GlyphId::new(2)).unwrap();
550 assert_eq!(zero.width, 39);
551 assert_eq!(zero.height, 52);
552 assert_eq!(zero.bearing_x, 0.0);
553 assert_eq!(zero.bearing_y, 0.0);
554 assert_eq!(zero.inner_bearing_x, 6.0);
555 assert_eq!(zero.inner_bearing_y, 52.0);
556 assert_eq!(zero.advance, Some(51.0));
557 }
558
559 #[test]
560 fn cbdt_glyph_selection() {
561 let font = FontRef::new(font_test_data::CBDT).unwrap();
562 let strikes = font.bitmap_strikes();
563
564 let g1 = strikes
565 .glyph_for_size(Size::new(12.0), GlyphId::new(2))
566 .unwrap();
567 assert_eq!(g1.ppem_x, 16.0);
568
569 let g2 = strikes
570 .glyph_for_size(Size::new(17.0), GlyphId::new(2))
571 .unwrap();
572 assert_eq!(g2.ppem_x, 64.0);
573
574 let g3 = strikes
575 .glyph_for_size(Size::new(60.0), GlyphId::new(2))
576 .unwrap();
577 assert_eq!(g3.ppem_x, 64.0);
578
579 let g4 = strikes
580 .glyph_for_size(Size::unscaled(), GlyphId::new(2))
581 .unwrap();
582 assert_eq!(g4.ppem_x, 128.0);
583 }
584
585 #[test]
586 fn sbix_metadata() {
587 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
588 let strikes = font.bitmap_strikes();
589
590 assert!(matches!(strikes.0, StrikesKind::Sbix(_, _)));
591 assert!(matches!(strikes.len(), 1));
592
593 assert!(matches!(strikes.get(0).unwrap().ppem(), 109.0));
594 }
595
596 #[test]
597 fn sbix_glyph_metrics() {
598 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
599 let strike_0 = font.bitmap_strikes().get(0).unwrap();
600
601 let g0 = strike_0.get(GlyphId::new(7)).unwrap();
602 assert_eq!(g0.bearing_x, 0.0);
604 assert_eq!(g0.bearing_y, 0.0);
608 assert_eq!(g0.inner_bearing_x, 4.0);
610 assert_eq!(g0.inner_bearing_y, -27.0);
611 assert!(matches!(g0.data, BitmapData::Png(_)))
612 }
613
614 #[test]
615 fn decode_1bpp_non_packed() {
616 let mask = MaskData {
620 bpp: 1,
621 is_packed: false,
622 data: &[0xA0, 0x50],
623 };
624 let decoded = mask.decode(4, 2).unwrap();
625 assert_eq!(decoded, [255, 0, 255, 0, 0, 255, 0, 255],);
626 }
627
628 #[test]
629 fn decode_2bpp_non_packed() {
630 let mask = MaskData {
634 bpp: 2,
635 is_packed: false,
636 data: &[0xE4],
637 };
638 let decoded = mask.decode(4, 1).unwrap();
639 assert_eq!(decoded, [255, 170, 85, 0]);
640 }
641
642 #[test]
643 fn decode_4bpp_non_packed() {
644 let mask = MaskData {
654 bpp: 4,
655 is_packed: false,
656 data: &[0xF8, 0x40, 0x05, 0xA0],
657 };
658 let decoded = mask.decode(3, 2).unwrap();
659 assert_eq!(decoded, [255, 136, 68, 0, 85, 170]);
660 }
661
662 #[test]
663 fn decode_8bpp_non_packed() {
664 let mask = MaskData {
666 bpp: 8,
667 is_packed: false,
668 data: &[10, 20, 30, 40, 50, 60],
669 };
670 let decoded = mask.decode(3, 2).unwrap();
671 assert_eq!(decoded, [10, 20, 30, 40, 50, 60]);
672 }
673
674 #[test]
675 fn decode_1bpp_packed() {
676 let mask = MaskData {
683 bpp: 1,
684 is_packed: true,
685 data: &[0xAB, 0x00],
686 };
687 let decoded = mask.decode(3, 3).unwrap();
688 assert_eq!(decoded, [255, 0, 255, 0, 255, 0, 255, 255, 0],);
689 }
690
691 #[test]
692 fn decode_2bpp_packed() {
693 let mask = MaskData {
701 bpp: 2,
702 is_packed: true,
703 data: &[0xE4, 0xC6, 0xC0],
704 };
705 let decoded = mask.decode(5, 2).unwrap();
706 assert_eq!(decoded, [255, 170, 85, 0, 255, 0, 85, 170, 255, 0]);
707 }
708
709 #[test]
710 fn decode_4bpp_packed() {
711 let mask = MaskData {
719 bpp: 4,
720 is_packed: true,
721 data: &[0xF0, 0x84, 0xA5],
722 };
723 let decoded = mask.decode(3, 2).unwrap();
724 assert_eq!(decoded, [255, 0, 136, 68, 170, 85]);
725 }
726
727 #[test]
728 fn decode_8bpp_packed() {
729 let mask = MaskData {
732 bpp: 8,
733 is_packed: true,
734 data: &[100, 200, 50, 0, 128, 255],
735 };
736 let decoded = mask.decode(3, 2).unwrap();
737 assert_eq!(decoded, [100, 200, 50, 0, 128, 255]);
738 }
739
740 #[test]
741 fn decode_error_cases() {
742 let mask = MaskData {
744 bpp: 8,
745 is_packed: false,
746 data: &[],
747 };
748 assert!(mask.decode(0, 0).unwrap().is_empty());
749 assert!(mask.decode(0, 5).unwrap().is_empty());
750 assert!(mask.decode(5, 0).unwrap().is_empty());
751
752 let mask = MaskData {
754 bpp: 8,
755 is_packed: false,
756 data: &[1, 2, 3],
757 };
758 assert_eq!(
759 mask.decode(4, 2),
760 Err(MaskDataDecodeError::InvalidDimensions)
761 );
762
763 let mask = MaskData {
765 bpp: 1,
766 is_packed: true,
767 data: &[0xFF],
768 };
769 assert_eq!(
770 mask.decode(3, 3),
771 Err(MaskDataDecodeError::InvalidDimensions)
772 );
773 }
774
775 #[test]
776 fn decode_to_slice_basic_and_errors() {
777 let mask = MaskData {
778 bpp: 8,
779 is_packed: false,
780 data: &[10, 20, 30, 40, 50, 60],
781 };
782
783 let mut buf = [0u8; 6];
785 mask.decode_to_slice(3, 2, &mut buf).unwrap();
786 assert_eq!(buf, [10, 20, 30, 40, 50, 60]);
787
788 let mut small_buf = [0u8; 4];
790 assert_eq!(
791 mask.decode_to_slice(3, 2, &mut small_buf),
792 Err(MaskDataDecodeError::InvalidDimensions)
793 );
794
795 let empty = MaskData {
797 bpp: 8,
798 is_packed: false,
799 data: &[],
800 };
801 let mut empty_buf = [0u8; 0];
802 empty.decode_to_slice(0, 0, &mut empty_buf).unwrap();
803 }
804}