1use super::{instance::Size, metrics::GlyphMetrics, MetadataProvider};
4use crate::prelude::LocationRef;
5use raw::{
6 tables::{bitmap, cbdt, cblc, ebdt, eblc, sbix},
7 types::{GlyphId, Tag},
8 FontData, FontRef, TableProvider,
9};
10
11#[derive(Clone)]
13pub struct BitmapStrikes<'a>(StrikesKind<'a>);
14
15impl<'a> BitmapStrikes<'a> {
16 pub fn new(font: &FontRef<'a>) -> Self {
22 for format in [BitmapFormat::Sbix, BitmapFormat::Cbdt, BitmapFormat::Ebdt] {
23 if let Some(strikes) = Self::with_format(font, format) {
24 return strikes;
25 }
26 }
27 Self(StrikesKind::None)
28 }
29
30 pub fn with_format(font: &FontRef<'a>, format: BitmapFormat) -> Option<Self> {
34 let kind = match format {
35 BitmapFormat::Sbix => StrikesKind::Sbix(
36 font.sbix().ok()?,
37 font.glyph_metrics(Size::unscaled(), LocationRef::default()),
38 ),
39 BitmapFormat::Cbdt => {
40 StrikesKind::Cbdt(CbdtTables::new(font.cblc().ok()?, font.cbdt().ok()?))
41 }
42 BitmapFormat::Ebdt => {
43 StrikesKind::Ebdt(EbdtTables::new(font.eblc().ok()?, font.ebdt().ok()?))
44 }
45 };
46 Some(Self(kind))
47 }
48
49 pub fn format(&self) -> Option<BitmapFormat> {
52 match &self.0 {
53 StrikesKind::None => None,
54 StrikesKind::Sbix(..) => Some(BitmapFormat::Sbix),
55 StrikesKind::Cbdt(..) => Some(BitmapFormat::Cbdt),
56 StrikesKind::Ebdt(..) => Some(BitmapFormat::Ebdt),
57 }
58 }
59
60 pub fn len(&self) -> usize {
62 match &self.0 {
63 StrikesKind::None => 0,
64 StrikesKind::Sbix(sbix, _) => sbix.strikes().len(),
65 StrikesKind::Cbdt(cbdt) => cbdt.location.bitmap_sizes().len(),
66 StrikesKind::Ebdt(ebdt) => ebdt.location.bitmap_sizes().len(),
67 }
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.len() == 0
73 }
74
75 pub fn get(&self, index: usize) -> Option<BitmapStrike<'a>> {
77 let kind = match &self.0 {
78 StrikesKind::None => return None,
79 StrikesKind::Sbix(sbix, metrics) => {
80 StrikeKind::Sbix(sbix.strikes().get(index).ok()?, metrics.clone())
81 }
82 StrikesKind::Cbdt(tables) => StrikeKind::Cbdt(
83 tables.location.bitmap_sizes().get(index).copied()?,
84 tables.clone(),
85 ),
86 StrikesKind::Ebdt(tables) => StrikeKind::Ebdt(
87 tables.location.bitmap_sizes().get(index).copied()?,
88 tables.clone(),
89 ),
90 };
91 Some(BitmapStrike(kind))
92 }
93
94 pub fn glyph_for_size(&self, size: Size, glyph_id: GlyphId) -> Option<BitmapGlyph<'a>> {
100 let size = size.ppem().unwrap_or(f32::MAX);
102 self.iter()
103 .fold(None, |best: Option<BitmapGlyph<'a>>, entry| {
104 let entry_size = entry.ppem();
105 if let Some(best) = best {
106 let best_size = best.ppem_y;
107 if (entry_size >= size && entry_size < best_size)
108 || (best_size < size && entry_size > best_size)
109 {
110 entry.get(glyph_id).or(Some(best))
111 } else {
112 Some(best)
113 }
114 } else {
115 entry.get(glyph_id)
116 }
117 })
118 }
119
120 pub fn iter(&self) -> impl Iterator<Item = BitmapStrike<'a>> + 'a + Clone {
122 let this = self.clone();
123 (0..this.len()).filter_map(move |ix| this.get(ix))
124 }
125}
126
127#[derive(Clone)]
128enum StrikesKind<'a> {
129 None,
130 Sbix(sbix::Sbix<'a>, GlyphMetrics<'a>),
131 Cbdt(CbdtTables<'a>),
132 Ebdt(EbdtTables<'a>),
133}
134
135#[derive(Clone)]
137pub struct BitmapStrike<'a>(StrikeKind<'a>);
138
139impl<'a> BitmapStrike<'a> {
140 pub fn ppem(&self) -> f32 {
142 match &self.0 {
143 StrikeKind::Sbix(sbix, _) => sbix.ppem() as f32,
144 StrikeKind::Cbdt(size, _) => size.ppem_y() as f32,
147 StrikeKind::Ebdt(size, _) => size.ppem_y() as f32,
148 }
149 }
150
151 pub fn get(&self, glyph_id: GlyphId) -> Option<BitmapGlyph<'a>> {
153 match &self.0 {
154 StrikeKind::Sbix(sbix, metrics) => {
155 let glyph = sbix.glyph_data(glyph_id).ok()??;
156 if glyph.graphic_type() != Tag::new(b"png ") {
157 return None;
158 }
159
160 let glyf_bb = metrics.bounds(glyph_id).unwrap_or_default();
164 let lsb = metrics.left_side_bearing(glyph_id).unwrap_or_default();
165 let ppem = sbix.ppem() as f32;
166 let png_data = glyph.data();
167 let reader = FontData::new(png_data);
170 let width = reader.read_at::<u32>(16).ok()?;
171 let height = reader.read_at::<u32>(20).ok()?;
172 Some(BitmapGlyph {
173 data: BitmapData::Png(glyph.data()),
174 bearing_x: lsb,
175 bearing_y: glyf_bb.y_min,
176 inner_bearing_x: glyph.origin_offset_x() as f32,
177 inner_bearing_y: glyph.origin_offset_y() as f32,
178 ppem_x: ppem,
179 ppem_y: ppem,
180 width,
181 height,
182 advance: None,
183 placement_origin: Origin::BottomLeft,
184 })
185 }
186 StrikeKind::Cbdt(size, tables) => {
187 let location = size
188 .location(tables.location.offset_data(), glyph_id)
189 .ok()?;
190 let data = tables.data.data(&location).ok()?;
191 BitmapGlyph::from_bdt(size, &data)
192 }
193 StrikeKind::Ebdt(size, tables) => {
194 let location = size
195 .location(tables.location.offset_data(), glyph_id)
196 .ok()?;
197 let data = tables.data.data(&location).ok()?;
198 BitmapGlyph::from_bdt(size, &data)
199 }
200 }
201 }
202}
203
204#[derive(Clone)]
205enum StrikeKind<'a> {
206 Sbix(sbix::Strike<'a>, GlyphMetrics<'a>),
207 Cbdt(bitmap::BitmapSize, CbdtTables<'a>),
208 Ebdt(bitmap::BitmapSize, EbdtTables<'a>),
209}
210
211#[derive(Clone)]
212struct BdtTables<L, D> {
213 location: L,
214 data: D,
215}
216
217impl<L, D> BdtTables<L, D> {
218 fn new(location: L, data: D) -> Self {
219 Self { location, data }
220 }
221}
222
223type CbdtTables<'a> = BdtTables<cblc::Cblc<'a>, cbdt::Cbdt<'a>>;
224type EbdtTables<'a> = BdtTables<eblc::Eblc<'a>, ebdt::Ebdt<'a>>;
225
226#[derive(Clone)]
228pub struct BitmapGlyph<'a> {
229 pub data: BitmapData<'a>,
231 pub bearing_x: f32,
233 pub bearing_y: f32,
235 pub inner_bearing_x: f32,
238 pub inner_bearing_y: f32,
241 pub ppem_x: f32,
243 pub ppem_y: f32,
245 pub advance: Option<f32>,
247 pub width: u32,
249 pub height: u32,
251 pub placement_origin: Origin,
253}
254
255impl<'a> BitmapGlyph<'a> {
256 fn from_bdt(
257 bitmap_size: &bitmap::BitmapSize,
258 bitmap_data: &bitmap::BitmapData<'a>,
259 ) -> Option<Self> {
260 let metrics = BdtMetrics::new(bitmap_data);
261 let (ppem_x, ppem_y) = (bitmap_size.ppem_x() as f32, bitmap_size.ppem_y() as f32);
262 let bpp = bitmap_size.bit_depth();
263 let data = match bpp {
264 32 => {
265 match &bitmap_data.content {
266 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::Png, bytes) => {
267 BitmapData::Png(bytes)
268 }
269 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
271 BitmapData::Bgra(bytes)
272 }
273 _ => return None,
274 }
275 }
276 1 | 2 | 4 | 8 => {
277 let (data, is_packed) = match &bitmap_data.content {
278 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::ByteAligned, bytes) => {
279 (bytes, false)
280 }
281 bitmap::BitmapContent::Data(bitmap::BitmapDataFormat::BitAligned, bytes) => {
282 (bytes, true)
283 }
284 _ => return None,
285 };
286 BitmapData::Mask(MaskData {
287 bpp,
288 is_packed,
289 data,
290 })
291 }
292 _ => return None,
294 };
295 Some(Self {
296 data,
297 bearing_x: 0.0,
298 bearing_y: 0.0,
299 inner_bearing_x: metrics.inner_bearing_x,
300 inner_bearing_y: metrics.inner_bearing_y,
301 ppem_x,
302 ppem_y,
303 width: metrics.width,
304 height: metrics.height,
305 advance: Some(metrics.advance),
306 placement_origin: Origin::TopLeft,
307 })
308 }
309}
310
311struct BdtMetrics {
312 inner_bearing_x: f32,
313 inner_bearing_y: f32,
314 advance: f32,
315 width: u32,
316 height: u32,
317}
318
319impl BdtMetrics {
320 fn new(data: &bitmap::BitmapData) -> Self {
321 match data.metrics {
322 bitmap::BitmapMetrics::Small(metrics) => Self {
323 inner_bearing_x: metrics.bearing_x() as f32,
324 inner_bearing_y: metrics.bearing_y() as f32,
325 advance: metrics.advance() as f32,
326 width: metrics.width() as u32,
327 height: metrics.height() as u32,
328 },
329 bitmap::BitmapMetrics::Big(metrics) => Self {
330 inner_bearing_x: metrics.hori_bearing_x() as f32,
331 inner_bearing_y: metrics.hori_bearing_y() as f32,
332 advance: metrics.hori_advance() as f32,
333 width: metrics.width() as u32,
334 height: metrics.height() as u32,
335 },
336 }
337 }
338}
339
340#[derive(Copy, Clone, PartialEq, Eq, Debug)]
342pub enum Origin {
343 TopLeft,
345 BottomLeft,
347}
348
349#[derive(Clone)]
351pub enum BitmapData<'a> {
352 Bgra(&'a [u8]),
355 Png(&'a [u8]),
357 Mask(MaskData<'a>),
359}
360
361#[derive(Clone)]
363pub struct MaskData<'a> {
364 pub bpp: u8,
366 pub is_packed: bool,
369 pub data: &'a [u8],
371}
372
373#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
375pub enum BitmapFormat {
376 Sbix,
377 Cbdt,
378 Ebdt,
379}
380
381#[cfg(test)]
382mod tests {
383 use crate::bitmap::{BitmapData, StrikesKind};
384 use crate::prelude::Size;
385 use crate::{GlyphId, MetadataProvider};
386 use raw::FontRef;
387
388 #[test]
389 fn cbdt_metadata() {
390 let font = FontRef::new(font_test_data::CBDT).unwrap();
391 let strikes = font.bitmap_strikes();
392
393 assert!(matches!(strikes.0, StrikesKind::Cbdt(_)));
394 assert!(matches!(strikes.len(), 3));
395
396 assert!(matches!(strikes.get(0).unwrap().ppem(), 16.0));
398 assert!(matches!(strikes.get(1).unwrap().ppem(), 64.0));
399 assert!(matches!(strikes.get(2).unwrap().ppem(), 128.0));
400 }
401
402 #[test]
403 fn cbdt_glyph_metrics() {
404 let font = FontRef::new(font_test_data::CBDT).unwrap();
405 let strike_0 = font.bitmap_strikes().get(0).unwrap();
406
407 let zero = strike_0.get(GlyphId::new(0)).unwrap();
408 assert_eq!(zero.width, 11);
409 assert_eq!(zero.height, 13);
410 assert_eq!(zero.bearing_x, 0.0);
411 assert_eq!(zero.bearing_y, 0.0);
412 assert_eq!(zero.inner_bearing_x, 1.0);
413 assert_eq!(zero.inner_bearing_y, 13.0);
414 assert_eq!(zero.advance, Some(12.0));
415
416 let strike_1 = font.bitmap_strikes().get(1).unwrap();
417
418 let zero = strike_1.get(GlyphId::new(2)).unwrap();
419 assert_eq!(zero.width, 39);
420 assert_eq!(zero.height, 52);
421 assert_eq!(zero.bearing_x, 0.0);
422 assert_eq!(zero.bearing_y, 0.0);
423 assert_eq!(zero.inner_bearing_x, 6.0);
424 assert_eq!(zero.inner_bearing_y, 52.0);
425 assert_eq!(zero.advance, Some(51.0));
426 }
427
428 #[test]
429 fn cbdt_glyph_selection() {
430 let font = FontRef::new(font_test_data::CBDT).unwrap();
431 let strikes = font.bitmap_strikes();
432
433 let g1 = strikes
434 .glyph_for_size(Size::new(12.0), GlyphId::new(2))
435 .unwrap();
436 assert_eq!(g1.ppem_x, 16.0);
437
438 let g2 = strikes
439 .glyph_for_size(Size::new(17.0), GlyphId::new(2))
440 .unwrap();
441 assert_eq!(g2.ppem_x, 64.0);
442
443 let g3 = strikes
444 .glyph_for_size(Size::new(60.0), GlyphId::new(2))
445 .unwrap();
446 assert_eq!(g3.ppem_x, 64.0);
447
448 let g4 = strikes
449 .glyph_for_size(Size::unscaled(), GlyphId::new(2))
450 .unwrap();
451 assert_eq!(g4.ppem_x, 128.0);
452 }
453
454 #[test]
455 fn sbix_metadata() {
456 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
457 let strikes = font.bitmap_strikes();
458
459 assert!(matches!(strikes.0, StrikesKind::Sbix(_, _)));
460 assert!(matches!(strikes.len(), 1));
461
462 assert!(matches!(strikes.get(0).unwrap().ppem(), 109.0));
463 }
464
465 #[test]
466 fn sbix_glyph_metrics() {
467 let font = FontRef::new(font_test_data::NOTO_HANDWRITING_SBIX).unwrap();
468 let strike_0 = font.bitmap_strikes().get(0).unwrap();
469
470 let g0 = strike_0.get(GlyphId::new(7)).unwrap();
471 assert_eq!(g0.bearing_x, 0.0);
473 assert_eq!(g0.bearing_y, 0.0);
477 assert_eq!(g0.inner_bearing_x, 4.0);
479 assert_eq!(g0.inner_bearing_y, -27.0);
480 assert!(matches!(g0.data, BitmapData::Png(_)))
481 }
482}