blockworx_canvas2d/
glyphs.rs1use std::cell::RefCell;
11use std::collections::HashMap;
12
13use blockworx_geom::WorldPx;
14use blockworx_paint::text::{GlyphId, Layout, TextLayout};
15use blockworx_paint::{Font, FontChoice};
16use blockworx_text::{Metrics, Outlines, PathCommand, Shaper};
17use web_sys::Path2d;
18
19pub struct Glyphs {
22 shaper: Shaper,
23 outlines: Outlines,
24 inked: RefCell<HashMap<GlyphId, Option<Path2d>>>,
27}
28
29impl Glyphs {
30 #[must_use]
31 pub fn new(typeface: FontChoice) -> Self {
32 Self {
33 shaper: Shaper::new(typeface),
34 outlines: Outlines::new(typeface),
35 inked: RefCell::default(),
36 }
37 }
38
39 #[must_use]
41 pub fn metrics(&self) -> Metrics {
42 self.shaper.metrics()
43 }
44
45 #[must_use]
48 pub fn glyph_index(&self, chr: char) -> Option<GlyphId> {
49 self.outlines.glyph_index(chr)
50 }
51
52 #[must_use]
55 pub fn path(&self, id: GlyphId) -> Option<Path2d> {
56 if let Some(inked) = self.inked.borrow().get(&id) {
57 return inked.clone();
58 }
59 let path = trace(&self.outlines.outline(id));
60 self.inked.borrow_mut().insert(id, path.clone());
61 path
62 }
63}
64
65impl TextLayout for Glyphs {
66 fn typeface(&self) -> FontChoice {
67 self.shaper.typeface()
68 }
69
70 fn layout(&self, text: &str, font: &Font, wrap: WorldPx) -> Layout {
71 self.shaper.layout(text, font, wrap)
72 }
73}
74
75fn trace(outline: &[PathCommand]) -> Option<Path2d> {
76 if outline.is_empty() {
77 return None;
78 }
79 let path = Path2d::new().ok()?;
80 for command in outline {
81 match *command {
82 PathCommand::MoveTo(to) => path.move_to(to.x.into(), to.y.into()),
83 PathCommand::LineTo(to) => path.line_to(to.x.into(), to.y.into()),
84 PathCommand::QuadTo(control, to) => path.quadratic_curve_to(
85 control.x.into(),
86 control.y.into(),
87 to.x.into(),
88 to.y.into(),
89 ),
90 PathCommand::CurveTo(first, second, to) => path.bezier_curve_to(
91 first.x.into(),
92 first.y.into(),
93 second.x.into(),
94 second.y.into(),
95 to.x.into(),
96 to.y.into(),
97 ),
98 PathCommand::Close => path.close_path(),
99 }
100 }
101 Some(path)
102}