1//! A [Color Bitmap Data Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt) implementation.
3
4use super::cblc::{self, BitmapFormat};
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#[derive(Clone, Copy)]
11pub struct Table<'a> {
12 locations: cblc::Table<'a>,
13 data: &'a [u8],
14}
15
16impl<'a> Table<'a> {
17 /// Parses a table from raw data.
18 pub fn parse(locations: cblc::Table<'a>, data: &'a [u8]) -> Option<Self> {
19 Some(Self { locations, data })
20 }
21
22 /// Returns a raster image for the glyph.
23 pub fn get(&self, glyph_id: GlyphId, pixels_per_em: u16) -> Option<RasterGlyphImage<'a>> {
24 let location = self.locations.get(glyph_id, pixels_per_em)?;
25 let mut s = Stream::new_at(self.data, location.offset)?;
26 match location.format {
27 BitmapFormat::Format17 => {
28 let height = s.read::<u8>()?;
29 let width = s.read::<u8>()?;
30 let bearing_x = s.read::<i8>()?;
31 let bearing_y = s.read::<i8>()?;
32 s.skip::<u8>(); // advance
33 let data_len = s.read::<u32>()?;
34 let data = s.read_bytes(usize::num_from(data_len))?;
35 Some(RasterGlyphImage {
36 x: i16::from(bearing_x),
37 // `y` in CBDT is a bottom bound, not top one.
38 y: i16::from(bearing_y) - i16::from(height),
39 width: u16::from(width),
40 height: u16::from(height),
41 pixels_per_em: location.ppem,
42 format: RasterImageFormat::PNG,
43 data,
44 })
45 }
46 BitmapFormat::Format18 => {
47 let height = s.read::<u8>()?;
48 let width = s.read::<u8>()?;
49 let hor_bearing_x = s.read::<i8>()?;
50 let hor_bearing_y = s.read::<i8>()?;
51 s.skip::<u8>(); // hor_advance
52 s.skip::<i8>(); // ver_bearing_x
53 s.skip::<i8>(); // ver_bearing_y
54 s.skip::<u8>(); // ver_advance
55 let data_len = s.read::<u32>()?;
56 let data = s.read_bytes(usize::num_from(data_len))?;
57 Some(RasterGlyphImage {
58 x: i16::from(hor_bearing_x),
59 // `y` in CBDT is a bottom bound, not top one.
60 y: i16::from(hor_bearing_y) - i16::from(height),
61 width: u16::from(width),
62 height: u16::from(height),
63 pixels_per_em: location.ppem,
64 format: RasterImageFormat::PNG,
65 data,
66 })
67 }
68 BitmapFormat::Format19 => {
69 let data_len = s.read::<u32>()?;
70 let data = s.read_bytes(usize::num_from(data_len))?;
71 Some(RasterGlyphImage {
72 x: i16::from(location.metrics.x),
73 // `y` in CBDT is a bottom bound, not top one.
74 y: i16::from(location.metrics.y) - i16::from(location.metrics.height),
75 width: u16::from(location.metrics.width),
76 height: u16::from(location.metrics.height),
77 pixels_per_em: location.ppem,
78 format: RasterImageFormat::PNG,
79 data,
80 })
81 }
82 }
83 }
84}
85
86impl core::fmt::Debug for Table<'_> {
87 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
88 write!(f, "Table {{ ... }}")
89 }
90}
91