compositing/
refresh_driver.rs1use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::thread::{self, JoinHandle};
10use std::time::Duration;
11
12use constellation_traits::EmbedderToConstellationMessage;
13use crossbeam_channel::{Sender, select};
14use embedder_traits::{EventLoopWaker, RefreshDriver};
15use log::warn;
16use timers::{BoxedTimerCallback, TimerEventRequest, TimerScheduler};
17
18use crate::painter::Painter;
19use crate::webview_renderer::WebViewRenderer;
20
21pub(crate) struct BaseRefreshDriver {
27 waiting_for_frame: Arc<AtomicBool>,
30 event_loop_waker: Box<dyn EventLoopWaker>,
32 observers: RefCell<Vec<Rc<dyn RefreshDriverObserver>>>,
34 refresh_driver: Rc<dyn RefreshDriver>,
37}
38
39impl BaseRefreshDriver {
40 pub(crate) fn new(
41 event_loop_waker: Box<dyn EventLoopWaker>,
42 refresh_driver: Option<Rc<dyn RefreshDriver>>,
43 ) -> Self {
44 let refresh_driver =
45 refresh_driver.unwrap_or_else(|| Rc::new(TimerRefreshDriver::default()));
46 Self {
47 waiting_for_frame: Arc::new(AtomicBool::new(false)),
48 event_loop_waker,
49 observers: Default::default(),
50 refresh_driver,
51 }
52 }
53
54 pub(crate) fn add_observer(&self, observer: Rc<dyn RefreshDriverObserver>) {
55 let mut observers = self.observers.borrow_mut();
56 observers.push(observer);
57
58 if observers.len() == 1 {
60 self.observe_next_frame();
61 }
62 }
63
64 pub(crate) fn notify_will_paint(&self, painter: &mut Painter) {
65 let still_has_observers = {
67 let mut observers = self.observers.borrow_mut();
68 observers.retain(|observer| observer.frame_started(painter));
69 !observers.is_empty()
70 };
71
72 if still_has_observers {
73 self.observe_next_frame();
74 }
75 }
76
77 fn observe_next_frame(&self) {
78 self.waiting_for_frame.store(true, Ordering::Relaxed);
79
80 let waiting_for_frame = self.waiting_for_frame.clone();
81 let event_loop_waker = self.event_loop_waker.clone_box();
82 self.refresh_driver.observe_next_frame(Box::new(move || {
83 waiting_for_frame.store(false, Ordering::Relaxed);
84 event_loop_waker.wake();
85 }));
86 }
87
88 pub(crate) fn wait_to_paint(&self) -> bool {
92 !self.observers.borrow().is_empty() && self.waiting_for_frame.load(Ordering::Relaxed)
93 }
94}
95
96pub(crate) trait RefreshDriverObserver {
101 fn frame_started(&self, painter: &mut Painter) -> bool;
105}
106
107pub(crate) struct AnimationRefreshDriverObserver {
112 pub(crate) constellation_sender: Sender<EmbedderToConstellationMessage>,
114
115 pub(crate) animating: Cell<bool>,
117}
118
119impl AnimationRefreshDriverObserver {
120 pub(crate) fn new(constellation_sender: Sender<EmbedderToConstellationMessage>) -> Self {
121 Self {
122 constellation_sender,
123 animating: Default::default(),
124 }
125 }
126
127 pub(crate) fn notify_animation_state_changed(
128 &self,
129 webview_renderer: &WebViewRenderer,
130 ) -> bool {
131 if !webview_renderer.animating() {
132 return false;
135 }
136
137 if let Err(error) =
138 self.constellation_sender
139 .send(EmbedderToConstellationMessage::TickAnimation(vec![
140 webview_renderer.id,
141 ]))
142 {
143 warn!("Sending tick to constellation failed ({error:?}).");
144 }
145
146 if self.animating.get() {
147 return false;
148 }
149
150 self.animating.set(true);
151 true
152 }
153}
154
155impl RefreshDriverObserver for AnimationRefreshDriverObserver {
156 fn frame_started(&self, painter: &mut Painter) -> bool {
157 let animating_webviews = painter.animating_webviews();
159
160 if animating_webviews.is_empty() {
163 self.animating.set(false);
164 return false;
165 }
166
167 if let Err(error) =
169 self.constellation_sender
170 .send(EmbedderToConstellationMessage::TickAnimation(
171 animating_webviews,
172 ))
173 {
174 warn!("Sending tick to constellation failed ({error:?}).");
175 return false;
176 }
177
178 self.animating.set(true);
179 true
180 }
181}
182
183enum TimerThreadMessage {
184 Request(TimerEventRequest),
185 Quit,
186}
187
188struct TimerRefreshDriver {
197 sender: Sender<TimerThreadMessage>,
198 join_handle: Option<JoinHandle<()>>,
199}
200
201impl Default for TimerRefreshDriver {
202 fn default() -> Self {
203 let (sender, receiver) = crossbeam_channel::unbounded::<TimerThreadMessage>();
204 let join_handle = thread::Builder::new()
205 .name(String::from("CompositorTimerThread"))
206 .spawn(move || {
207 let mut scheduler = TimerScheduler::default();
208
209 loop {
210 select! {
211 recv(receiver) -> message => {
212 match message {
213 Ok(TimerThreadMessage::Request(request)) => {
214 scheduler.schedule_timer(request);
215 },
216 _ => return,
217 }
218 },
219 recv(scheduler.wait_channel()) -> _message => {
220 scheduler.dispatch_completed_timers();
221 },
222 };
223 }
224 })
225 .expect("Could not create RefreshDriver timer thread.");
226
227 Self {
228 sender,
229 join_handle: Some(join_handle),
230 }
231 }
232}
233
234impl TimerRefreshDriver {
235 fn queue_timer(&self, duration: Duration, callback: BoxedTimerCallback) {
236 let _ = self
237 .sender
238 .send(TimerThreadMessage::Request(TimerEventRequest {
239 callback,
240 duration,
241 }));
242 }
243}
244
245impl RefreshDriver for TimerRefreshDriver {
246 fn observe_next_frame(&self, new_start_frame_callback: Box<dyn Fn() + Send + 'static>) {
247 const FRAME_DURATION: Duration = Duration::from_millis(1000 / 120);
248 self.queue_timer(FRAME_DURATION, new_start_frame_callback);
249 }
250}
251
252impl Drop for TimerRefreshDriver {
253 fn drop(&mut self) {
254 let _ = self.sender.send(TimerThreadMessage::Quit);
255 if let Some(join_handle) = self.join_handle.take() {
256 let _ = join_handle.join();
257 }
258 }
259}