1use alloc::boxed::Box;
28use alloc::vec::Vec;
29
30use rt::fx::cvt;
31
32use crate::colr;
33use crate::font::*;
34use crate::outline::{Zones, F_INV30, F_TAN12};
35use crate::ttf::{self, TtFont, ERR_FAIL, ERR_IO, ERR_LIMIT, FILE_MAX};
36use crate::var::{VarAxis, VarInstance};
37use crate::Text;
38
39pub const FONT_EMBEDDED: u32 = 4; pub const FONT_MAX_IDS: u32 = 4096; pub struct SynFont {
44 pub hdr: Hdr,
45 pub fm: Metrics,
46 pub base: u32,
47 pub syn: u32,
48 pub strength: f32, pub serial: u64,
50}
51
52pub(crate) struct VarFont {
54 pub hdr: Hdr,
55 pub fm: Metrics,
56 pub base: u32,
57 pub user: Vec<f32>,
59 pub coords: Vec<i16>,
60 pub serial: u64,
61 pub adv: Vec<i32>,
63}
64
65pub(crate) enum Face {
66 Free,
67 Sgf(Font),
68 Tt(Box<TtFont>),
69 Syn(Box<SynFont>),
70 Var(Box<VarFont>),
71}
72
73pub(crate) struct Slot {
74 pub face: Face,
75 pub raster: crate::FontRaster,
76 pub fmap: Vec<u16>, }
78
79impl Slot {
80 fn free() -> Slot {
81 Slot { face: Face::Free, raster: crate::FontRaster::Legacy, fmap: Vec::new() }
82 }
83
84 fn is_free(&self) -> bool {
85 matches!(self.face, Face::Free)
86 }
87}
88
89static S_SGF1: &[u8] = b"SGF1";
90static S_REGULAR: &[u8] = b"Regular";
91
92impl Text {
93 pub(crate) fn slot_idx(&self, font: u32) -> Option<usize> {
98 if self.slots.is_empty() {
99 return None;
100 }
101 let i = font as usize;
102 if i < self.slots.len() && !self.slots[i].is_free() { Some(i) } else { Some(0) }
103 }
104
105 pub(crate) fn face(&self, font: u32) -> Option<&Face> {
106 self.slot_idx(font).map(|i| &self.slots[i].face)
107 }
108
109 fn slot_alloc(&mut self) -> Option<usize> {
111 for i in FONT_EMBEDDED as usize..self.slots.len() {
112 if self.slots[i].is_free() {
113 return Some(i);
114 }
115 }
116 if self.slots.len() >= FONT_MAX_IDS as usize {
117 return None;
118 }
119 self.slots.push(Slot::free());
120 Some(self.slots.len() - 1)
121 }
122
123 pub fn register(&mut self, data: &'static [u8]) -> i32 {
125 let Some(f) = Font::parse(data) else { return -1 };
126 let Some(i) = self.slot_alloc() else { return -1 };
127 self.slots[i] = Slot { face: Face::Sgf(f), raster: crate::FontRaster::Legacy, fmap: Vec::new() };
128 i as i32
129 }
130
131 fn fast_map(&self, face: &Face) -> Vec<u16> {
133 let mut fmap = Vec::with_capacity(FAST_CP as usize);
134 for cp in 0..FAST_CP {
135 let g = match face {
136 Face::Tt(t) => t.glyph(cp),
137 Face::Syn(s) => self.glyph(s.base, cp),
138 Face::Var(v) => self.glyph(v.base, cp),
139 _ => 0,
140 };
141 fmap.push(g as u16);
142 }
143 fmap
144 }
145
146 fn add_rt(&mut self, face: Face) -> i32 {
148 let fmap = self.fast_map(&face);
149 let Some(i) = self.slot_alloc() else { return ERR_LIMIT };
150 let raster = match &face {
151 Face::Syn(s) => self.font_raster(s.base),
152 Face::Var(v) => self.font_raster(v.base),
153 _ => crate::FontRaster::Legacy,
154 };
155 self.slots[i] = Slot { face, raster, fmap };
156 i as i32
157 }
158
159 pub fn set_embedded(&mut self, fonts: [&'static [u8]; 4], names: [[&'static str; 5]; 4]) {
163 for (i, f) in fonts.iter().enumerate() {
164 let face = if f.starts_with(b"SGF1") {
165 Font::parse(f).map_or(Face::Free, Face::Sgf)
166 } else {
167 let serial = self.next_serial();
168 TtFont::open(Vec::from(*f), 0, &mut self.ol, serial).map_or(Face::Free, Face::Tt)
169 };
170 let fmap = if matches!(face, Face::Tt(_)) { self.fast_map(&face) } else { Vec::new() };
171 while self.slots.len() <= i {
172 self.slots.push(Slot::free());
173 }
174 self.slots[i] = Slot { face, raster: crate::FontRaster::Legacy, fmap };
175 }
176 self.names = names;
177 for i in FONT_EMBEDDED as usize..self.slots.len() {
180 let (base, user) = match &self.slots[i].face {
181 Face::Var(v) if v.base < FONT_EMBEDDED => (v.base, v.user.clone()),
182 _ => continue,
183 };
184 let serial = self.next_serial();
185 let Some((hdr, fm, coords, adv)) = self.var_build(base, &user) else { continue };
186 if let Face::Var(v) = &mut self.slots[i].face {
187 (v.hdr, v.fm, v.coords, v.adv, v.serial) = (hdr, fm, coords, adv, serial);
188 }
189 let fmap = self.fast_map(&self.slots[i].face);
190 self.slots[i].fmap = fmap;
191 self.slots[i].raster = self.font_raster(base);
192 }
193 for i in FONT_EMBEDDED as usize..self.slots.len() {
195 let (base, syn) = match &self.slots[i].face {
196 Face::Syn(s) if s.base < FONT_EMBEDDED => (s.base, s.syn),
197 _ => continue,
198 };
199 let Some((hdr, fm, strength)) = self.syn_metrics(base, syn) else { continue };
200 let serial = self.next_serial();
201 if let Face::Syn(s) = &mut self.slots[i].face {
202 (s.hdr, s.fm, s.strength, s.serial) = (hdr, fm, strength, serial);
203 }
204 let fmap = self.fast_map(&self.slots[i].face);
205 self.slots[i].fmap = fmap;
206 self.slots[i].raster = self.font_raster(base);
207 }
208 self.gc_flush();
209 }
210
211 fn next_serial(&mut self) -> u64 {
212 self.serial += 1;
213 self.serial
214 }
215
216 pub fn face_count(data: &[u8]) -> i32 {
218 ttf::face_count(data)
219 }
220
221 pub fn load_mem(&mut self, data: &[u8], face: u32) -> i32 {
223 self.load_vec(Vec::from(data), face)
224 }
225
226 fn load_vec(&mut self, data: Vec<u8>, face: u32) -> i32 {
227 let serial = self.next_serial();
228 match TtFont::open(data, face, &mut self.ol, serial) {
229 Ok(t) => self.add_rt(Face::Tt(t)),
230 Err(e) => e,
231 }
232 }
233
234 pub fn load_file(&mut self, path: &str, face: u32) -> i32 {
236 let Some(f) = plat::File::open(path, plat::FO_READ) else { return ERR_IO };
237 let size = f.size().unwrap_or(0);
238 if size == 0 {
239 return ERR_IO;
240 }
241 if size > FILE_MAX {
242 return ERR_LIMIT;
243 }
244 let mut buf = alloc::vec![0u8; size as usize];
245 if f.read_at(0, &mut buf) != Some(size as usize) {
246 return ERR_IO;
247 }
248 drop(f);
249 self.load_vec(buf, face)
250 }
251
252 pub fn unload(&mut self, id: u32) -> i32 {
254 let i = id as usize;
255 if id < FONT_EMBEDDED || i >= self.slots.len() || self.slots[i].is_free() {
256 return -1;
257 }
258 let old = core::mem::replace(&mut self.slots[i].face, Face::Free);
260 let mut j = 0;
262 while j < self.slots.len() {
263 let dep = match &self.slots[j].face {
264 Face::Tt(t) => t.hdr.baseid == id + 1,
265 Face::Syn(s) => s.hdr.baseid == id + 1,
266 Face::Var(v) => v.hdr.baseid == id + 1,
267 _ => false,
268 };
269 if dep {
270 self.unload(j as u32);
271 }
272 j += 1;
273 }
274 drop(old);
275 if i < self.slots.len() {
276 self.slots[i] = Slot::free();
277 }
278 while self.slots.len() > FONT_EMBEDDED as usize && self.slots[self.slots.len() - 1].is_free() {
280 self.slots.pop();
281 }
282 self.gc_flush(); 0
284 }
285
286 pub fn count(&self) -> u32 {
288 self.slots.len() as u32
289 }
290
291 pub fn valid(&self, id: u32) -> bool {
293 (id as usize) < self.slots.len() && !self.slots[id as usize].is_free()
294 }
295
296 pub fn hdr(&self, font: u32) -> Hdr {
298 match self.face(font) {
299 Some(Face::Sgf(f)) => f.hdr(),
300 Some(Face::Tt(t)) => t.hdr,
301 Some(Face::Syn(s)) => s.hdr,
302 Some(Face::Var(v)) => v.hdr,
303 _ => Hdr::default(),
304 }
305 }
306
307 pub fn upem(&self, font: u32) -> i32 {
308 if self.slots.is_empty() { 2048 } else { self.hdr(font).upem }
309 }
310
311 pub fn glyph(&self, font: u32, cp: u32) -> u32 {
313 if cp < FAST_CP && (font as usize) < self.slots.len() {
314 let s = &self.slots[font as usize];
315 if !s.fmap.is_empty() {
316 return s.fmap[cp as usize] as u32;
317 }
318 if let Face::Sgf(f) = &s.face {
319 return f.glyph(cp);
320 }
321 }
322 match self.face(font) {
323 Some(Face::Sgf(f)) => f.glyph(cp),
324 Some(Face::Tt(t)) => t.glyph(cp),
325 Some(Face::Syn(s)) => self.glyph(s.base, cp),
326 Some(Face::Var(v)) => self.glyph(v.base, cp),
327 _ => 0,
328 }
329 }
330
331 pub fn has(&self, font: u32, cp: u32) -> bool {
333 match self.face(font) {
334 Some(Face::Sgf(f)) => f.lookup(cp).is_some(),
335 Some(Face::Tt(t)) => t.has(cp),
336 Some(Face::Syn(s)) => self.has(s.base, cp),
337 Some(Face::Var(v)) => self.has(v.base, cp),
338 _ => false,
339 }
340 }
341
342 pub fn adv(&self, font: u32, g: u32) -> i32 {
344 match self.face(font) {
345 Some(Face::Sgf(f)) => f.adv(g),
346 Some(Face::Tt(t)) => t.adv(g),
347 Some(Face::Syn(s)) => {
348 let a = self.adv(s.base, g);
349 if s.syn & FS_SYN_BOLD != 0 { a.wrapping_add(cvt(s.strength)) } else { a }
350 }
351 Some(Face::Var(v)) => match (v.adv.get(g as usize), self.face(v.base)) {
352 (Some(&a), _) => a,
353 (None, Some(Face::Tt(t))) => t.adv_var(g, &v.coords),
354 _ => 0,
355 },
356 _ => 0,
357 }
358 }
359
360 pub fn kern(&self, font: u32, g1: u32, g2: u32) -> i32 {
362 match self.face(font) {
363 Some(Face::Sgf(f)) => f.kern(g1, g2),
364 Some(Face::Tt(t)) => t.kern(g1, g2),
365 Some(Face::Syn(s)) => self.kern(s.base, g1, g2),
366 Some(Face::Var(v)) => match self.face(v.base) {
367 Some(Face::Tt(t)) => t.kern_var(g1, g2, &v.coords),
368 _ => 0,
369 },
370 _ => 0,
371 }
372 }
373
374 pub fn kern_table(&self, font: u32, g1: u32, g2: u32) -> i32 {
376 match self.face(font) {
377 Some(Face::Tt(t)) => t.kern_table(g1, g2),
378 Some(Face::Var(v)) => self.kern_table(v.base, g1, g2),
379 Some(_) => self.kern(font, g1, g2),
380 None => 0,
381 }
382 }
383
384 pub fn is_color(&self, font: u32) -> bool {
386 self.slot_idx(font).is_some() && self.hdr(font).flags & (SGH_COLR | SGH_CBDT) != 0
387 }
388
389 pub fn layers(&self, font: u32, g: u32, cap: usize, out: &mut Vec<(u32, u32)>) {
392 out.clear();
393 match self.face(font) {
394 Some(Face::Tt(t)) if t.hdr.flags & SGH_COLR != 0 => colr::layers(t, g, cap, out),
395 Some(Face::Syn(s)) if s.hdr.flags & SGH_COLR != 0 => self.layers(s.base, g, cap, out),
396 Some(Face::Var(v)) if v.hdr.flags & SGH_COLR != 0 => self.layers(v.base, g, cap, out),
397 _ => {}
398 }
399 }
400
401 pub fn name(&self, font: u32, which: u32) -> &[u8] {
403 let Some(i) = self.slot_idx(font) else { return b"" };
404 match &self.slots[i].face {
405 Face::Sgf(_) => {
406 if i < FONT_EMBEDDED as usize {
407 let k = match which {
409 FN_FAMILY => 0,
410 FN_STYLE => 1,
411 FN_FULL => 2,
412 FN_TYPO_FAMILY => 3,
413 FN_TYPO_STYLE => 4,
414 _ => return b"",
415 };
416 return self.names[i][k].as_bytes();
417 }
418 match which {
419 FN_FAMILY | FN_TYPO_FAMILY | FN_FULL => S_SGF1,
420 FN_STYLE | FN_TYPO_STYLE => S_REGULAR,
421 _ => b"",
422 }
423 }
424 Face::Tt(t) => t.name(which),
425 Face::Syn(s) => self.name(s.base, which),
426 Face::Var(v) => self.name(v.base, which),
427 Face::Free => b"",
428 }
429 }
430
431 pub fn metrics(&self, font: u32) -> Option<Metrics> {
433 let i = self.slot_idx(font)?;
434 match &self.slots[i].face {
435 Face::Tt(t) => Some(t.fm),
436 Face::Syn(s) => Some(s.fm),
437 Face::Var(v) => Some(v.fm),
438 Face::Sgf(f) => {
439 let mut m = Metrics {
440 upem: f.upem,
441 asc: f.asc,
442 typo_asc: f.asc,
443 win_asc: f.asc,
444 desc: f.desc,
445 typo_desc: f.desc,
446 win_desc: f.desc.wrapping_neg(),
447 gap: f.gap,
448 typo_gap: f.gap,
449 xh: f.xh,
450 caph: f.caph,
451 ul_pos: f.ulpos,
452 ul_thick: f.ulthick,
453 st_thick: f.ulthick,
454 st_pos: (f.xh + f.ulthick) >> 1,
456 width: 5,
457 nglyphs: f.nglyphs as i32,
458 ..Default::default()
459 };
460 m.weight = match i as u32 {
461 1 => 600,
462 2 => 700,
463 _ => 400,
464 };
465 let mut fl = FMF_EMBED;
466 if f.flags & SGH_KERN != 0 {
467 fl |= FMF_KERN;
468 }
469 if i == 2 {
470 fl |= FMF_BOLD;
471 }
472 m.flags = fl;
473 Some(m)
474 }
475 Face::Free => None,
476 }
477 }
478
479 pub fn metric(&self, font: u32, field: u32) -> i32 {
481 self.metrics(font).unwrap_or_default().field(field)
482 }
483
484 pub fn glyph_box(&mut self, font: u32, g: u32) -> Option<[i32; 4]> {
487 let i = self.slot_idx(font)?;
488 match &self.slots[i].face {
489 Face::Sgf(f) => f.glyph_box(g),
490 Face::Tt(t) => t.bbox(g, &mut self.ol),
491 Face::Syn(_) => self.syn_box(i, g),
492 Face::Var(_) => {
493 if self.var_prep(i, g) { self.ol.bbox() } else { None }
494 }
495 Face::Free => None,
496 }
497 }
498
499 pub fn glyph_path(&mut self, font: u32, g: u32) {
502 let Some(i) = self.slot_idx(font) else { return };
503 match &self.slots[i].face {
504 Face::Sgf(f) => {
505 let mut gp = self.gp;
506 f.path(g, &mut gp, &mut self.path, 0);
507 }
508 Face::Tt(t) => t.path(g, &mut self.ol, &mut self.path, &self.gp),
509 Face::Syn(_) => self.syn_path(i, g),
510 Face::Var(v) => {
511 let serial = v.serial;
512 if !self.ol.owner_is(serial, g) {
513 self.var_prep(i, g);
514 }
515 if self.ol.npts() != 0 {
516 self.ol.emit(&mut self.path, &self.gp, None);
517 }
518 }
519 Face::Free => {}
520 }
521 }
522
523 pub(crate) fn op_bitmap(&mut self, font: u32, g: u32, size_fx: i32) -> Option<colr::Bitmap> {
525 let i = self.slot_idx(font)?;
526 match &self.slots[i].face {
527 Face::Tt(t) => colr::bitmap(t, g, size_fx, self.png_decode, self.img_scale, &mut self.cb_metrics),
528 Face::Syn(s) => {
529 let base = s.base;
530 match self.face(base) {
531 Some(Face::Tt(_)) | Some(Face::Syn(_)) | Some(Face::Var(_)) => self.op_bitmap(base, g, size_fx),
532 _ => None,
533 }
534 }
535 Face::Var(v) => {
536 let base = v.base;
537 self.op_bitmap(base, g, size_fx)
538 }
539 _ => None,
540 }
541 }
542
543 fn var_root(&self, font: u32) -> Option<(u32, Option<&[f32]>, u32)> {
548 let (mut f, mut syn) = (font, 0);
549 if let Some(Face::Syn(s)) = self.face(f) {
550 syn = s.syn;
551 f = s.base;
552 }
553 let i = self.slot_idx(f)?;
554 match &self.slots[i].face {
555 Face::Var(v) => Some((v.base, Some(&v.user), syn)),
556 Face::Tt(t) if t.var.is_some() => Some((i as u32, None, syn)),
557 _ => None,
558 }
559 }
560
561 fn var_tt(&self, base: u32) -> Option<&TtFont> {
562 match self.face(base) {
563 Some(Face::Tt(t)) => Some(t),
564 _ => None,
565 }
566 }
567
568 pub fn var_axes(&self, font: u32) -> Vec<VarAxis> {
571 self.var_root(font).and_then(|(b, _, _)| self.var_tt(b)).and_then(|t| t.var.as_ref()).map_or(Vec::new(), |v| v.axes.clone())
572 }
573
574 pub fn var_instances(&self, font: u32) -> Vec<VarInstance> {
576 self.var_root(font).and_then(|(b, _, _)| self.var_tt(b)).and_then(|t| t.var.as_ref()).map_or(Vec::new(), |v| v.instances.clone())
577 }
578
579 pub fn var_values(&self, font: u32) -> Vec<f32> {
582 match self.var_root(font) {
583 Some((_, Some(u), _)) => u.to_vec(),
584 Some(_) => self.var_axes(font).iter().map(|a| a.def).collect(),
585 None => Vec::new(),
586 }
587 }
588
589 pub fn var_coords(&self, font: u32) -> Vec<i16> {
593 let mut f = font;
594 if let Some(Face::Syn(s)) = self.face(f) {
595 f = s.base;
596 }
597 match self.face(f) {
598 Some(Face::Var(v)) => v.coords.clone(),
599 _ => Vec::new(),
600 }
601 }
602
603 pub fn vary(&mut self, font: u32, values: &[([u8; 4], f32)]) -> i32 {
610 if !self.valid(font) {
611 return ERR_FAIL;
612 }
613 let Some((base, cur, syn)) = self.var_root(font) else { return font as i32 };
614 let axes = self.var_axes(base);
615 let mut user: Vec<f32> = match cur {
616 Some(u) => u.to_vec(),
617 None => axes.iter().map(|a| a.def).collect(),
618 };
619 for &(tag, v) in values {
620 if let Some(k) = axes.iter().position(|a| a.tag == tag) {
621 user[k] = if v.is_nan() { axes[k].def } else { v.clamp(axes[k].min, axes[k].max) };
622 }
623 }
624 let id = self.var_instance(base, &user);
625 if id < 0 || syn == 0 { id } else { self.style(id as u32, syn) }
626 }
627
628 pub fn vary_named(&mut self, font: u32, i: usize) -> i32 {
631 let ins = self.var_instances(font);
632 let Some(inst) = ins.get(i) else { return ERR_FAIL };
633 let axes = self.var_axes(font);
634 let vals: Vec<([u8; 4], f32)> = axes.iter().zip(&inst.coords).map(|(a, &c)| (a.tag, c)).collect();
635 self.vary(font, &vals)
636 }
637
638 fn var_instance(&mut self, base: u32, user: &[f32]) -> i32 {
640 let Some(coords) = self.var_tt(base).and_then(|t| t.var.as_ref()).map(|v| v.normalize(user)) else { return base as i32 };
641 if coords.iter().all(|&c| c == 0) {
642 return base as i32;
643 }
644 for i in FONT_EMBEDDED as usize..self.slots.len() {
645 if let Face::Var(v) = &self.slots[i].face
646 && v.base == base
647 && v.coords == coords
648 {
649 return i as i32;
650 }
651 }
652 let Some((hdr, fm, coords, adv)) = self.var_build(base, user) else { return ERR_FAIL };
653 let serial = self.next_serial();
654 self.add_rt(Face::Var(Box::new(VarFont { hdr, fm, base, user: user.to_vec(), coords, serial, adv })))
655 }
656
657 fn var_build(&mut self, base: u32, user: &[f32]) -> Option<(Hdr, Metrics, Vec<i16>, Vec<i32>)> {
660 let bi = self.slot_idx(base)?;
661 let Face::Tt(t) = &self.slots[bi].face else { return None };
662 let v = t.var.as_ref();
663 let coords = v.map_or(Vec::new(), |v| v.normalize(user));
664 let axes: &[VarAxis] = v.map_or(&[], |v| &v.axes);
665 let val = |tag: &[u8; 4]| axes.iter().position(|a| &a.tag == tag).and_then(|k| user.get(k).copied());
666 let (wght, ital, slnt) = (val(b"wght"), val(b"ital"), val(b"slnt"));
667 let (mut hdr, mut fm) = {
668 let (m, h) = t.metrics_var(&coords, wght, &mut self.ol);
669 (h, m)
670 };
671 let adv = t.adv_table(&coords, &mut self.ol);
672 hdr.baseid = base + 1;
673 if let Some(w) = wght {
674 fm.flags = (fm.flags & !FMF_BOLD) | if w >= 600.0 { FMF_BOLD } else { 0 };
675 }
676 if let Some(i) = ital {
677 fm.flags = (fm.flags & !FMF_ITALIC) | if i >= 0.5 { FMF_ITALIC } else { 0 };
678 }
679 if let Some(s) = slnt {
680 fm.flags = (fm.flags & !FMF_OBLIQUE) | if s != 0.0 { FMF_OBLIQUE } else { 0 };
681 }
682 Some((hdr, fm, coords, adv))
683 }
684
685 fn var_prep(&mut self, i: usize, g: u32) -> bool {
687 let Face::Var(v) = &self.slots[i].face else { return false };
688 let Some(bi) = self.slot_idx(v.base) else { return false };
689 let (Face::Var(v), Face::Tt(t)) = (&self.slots[i].face, &self.slots[bi].face) else { return false };
690 t.prep_var(g, &v.coords, v.serial, &mut self.ol)
691 }
692
693 pub(crate) fn shape_engine(&self, mut font: u32) -> Option<text_shape::Engine> {
696 let mut coords: &[i16] = &[];
697 for _ in 0..16 {
698 match self.face(font)? {
699 Face::Tt(t) => {
700 let e = text_shape::Engine::new(&t.data, t.face_index)?;
701 return Some(if coords.is_empty() { e } else { e.with_coords(coords) });
702 }
703 Face::Syn(s) => font = s.base,
704 Face::Var(v) => {
705 if coords.is_empty() {
706 coords = &v.coords;
707 }
708 font = v.base;
709 }
710 _ => return None,
711 }
712 }
713 None
714 }
715
716 pub(crate) fn shape_serial(&self, mut font: u32) -> u64 {
718 for _ in 0..16 {
719 match self.face(font) {
720 Some(Face::Tt(t)) => return t.serial,
721 Some(Face::Var(v)) => return v.serial,
722 Some(Face::Syn(s)) => font = s.base,
723 _ => return 0,
724 }
725 }
726 0
727 }
728
729 pub(crate) fn classic_metrics(&self, font: u32) -> bool {
732 matches!(self.face(font), Some(Face::Syn(s)) if s.syn & FS_CLASSIC != 0)
733 }
734
735 pub fn style(&mut self, font: u32, flags: u32) -> i32 {
737 let mut flags = flags & FS_MASK;
738 if !self.valid(font) {
739 return ERR_FAIL;
740 }
741 if flags == 0 {
742 return font as i32;
743 }
744 let mut base = font;
746 if let Some(Face::Syn(s)) = self.face(font) {
747 flags |= s.syn;
748 base = s.base;
749 }
750 for i in 0..self.slots.len() {
752 if let Face::Syn(s) = &self.slots[i].face
753 && s.base == base
754 && s.syn == flags
755 {
756 return i as i32;
757 }
758 }
759 let Some((hdr, fm, strength)) = self.syn_metrics(base, flags) else { return ERR_FAIL };
760 let serial = self.next_serial();
761 self.add_rt(Face::Syn(Box::new(SynFont { hdr, fm, base, syn: flags, strength, serial })))
762 }
763
764 fn syn_metrics(&self, base: u32, flags: u32) -> Option<(Hdr, Metrics, f32)> {
766 let mut hdr = self.hdr(base);
767 let mut fm = self.metrics(base)?;
768 hdr.flags = (hdr.flags & (SGH_COLR | SGH_CBDT)) | SGH_RUNTIME;
769 hdr.baseid = base + 1;
770 let strength = fm.upem as f32 * F_INV30;
772 fm.flags |= FMF_SYN;
773 if flags & FS_SYN_BOLD != 0 {
774 fm.flags |= FMF_BOLD;
775 fm.weight = fm.weight.wrapping_add(300).clamp(700, 1000);
776 fm.advmax = fm.advmax.wrapping_add(cvt(strength));
777 }
778 if flags & FS_SYN_ITALIC != 0 {
779 fm.flags |= FMF_ITALIC;
780 }
781 Some((hdr, fm, strength))
782 }
783
784 fn syn_prep(&mut self, i: usize, g: u32) -> bool {
786 let Face::Syn(s) = &self.slots[i].face else { return false };
787 let (base, syn, strength, serial) = (s.base, s.syn, s.strength, s.serial);
788 let have = match self.slot_idx(base) {
789 None => false,
790 Some(bi) => match &self.slots[bi].face {
791 Face::Sgf(f) => {
792 self.ol.reset();
793 f.outline(g, 0, 0, 0, &mut self.ol);
794 true
795 }
796 Face::Tt(t) => t.bbox(g, &mut self.ol).is_some(),
797 Face::Var(_) => self.var_prep(bi, g),
798 _ => false,
799 },
800 };
801 if !have || self.ol.npts() == 0 {
802 self.ol.reset();
803 self.ol.owner_set(serial, g);
804 return false;
805 }
806 if syn & FS_SYN_BOLD != 0 {
807 self.ol.embolden(strength);
808 }
809 if syn & FS_SYN_ITALIC != 0 {
810 self.ol.shear(F_TAN12);
811 }
812 self.ol.owner_set(serial, g);
813 true
814 }
815
816 fn syn_box(&mut self, i: usize, g: u32) -> Option<[i32; 4]> {
818 if !self.syn_prep(i, g) {
819 return None;
820 }
821 let mut b = self.ol.bbox()?;
822 let Face::Syn(s) = &self.slots[i].face else { return Some(b) };
823 if s.syn & FS_SHARP != 0 {
824 let grow = ((s.fm.upem as u32 >> 4) + 2) as i32;
826 b[1] = b[1].wrapping_sub(grow);
827 b[3] = b[3].wrapping_add(grow);
828 }
829 Some(b)
830 }
831
832 fn syn_path(&mut self, i: usize, g: u32) {
834 let serial = match &self.slots[i].face {
835 Face::Syn(s) => s.serial,
836 _ => return,
837 };
838 if !self.ol.owner_is(serial, g) {
839 self.syn_prep(i, g);
840 }
841 if self.ol.npts() == 0 {
842 return;
843 }
844 let Face::Syn(s) = &self.slots[i].face else { return };
845 if s.syn & FS_SHARP != 0 {
846 let zn = Zones::fit(s.fm.desc, s.fm.xh, s.fm.caph, s.fm.asc, self.gp.sy);
847 self.ol.emit(&mut self.path, &self.gp, Some(&zn));
848 } else {
849 self.ol.emit(&mut self.path, &self.gp, None);
850 }
851 }
852}