piet_web/text/
grapheme.rs1use piet::HitTestPoint;
5use unicode_segmentation::UnicodeSegmentation;
6use web_sys::CanvasRenderingContext2d;
7
8use super::hit_test_line_position;
9
10pub(crate) fn get_grapheme_boundaries(
18 ctx: &CanvasRenderingContext2d,
19 text: &str,
20 grapheme_position: usize,
21) -> Option<GraphemeBoundaries> {
22 let mut graphemes = UnicodeSegmentation::grapheme_indices(text, true);
23 let (text_position, _) = graphemes.nth(grapheme_position)?;
24 let (next_text_position, _) = graphemes.next().unwrap_or((text.len(), ""));
25
26 let curr_edge = hit_test_line_position(ctx, text, text_position);
27 let next_edge = hit_test_line_position(ctx, text, next_text_position);
28
29 let res = GraphemeBoundaries {
30 curr_idx: text_position,
31 next_idx: next_text_position,
32 leading: curr_edge,
33 trailing: next_edge,
34 };
35
36 Some(res)
37}
38
39pub(crate) fn point_x_in_grapheme(
40 point_x: f64,
41 grapheme_boundaries: &GraphemeBoundaries,
42) -> Option<HitTestPoint> {
43 let leading = grapheme_boundaries.leading;
44 let trailing = grapheme_boundaries.trailing;
45 let curr_idx = grapheme_boundaries.curr_idx;
46 let next_idx = grapheme_boundaries.next_idx;
47
48 if point_x >= leading && point_x <= trailing {
49 let midpoint = leading + ((trailing - leading) / 2.0);
52 let is_inside = true;
53 let idx = if point_x >= midpoint {
54 next_idx
55 } else {
56 curr_idx
57 };
58 Some(HitTestPoint::new(idx, is_inside))
59 } else {
60 None
61 }
62}
63
64#[derive(Debug, Default, PartialEq)]
65pub(crate) struct GraphemeBoundaries {
66 pub curr_idx: usize,
67 pub next_idx: usize,
68 pub leading: f64,
69 pub trailing: f64,
71}