1use alloc::vec;
16use alloc::vec::Vec;
17
18use gfx::Surface;
19use rt::fx::{cvt, cvtt, maxss, minss};
20
21use crate::ttf::{Tb, TtFont, TFF_CBDT, TFF_COLR, TT_CBDT, TT_CBLC, TT_COLR, TT_CPAL};
22
23pub const LAYER_FG: u32 = 0x8000_0000;
24const PNG_MAX: u64 = 16 * 1024 * 1024;
25const BMP_MAXSIDE: i32 = 2048;
26
27pub type PngDecode = fn(&[u8]) -> Option<Surface>;
29pub type ImgScale = fn(&Surface, i32, i32) -> Option<Surface>;
31
32pub struct Bitmap {
34 pub left: i32,
35 pub top: i32,
36 pub w: i32,
37 pub h: i32,
38 pub px: Vec<u8>,
39}
40
41pub fn open(f: &mut TtFont) {
43 'colr: {
45 let t = f.tb(TT_COLR);
46 if t.len() < 14 || t.u16(0) as u32 > 1 {
47 break 'colr;
48 }
49 let nb = t.u16(2);
50 if nb <= 0 {
51 break 'colr; }
53 let bo = t.u32(4);
54 if bo < 0 || (nb as u32).wrapping_mul(6) as u64 + bo as u64 > t.len() as u64 {
55 break 'colr;
56 }
57 let nl = t.u16(12);
58 if nl <= 0 {
59 break 'colr;
60 }
61 let lo = t.u32(8);
62 if lo < 0 || lo as u64 + nl as u64 * 4 > t.len() as u64 {
63 break 'colr;
64 }
65 let p = f.tb(TT_CPAL);
67 if p.len() < 14 {
68 break 'colr;
69 }
70 let ne = p.u16(2);
71 if ne <= 0 || p.u16(4) <= 0 {
72 break 'colr;
73 }
74 let cro = p.u32(8);
75 if cro < 0 {
76 break 'colr;
77 }
78 let ci = p.u16(12);
79 if ci < 0 {
80 break 'colr;
81 }
82 let first = cro as u64 + ci as u64 * 4; if p.len() as u64 <= first {
84 break 'colr;
85 }
86 let avail = (p.len() as u64 - first) >> 2;
87 let n = (ne as u64).min(avail) as u32;
88 if n == 0 {
89 break 'colr;
90 }
91 f.cpal = (first as u32).wrapping_add(f.tab[TT_CPAL].0);
92 f.cpaln = n;
93 f.flags |= TFF_COLR;
94 }
95 if f.tab[TT_CBDT].1 < 8 {
97 return;
98 }
99 let t = f.tb(TT_CBLC);
100 if t.len() < 8 + 48 {
101 return;
102 }
103 let v = t.u16(0);
104 if !(2..=3).contains(&v) || t.u32(4) <= 0 {
105 return;
106 }
107 f.flags |= TFF_CBDT;
108}
109
110pub fn layers(f: &TtFont, glyph: u32, cap: usize, out: &mut Vec<(u32, u32)>) {
112 out.clear();
113 if f.flags & TFF_COLR == 0 {
114 return;
115 }
116 let t = f.tb(TT_COLR);
117 let d = t.0;
118 let nb = t.u16(2) as u32; let bo = t.u32(4) as u32;
120 let (mut lo, mut hi) = (0u32, nb);
121 let mut found = None;
122 while lo < hi {
123 let mid = (lo + hi) >> 1;
124 let r = (mid * 6 + bo) as usize;
125 let g = u16::from_be_bytes([d[r], d[r + 1]]) as u32;
126 if glyph < g {
127 hi = mid;
128 } else if glyph > g {
129 lo = mid + 1;
130 } else {
131 let first = u16::from_be_bytes([d[r + 2], d[r + 3]]) as u32;
132 let n = u16::from_be_bytes([d[r + 4], d[r + 5]]) as u32;
133 found = Some((first, n));
134 break;
135 }
136 }
137 let Some((first, n)) = found else { return };
138 let n = n.min(cap as u32);
139 let nl = t.u16(12) as u32; let lo = t.u32(8) as u32;
141 for k in 0..n {
142 let li = first + k;
143 if li >= nl {
144 break;
145 }
146 let r = (lo + li * 4) as usize;
147 let lg = u16::from_be_bytes([d[r], d[r + 1]]) as u32;
148 let pi = u16::from_be_bytes([d[r + 2], d[r + 3]]) as u32;
149 if pi >= f.cpaln {
150 out.push((lg | LAYER_FG, 0)); } else {
152 let o = (f.cpal + pi * 4) as usize;
154 let c = u32::from_le_bytes([f.data[o], f.data[o + 1], f.data[o + 2], f.data[o + 3]]);
155 out.push((lg, c));
156 }
157 }
158}
159
160struct Found {
162 off: u32, len: u32,
164 fmt: u32,
165 ppem: u32,
166 metrics: [u8; 5], }
168
169fn bigmetrics(t: Tb, off: u32, m: &mut [u8; 5]) {
171 for (i, v) in m.iter_mut().enumerate() {
172 let b = t.u8(off.wrapping_add(i as u32));
173 *v = if b < 0 { 0 } else { b as u8 };
174 }
175}
176
177fn find(f: &TtFont, glyph: u32, want: u32, metrics: [u8; 5]) -> Option<Found> {
178 let t = f.tb(TT_CBLC);
179 let ns = t.u32(4);
180 if ns <= 0 {
181 return None;
182 }
183 let ns = (ns as u32).min(256);
184 let (mut best, mut bppem) = (u32::MAX, 0u32);
186 for i in 0..ns {
187 let r = i * 48 + 8; let s = t.u16(r + 40);
189 if s < 0 || glyph < s as u32 {
190 continue;
191 }
192 if glyph > t.u16(r + 42) as u32 {
193 continue;
194 }
195 let pp = t.u8(r + 45);
196 if pp <= 0 {
197 continue;
198 }
199 let pp = pp as u32;
200 let take = if best == u32::MAX {
201 true
202 } else if bppem >= want {
203 pp >= want && pp < bppem
205 } else {
206 pp >= want || pp > bppem
208 };
209 if take {
210 best = r;
211 bppem = pp;
212 }
213 }
214 if best == u32::MAX {
215 return None;
216 }
217 let r = best;
218 let mut m = metrics;
219 let sa = t.u32(r);
220 if sa < 0 {
221 return None;
222 }
223 let sa = sa as u32;
224 let nsub = t.u32(r + 8);
225 if nsub <= 0 {
226 return None;
227 }
228 let nsub = (nsub as u32).min(4096);
229 let mut sub = None;
231 for i in 0..nsub {
232 let e = (i << 3).wrapping_add(sa);
233 let first = t.u16(e);
234 if first < 0 {
235 return None;
236 }
237 if glyph < first as u32 {
238 continue;
239 }
240 if glyph <= t.u16(e.wrapping_add(2)) as u32 {
241 sub = Some((e, first as u32));
242 break;
243 }
244 }
245 let (e, first) = sub?;
246 let ao = t.u32(e.wrapping_add(4));
247 if ao < 0 {
248 return None;
249 }
250 let st = (ao as u32).wrapping_add(sa); let ifmt = t.u16(st);
252 let fmt = t.u16(st.wrapping_add(2)) as u32;
253 let ido = t.u32(st.wrapping_add(4));
254 if ido < 0 {
255 return None;
256 }
257 let mut ido = ido as u32; let k = glyph - first;
259 let span = |a: i64, b: i64| -> Option<(u32, u32)> {
261 if b <= a {
262 return None; }
264 Some(((a as u32).wrapping_add(ido), (b - a) as u32))
265 };
266 let (off, len) = match ifmt {
267 1 => {
268 let a = t.u32(st.wrapping_add(k.wrapping_mul(4)).wrapping_add(8));
269 if a < 0 {
270 return None;
271 }
272 let b = t.u32(st.wrapping_add(k.wrapping_mul(4)).wrapping_add(12));
273 if b < 0 {
274 return None;
275 }
276 span(a, b)?
277 }
278 3 => {
279 let a = t.u16(st.wrapping_add(k.wrapping_mul(2)).wrapping_add(8));
280 if a < 0 {
281 return None;
282 }
283 let b = t.u16(st.wrapping_add(k.wrapping_mul(2)).wrapping_add(10));
284 if b < 0 {
285 return None;
286 }
287 span(a as i64, b as i64)?
288 }
289 2 => {
290 let size = t.u32(st.wrapping_add(8)); if size <= 0 {
292 return None;
293 }
294 let size = size as u32;
295 ido = size.wrapping_mul(k).wrapping_add(ido);
296 bigmetrics(t, st.wrapping_add(12), &mut m);
297 (ido, size)
298 }
299 5 => {
300 let n = t.u32(st.wrapping_add(20)); if n <= 0 {
302 return None;
303 }
304 let mut idx = None;
305 for i in 0..n as u32 {
306 let g = t.u16(st.wrapping_add(i * 2).wrapping_add(24));
307 if g < 0 {
308 return None;
309 }
310 if g as u32 == glyph {
311 idx = Some(i);
312 break;
313 }
314 }
315 let i = idx?;
316 let size = t.u32(st.wrapping_add(8));
317 if size <= 0 {
318 return None;
319 }
320 let size = size as u32;
321 ido = size.wrapping_mul(i).wrapping_add(ido);
322 bigmetrics(t, st.wrapping_add(12), &mut m);
323 (ido, size)
324 }
325 4 => {
326 let n = t.u32(st.wrapping_add(8)); if n <= 0 {
328 return None;
329 }
330 let mut idx = None;
331 for i in 0..n as u32 {
332 let g = t.u16(st.wrapping_add(i * 4).wrapping_add(12));
333 if g < 0 {
334 return None;
335 }
336 if g as u32 == glyph {
337 idx = Some(i);
338 break;
339 }
340 }
341 let i = idx?;
342 let a = t.u16(st.wrapping_add(i * 4).wrapping_add(14));
343 let b = t.u16(st.wrapping_add(i * 4).wrapping_add(18));
344 if b < 0 {
345 return None;
346 }
347 span(a as u32 as i64, b as i64)?
348 }
349 _ => return None,
350 };
351 if off == 0 {
352 return None;
353 }
354 Some(Found { off, len, fmt, ppem: bppem, metrics: m })
355}
356
357pub fn bitmap(f: &TtFont, glyph: u32, size_fx: i32, png: Option<PngDecode>, scale: Option<ImgScale>,
359 metrics: &mut [u8; 5]) -> Option<Bitmap> {
360 if f.flags & TFF_CBDT == 0 {
361 return None;
362 }
363 let want = ((size_fx as u32).wrapping_add(255)) >> 8; let fd = find(f, glyph, want, *metrics)?;
365 *metrics = fd.metrics;
366 let t = f.tb(TT_CBDT);
367 let s = fd.off;
368 let (plen, poff): (i64, u32) = match fd.fmt {
369 19 => {
370 let l = t.u32(s);
372 if l < 0 {
373 return None;
374 }
375 (l, s.wrapping_add(4))
376 }
377 17 => {
378 for i in 0..5u32 {
379 let b = t.u8(s.wrapping_add(i));
380 if b < 0 {
381 return None;
382 }
383 metrics[i as usize] = b as u8;
384 }
385 let l = t.u32(s.wrapping_add(5));
386 if l < 0 {
387 return None;
388 }
389 (l, s.wrapping_add(9))
390 }
391 18 => {
392 bigmetrics(t, s, metrics);
393 let l = t.u32(s.wrapping_add(8));
394 if l < 0 {
395 return None;
396 }
397 (l, s.wrapping_add(12))
398 }
399 _ => return None,
400 };
401 let _ = fd.len;
402 if poff as u64 + plen as u64 > t.len() as u64 || plen as u64 > PNG_MAX {
403 return None;
404 }
405 let src = (png?)(&t.0[poff as usize..poff as usize + plen as usize])?;
406 let sc = size_fx as f32 * (1.0 / 256.0) / fd.ppem as i32 as f32;
408 let w = cvt(src.w as f32 * sc).max(1);
409 if w > BMP_MAXSIDE {
410 return None;
411 }
412 let h = cvt(src.h as f32 * sc).max(1);
413 if h > BMP_MAXSIDE {
414 return None;
415 }
416 let px = if w > src.w || h > src.h {
418 let up = (scale?)(&src, w, h)?;
419 area_scale(&up, w, h) } else {
421 area_scale(&src, w, h)
422 };
423 let left = cvt(metrics[2] as i8 as i32 as f32 * sc);
425 let top = cvt(metrics[3] as i8 as i32 as f32 * sc).wrapping_neg();
426 Some(Bitmap { left, top, w, h, px })
427}
428
429fn area_scale(src: &Surface, w: i32, h: i32) -> Vec<u8> {
431 let mut out = vec![0u8; (w * h * 4) as usize];
432 let fx = src.w as f32 / w as f32;
434 let fy = src.h as f32 / h as f32;
435 let stride = src.stride as usize;
436 let mut o = 0usize;
437 for y in 0..h {
438 for x in 0..w {
439 let x0 = x as f32 * fx;
441 let x1 = x0 + fx;
442 let y0 = y as f32 * fy;
443 let y1 = y0 + fy;
444 let mut acc = [0f32; 4];
445 let mut wsum = 0f32;
446 let mut sy = cvtt(y0);
447 loop {
448 let syf = sy as f32;
449 if !(syf < y1) || sy as u32 >= src.h as u32 {
450 break;
451 }
452 let wy = minss(syf + 1.0, y1) - maxss(syf, y0);
454 let row = sy as usize * stride;
455 let mut sx = cvtt(x0);
456 loop {
457 let sxf = sx as f32;
458 if !(sxf < x1) || sx as u32 >= src.w as u32 {
459 break;
460 }
461 let wgt = (minss(sxf + 1.0, x1) - maxss(sxf, x0)) * wy;
462 wsum = wsum + wgt;
463 let p = row + sx as usize * 4;
464 for c in 0..4 {
465 acc[c] = acc[c] + src.px[p + c] as f32 * wgt;
466 }
467 sx += 1;
468 }
469 sy += 1;
470 }
471 if wsum > 0.0 {
472 for c in 0..4 {
473 let v = cvt(acc[c] / wsum).clamp(-32768, 32767);
475 out[o + c] = v.clamp(0, 255) as u8;
476 }
477 }
478 o += 4;
479 }
480 }
481 out
482}