long_screen/kernels/
chrome.rs1use crate::kernels::geometry::{js_ceil, js_floor, js_round, Rect};
7
8#[derive(Clone, Copy, PartialEq, Eq)]
9pub enum Axis {
10 X,
11 Y,
12}
13
14#[derive(Clone, Copy, PartialEq, Eq)]
15pub enum Choose {
16 First,
17 Last,
18}
19
20#[allow(clippy::too_many_arguments)]
24pub fn stationary_boundary(
25 rgba: &[u8],
26 width: usize,
27 height: usize,
28 axis: Axis,
29 from: f64,
30 to: f64,
31 cross_from: f64,
32 cross_to: f64,
33 choose: Choose,
34) -> Option<f64> {
35 let (w, h) = (width as i64, height as i64);
36 let limit = if axis == Axis::X { w } else { h };
37 let cross_limit = if axis == Axis::X { h } else { w };
38 let step = (((cross_to - cross_from) / 160.0).floor() as i64).max(1);
40 let mut found = None;
41 let mut v = if from > 1.0 { from } else { 1.0 };
44 let v_end = (limit as f64).min(to + 1.0);
45 let c_start = (cross_from + 2.0).max(0.0);
46 let c_end = (cross_limit as f64).min(cross_to - 2.0);
47 while v < v_end {
48 let (mut strong, mut count, mut sum) = (0u32, 0u32, 0.0f64);
49 let mut poisoned = false;
53 let mut c = c_start;
54 while c < c_end {
55 let (px, py) = if axis == Axis::X { (v, c) } else { (c, v) };
56 let idx = (py * w as f64 + px) * 4.0;
57 if idx.fract() != 0.0 {
58 poisoned = true;
59 break;
60 }
61 let i = idx as usize;
62 let j = if axis == Axis::X {
63 i - 4
64 } else {
65 i - (w as usize) * 4
66 };
67 let d = ((rgba[i] as i32 - rgba[j] as i32).abs()
68 + (rgba[i + 1] as i32 - rgba[j + 1] as i32).abs()
69 + (rgba[i + 2] as i32 - rgba[j + 2] as i32).abs()) as f64
70 / 3.0;
71 if d > 3.0 {
72 strong += 1;
73 }
74 sum += d;
75 count += 1;
76 c += step as f64;
77 }
78 if !poisoned && count > 0 && strong as f64 / count as f64 > 0.68 && sum / count as f64 > 3.0
79 {
80 found = Some(v);
82 if choose == Choose::First {
83 break;
84 }
85 }
86 v += 1.0;
87 }
88 found
89}
90
91#[allow(clippy::too_many_arguments)]
94pub fn sticky_occlusions(
95 previous: &[u8],
96 current: &[u8],
97 width: usize,
98 height: usize,
99 region: Rect,
100 motion_x: f64,
101 motion_y: f64,
102 carry_in: &[Rect],
103) -> Vec<Rect> {
104 let (w, h) = (width as i64, height as i64);
105 let carry: Vec<Rect> = carry_in
108 .iter()
109 .copied()
110 .filter(|o| {
111 if o.x < 0.0 || o.y < 0.0 || o.x + o.width > w as f64 || o.y + o.height > h as f64 {
112 return false;
113 }
114 let y_end = o.y + o.height;
115 let mut y = o.y.ceil();
116 while y < y_end {
117 let start = ((y as i64 * w) as f64 + (o.x).ceil()) as usize * 4;
118 let end = ((y as i64 * w) as f64 + (o.x + o.width).ceil()) as usize * 4;
119 if previous[start..end] != current[start..end] {
120 return false;
121 }
122 y += 1.0;
123 }
124 true
125 })
126 .collect();
127 if crate::kernels::geometry::js_hypot(motion_x, motion_y) < 2.0 {
128 return carry;
129 }
130 let r = region;
131 let (dx, dy) = (js_round(motion_x) as i64, js_round(motion_y) as i64);
132 let end = (h - 2).min(js_floor(r.y + (288.0f64).min(r.height * 0.23)) as i64);
133 let start = 2i64.max(js_floor(r.y) as i64);
134 let step = 1i64.max(js_floor(r.width / 700.0) as i64);
135 let (mut last_fixed, mut strong_rows, mut matched) = (-1i64, 0u32, 0u32);
136 let x_start = 2i64.max(js_ceil(r.x) as i64);
137 let x_end = (w - 2) as f64;
138 for y in start..end {
139 if y + dy < 2 || y + dy >= h - 2 {
140 continue;
141 }
142 let (mut n, mut zero, mut shifted) = (0u32, 0i64, 0i64);
143 let mut x = x_start;
144 while (x as f64) < x_end.min(r.x + r.width) {
146 if x + dx < 2 || x + dx >= w - 2 {
147 x += step;
148 continue;
149 }
150 let i = ((y * w + x) * 4) as usize;
151 if (current[i - 4] as i32 - current[i + 4] as i32).abs() < 24 {
152 x += step;
153 continue;
154 }
155 let j = (((y + dy) * w + x + dx) * 4) as usize;
156 zero += (previous[i] as i64 - current[i] as i64).abs();
157 shifted += (previous[j] as i64 - current[i] as i64).abs();
158 n += 1;
159 x += step;
160 }
161 let nf = n as f64;
162 if n >= 8 && (zero as f64) / nf < 6.0 && (shifted as f64) / nf > 18.0 {
163 last_fixed = y;
164 strong_rows += 1;
165 matched += n;
166 }
167 }
168 if strong_rows < 4 || matched < 64 || last_fixed < 0 {
169 return carry;
170 }
171 let edge = stationary_boundary(
172 current,
173 width,
174 height,
175 Axis::Y,
176 (last_fixed + 1) as f64,
177 (end.min(last_fixed + 80)) as f64,
178 r.x,
179 r.x + r.width,
180 Choose::First,
181 );
182 match edge {
183 Some(edge) if edge - start as f64 <= r.height * 0.23 => vec![Rect {
184 x: r.x,
185 y: r.y,
186 width: r.width,
187 height: edge - r.y + 1.0,
188 }],
189 _ => carry,
190 }
191}