1//! A [Color Bitmap Data Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) implementation.
3
4use crate::cblc::{self, BitmapDataFormat, Metrics, MetricsFormat};
5use crate::parser::{NumFrom, Stream};
6use crate::{GlyphId, RasterGlyphImage, RasterImageFormat};
7
8/// A [Color Bitmap Data Table](
9/// https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt).
10///
11/// EBDT and bdat also share the same structure, so this is re-used for them.
12#[derive(Clone, Copy)]
13pub struct Table<'a> {
14 locations: cblc::Table<'a>,
15 data: &'a [u8],
16}
17
18impl<'a> Table<'a> {
19 /// Parses a table from raw data.
20 pub fn parse(locations: cblc::Table<'a>, data: &'a [u8]) -> Option<Self> {
21 Some(Self { locations, data })
22 }
23
24 /// Returns a raster image for the glyph.
25 pub fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<RasterGlyphImage<'a>> {
26 let location = self.locations.get(glyph_id, pixels_per_em)?;
27 let mut s = Stream::new_at(self.data, location.offset)?;
28 let metrics = match location.format.metrics {
29 MetricsFormat::Small => {
30 let height = s.read::<u8>()?;
31 let width = s.read::<u8>()?;
32 let bearing_x = s.read::<i8>()?;
33 let bearing_y = s.read::<i8>()?;
34 s.skip::<u8>(); // advance
35 Metrics {
36 x: bearing_x,
37 y: bearing_y,
38 width,
39 height,
40 }
41 }
42 MetricsFormat::Big => {
43 let height = s.read::<u8>()?;
44 let width = s.read::<u8>()?;
45 let hor_bearing_x = s.read::<i8>()?;
46 let hor_bearing_y = s.read::<i8>()?;
47 s.skip::<u8>(); // hor_advance
48 s.skip::<i8>(); // ver_bearing_x
49 s.skip::<i8>(); // ver_bearing_y
50 s.skip::<u8>(); // ver_advance
51 Metrics {
52 x: hor_bearing_x,
53 y: hor_bearing_y,
54 width,
55 height,
56 }
57 }
58 MetricsFormat::Shared => location.metrics,
59 };
60 match location.format.data {
61 BitmapDataFormat::ByteAligned { bit_depth } => {
62 let row_len = (u32::from(metrics.width) * u32::from(bit_depth) + 7) / 8;
63 let data_len = row_len * u32::from(metrics.height);
64 let data = s.read_bytes(usize::num_from(data_len))?;
65 Some(RasterGlyphImage {
66 x: i16::from(metrics.x),
67 // `y` in CBDT is a bottom bound, not top one.
68 y: i16::from(metrics.y) - i16::from(metrics.height),
69 width: u16::from(metrics.width),
70 height: u16::from(metrics.height),
71 pixels_per_em: location.ppem,
72 format: match bit_depth {
73 1 => RasterImageFormat::BitmapMono,
74 2 => RasterImageFormat::BitmapGray2,
75 4 => RasterImageFormat::BitmapGray4,
76 8 => RasterImageFormat::BitmapGray8,
77 32 => RasterImageFormat::BitmapPremulBgra32,
78 _ => return None,
79 },
80 data,
81 })
82 }
83 BitmapDataFormat::BitAligned { bit_depth } => {
84 let data_len = {
85 let w = u32::from(metrics.width);
86 let h = u32::from(metrics.height);
87 let d = u32::from(bit_depth);
88 (w * h * d + 7) / 8
89 };
90
91 let data = s.read_bytes(usize::num_from(data_len))?;
92 Some(RasterGlyphImage {
93 x: i16::from(metrics.x),
94 // `y` in CBDT is a bottom bound, not top one.
95 y: i16::from(metrics.y) - i16::from(metrics.height),
96 width: u16::from(metrics.width),
97 height: u16::from(metrics.height),
98 pixels_per_em: location.ppem,
99 format: match bit_depth {
100 1 => RasterImageFormat::BitmapMonoPacked,
101 2 => RasterImageFormat::BitmapGray2Packed,
102 4 => RasterImageFormat::BitmapGray4Packed,
103 8 => RasterImageFormat::BitmapGray8,
104 32 => RasterImageFormat::BitmapPremulBgra32,
105 _ => return None,
106 },
107 data,
108 })
109 }
110 BitmapDataFormat::PNG => {
111 let data_len = s.read::<u32>()?;
112 let data = s.read_bytes(usize::num_from(data_len))?;
113 Some(RasterGlyphImage {
114 x: i16::from(metrics.x),
115 // `y` in CBDT is a bottom bound, not top one.
116 y: i16::from(metrics.y) - i16::from(metrics.height),
117 width: u16::from(metrics.width),
118 height: u16::from(metrics.height),
119 pixels_per_em: location.ppem,
120 format: RasterImageFormat::PNG,
121 data,
122 })
123 }
124 }
125 }
126}
127
128impl core::fmt::Debug for Table<'_> {
129 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
130 write!(f, "Table {{ ... }}")
131 }
132}
133