zeno/
hit_test.rs

1//! Hit testing.
2
3use super::geometry::{Point, Transform};
4use super::mask::Mask;
5use super::path_data::PathData;
6use super::scratch::Scratch;
7use super::style::{Fill, Style};
8
9use core::cell::RefCell;
10
11/// Builder for configuring and executing a hit test.
12pub struct HitTest<'a, 's, D> {
13    data: D,
14    style: Style<'a>,
15    transform: Option<Transform>,
16    threshold: u8,
17    scratch: RefCell<Option<&'s mut Scratch>>,
18}
19
20impl<'a, 's, D> HitTest<'a, 's, D>
21where
22    D: PathData,
23{
24    /// Creates a new hit test builder for the specified path data.
25    pub fn new(data: D) -> Self {
26        Self {
27            data,
28            style: Style::Fill(Fill::NonZero),
29            transform: None,
30            threshold: 0,
31            scratch: RefCell::new(None),
32        }
33    }
34
35    /// Creates a new hit test builder for the specified path data and scratch memory.
36    pub fn with_scratch(data: D, scratch: &'s mut Scratch) -> Self {
37        Self {
38            data,
39            style: Style::Fill(Fill::NonZero),
40            transform: None,
41            threshold: 0,
42            scratch: RefCell::new(Some(scratch)),
43        }
44    }
45
46    /// Sets the style of the path.
47    pub fn style(&mut self, style: impl Into<Style<'a>>) -> &mut Self {
48        self.style = style.into();
49        self
50    }
51
52    /// Sets the transformation matrix of the path.
53    pub fn transform(&mut self, transform: Option<Transform>) -> &mut Self {
54        self.transform = transform;
55        self
56    }
57
58    /// Sets the threshold value for determining whether a hit test registers.
59    pub fn threshold(&mut self, threshold: u8) -> &mut Self {
60        self.threshold = threshold;
61        self
62    }
63
64    /// Returns true if the specified point is painted by the path.
65    pub fn test(&self, point: impl Into<Point>) -> bool {
66        let mut scratch = self.scratch.borrow_mut();
67        let mut buf = [0u8; 1];
68        let p = point.into() * -1.;
69        if let Some(scratch) = scratch.as_mut() {
70            Mask::with_scratch(&self.data, scratch)
71                .style(self.style)
72                .offset(p)
73                .transform(self.transform)
74                .size(1, 1)
75                .render_into(&mut buf, None);
76        } else {
77            Mask::new(&self.data)
78                .style(self.style)
79                .offset(p)
80                .transform(self.transform)
81                .size(1, 1)
82                .render_into(&mut buf, None);
83        }
84        if self.threshold == 0xFF {
85            buf[0] >= self.threshold
86        } else {
87            buf[0] > self.threshold
88        }
89    }
90}