1use std::cell::RefCell;
6use std::collections::HashMap;
7use std::rc::Rc;
8
9use log::warn;
10use servo::{
11 EmbedderControl, EmbedderControlId, SimpleDialog, WebDriverCommandMsg, WebDriverUserPrompt,
12 WebDriverUserPromptAction, WebViewId,
13};
14use url::Url;
15
16use crate::running_app_state::RunningAppState;
17
18#[derive(Default)]
19pub(crate) struct WebDriverEmbedderControls {
20 embedder_controls: RefCell<HashMap<WebViewId, Vec<EmbedderControl>>>,
21}
22
23impl WebDriverEmbedderControls {
24 pub(crate) fn show_embedder_control(
25 &self,
26 webview_id: WebViewId,
27 embedder_control: EmbedderControl,
28 ) {
29 self.embedder_controls
30 .borrow_mut()
31 .entry(webview_id)
32 .or_default()
33 .push(embedder_control)
34 }
35
36 pub(crate) fn hide_embedder_control(
37 &self,
38 webview_id: WebViewId,
39 embedder_control_id: EmbedderControlId,
40 ) {
41 let mut embedder_controls = self.embedder_controls.borrow_mut();
42 if let Some(controls) = embedder_controls.get_mut(&webview_id) {
43 controls.retain(|control| control.id() != embedder_control_id);
44 }
45 embedder_controls.retain(|_, controls| !controls.is_empty());
46 }
47
48 pub(crate) fn current_active_dialog_webdriver_type(
49 &self,
50 webview_id: WebViewId,
51 ) -> Option<WebDriverUserPrompt> {
52 let embedder_controls = self.embedder_controls.borrow();
59 match embedder_controls.get(&webview_id)?.last()? {
60 EmbedderControl::SimpleDialog(SimpleDialog::Alert(..)) => {
61 Some(WebDriverUserPrompt::Alert)
62 },
63 EmbedderControl::SimpleDialog(SimpleDialog::Confirm(..)) => {
64 Some(WebDriverUserPrompt::Confirm)
65 },
66 EmbedderControl::SimpleDialog(SimpleDialog::Prompt(..)) => {
67 Some(WebDriverUserPrompt::Prompt)
68 },
69 EmbedderControl::FilePicker { .. } => Some(WebDriverUserPrompt::File),
70 EmbedderControl::SelectElement { .. } => Some(WebDriverUserPrompt::Default),
71 _ => None,
72 }
73 }
74
75 pub(crate) fn respond_to_active_simple_dialog(
79 &self,
80 webview_id: WebViewId,
81 action: WebDriverUserPromptAction,
82 ) -> Result<String, ()> {
83 let mut embedder_controls = self.embedder_controls.borrow_mut();
84 let Some(controls) = embedder_controls.get_mut(&webview_id) else {
85 return Err(());
86 };
87 let Some(&EmbedderControl::SimpleDialog(simple_dialog)) = controls.last().as_ref() else {
88 return Err(());
89 };
90
91 let result_text = simple_dialog.message().to_owned();
92 if action == WebDriverUserPromptAction::Ignore {
93 return Ok(result_text);
94 }
95
96 let Some(EmbedderControl::SimpleDialog(simple_dialog)) = controls.pop() else {
97 return Err(());
98 };
99 match action {
100 WebDriverUserPromptAction::Accept => simple_dialog.confirm(),
101 WebDriverUserPromptAction::Dismiss => simple_dialog.dismiss(),
102 WebDriverUserPromptAction::Ignore => unreachable!("Should have returned early above"),
103 }
104 Ok(result_text)
105 }
106
107 pub(crate) fn message_of_newest_dialog(&self, webview_id: WebViewId) -> Option<String> {
108 let embedder_controls = self.embedder_controls.borrow();
109 match embedder_controls.get(&webview_id)?.last()? {
110 EmbedderControl::SimpleDialog(simple_dialog) => Some(simple_dialog.message().into()),
111 _ => None,
112 }
113 }
114
115 pub(crate) fn set_prompt_value_of_newest_dialog(&self, webview_id: WebViewId, text: String) {
116 let mut embedder_controls = self.embedder_controls.borrow_mut();
117 let Some(controls) = embedder_controls.get_mut(&webview_id) else {
118 return;
119 };
120 let Some(&mut EmbedderControl::SimpleDialog(SimpleDialog::Prompt(ref mut prompt_dialog))) =
121 controls.last_mut()
122 else {
123 return;
124 };
125 prompt_dialog.set_current_value(&text);
126 }
127}
128
129impl RunningAppState {
130 pub(crate) fn handle_webdriver_messages(self: &Rc<Self>) {
131 let Some(webdriver_receiver) = self.webdriver_receiver() else {
132 return;
133 };
134
135 while let Ok(msg) = webdriver_receiver.try_recv() {
136 match msg {
137 WebDriverCommandMsg::ResetAllCookies(sender) => {
138 self.servo().clear_cookies();
139 let _ = sender.send(());
140 },
141 WebDriverCommandMsg::Shutdown => {
142 self.schedule_exit();
143 },
144 WebDriverCommandMsg::IsWebViewOpen(webview_id, sender) => {
145 let context = self.webview_by_id(webview_id);
146
147 if let Err(error) = sender.send(context.is_some()) {
148 warn!("Failed to send response of IsWebViewOpen: {error}");
149 }
150 },
151 WebDriverCommandMsg::IsBrowsingContextOpen(..) => {
152 self.servo().execute_webdriver_command(msg);
153 },
154 WebDriverCommandMsg::NewWebView(response_sender, load_status_sender) => {
155 let new_webview = self
156 .any_window()
157 .create_toplevel_webview(self.clone(), Url::parse("about:blank").unwrap());
158
159 if let Err(error) = response_sender.send(new_webview.id()) {
160 warn!("Failed to send response of NewWebview: {error}");
161 }
162 if let Some(load_status_sender) = load_status_sender {
163 self.set_load_status_sender(new_webview.id(), load_status_sender);
164 }
165 },
166 WebDriverCommandMsg::CloseWebView(webview_id, response_sender) => {
167 self.window_for_webview_id(webview_id)
168 .close_webview(webview_id);
169 if let Err(error) = response_sender.send(()) {
170 warn!("Failed to send response of CloseWebView: {error}");
171 }
172 },
173 WebDriverCommandMsg::FocusWebView(webview_id) => {
174 self.window_for_webview_id(webview_id)
175 .activate_webview(webview_id);
176 },
177 WebDriverCommandMsg::FocusBrowsingContext(..) => {
178 self.servo().execute_webdriver_command(msg);
179 },
180 WebDriverCommandMsg::GetAllWebViews(response_sender) => {
181 let webviews = self
182 .windows()
183 .values()
184 .flat_map(|window| window.webview_ids())
185 .collect();
186 if let Err(error) = response_sender.send(webviews) {
187 warn!("Failed to send response of GetAllWebViews: {error}");
188 }
189 },
190 WebDriverCommandMsg::GetWindowRect(webview_id, response_sender) => {
191 let platform_window = self.platform_window_for_webview_id(webview_id);
192 if let Err(error) = response_sender.send(platform_window.window_rect()) {
193 warn!("Failed to send response of GetWindowSize: {error}");
194 }
195 },
196 WebDriverCommandMsg::MaximizeWebView(webview_id, response_sender) => {
197 let Some(webview) = self.webview_by_id(webview_id) else {
198 continue;
199 };
200 let platform_window = self.platform_window_for_webview_id(webview_id);
201 platform_window.maximize(&webview);
202
203 if let Err(error) = response_sender.send(platform_window.window_rect()) {
204 warn!("Failed to send response of GetWindowSize: {error}");
205 }
206 },
207 WebDriverCommandMsg::SetWindowRect(webview_id, requested_rect, size_sender) => {
208 let Some(webview) = self.webview_by_id(webview_id) else {
209 continue;
210 };
211
212 let platform_window = self.platform_window_for_webview_id(webview_id);
213 let scale = platform_window.hidpi_scale_factor();
214
215 let requested_physical_rect =
216 (requested_rect.to_f32() * scale).round().to_i32();
217
218 platform_window.request_resize(&webview, requested_physical_rect.size());
220
221 platform_window.set_position(requested_physical_rect.min);
223
224 if let Err(error) = size_sender.send(platform_window.window_rect()) {
225 warn!("Failed to send window size: {error}");
226 }
227 },
228 WebDriverCommandMsg::GetViewportSize(webview_id, response_sender) => {
229 let platform_window = self.platform_window_for_webview_id(webview_id);
230 let size = platform_window.rendering_context().size2d();
231 if let Err(error) = response_sender.send(size) {
232 warn!("Failed to send response of GetViewportSize: {error}");
233 }
234 },
235 WebDriverCommandMsg::GetFocusedWebView(sender) => {
237 let active_webview = self.any_window().active_webview();
238 if let Err(error) = sender.send(active_webview.map(|w| w.id())) {
239 warn!("Failed to send response of GetFocusedWebView: {error}");
240 };
241 },
242 WebDriverCommandMsg::LoadUrl(webview_id, url, load_status_sender) => {
243 self.handle_webdriver_load_url(webview_id, url, load_status_sender);
244 },
245 WebDriverCommandMsg::Refresh(webview_id, load_status_sender) => {
246 if let Some(webview) = self.webview_by_id(webview_id) {
247 self.set_load_status_sender(webview_id, load_status_sender);
248 webview.reload();
249 }
250 },
251 WebDriverCommandMsg::GoBack(webview_id, load_status_sender) => {
252 if let Some(webview) = self.webview_by_id(webview_id) {
253 let traversal_id = webview.go_back(1);
254 self.set_pending_traversal(traversal_id, load_status_sender);
255 }
256 },
257 WebDriverCommandMsg::GoForward(webview_id, load_status_sender) => {
258 if let Some(webview) = self.webview_by_id(webview_id) {
259 let traversal_id = webview.go_forward(1);
260 self.set_pending_traversal(traversal_id, load_status_sender);
261 }
262 },
263 WebDriverCommandMsg::InputEvent(webview_id, input_event, response_sender) => {
264 self.handle_webdriver_input_event(webview_id, input_event, response_sender);
265 },
266 WebDriverCommandMsg::ScriptCommand(_, ref webdriver_script_command) => {
267 self.handle_webdriver_script_command(webdriver_script_command);
268 self.servo().execute_webdriver_command(msg);
269 },
270 WebDriverCommandMsg::CurrentUserPrompt(webview_id, response_sender) => {
271 let current_dialog = self
272 .webdriver_embedder_controls
273 .current_active_dialog_webdriver_type(webview_id);
274 if let Err(error) = response_sender.send(current_dialog) {
275 warn!("Failed to send response of CurrentUserPrompt: {error}");
276 };
277 },
278 WebDriverCommandMsg::HandleUserPrompt(webview_id, action, response_sender) => {
279 let controls = &self.webdriver_embedder_controls;
280 let result = controls.respond_to_active_simple_dialog(webview_id, action);
281 if let Err(error) = response_sender.send(result) {
282 warn!("Failed to send response of HandleUserPrompt: {error}");
283 };
284 },
285 WebDriverCommandMsg::GetAlertText(webview_id, response_sender) => {
286 let response = match self
287 .webdriver_embedder_controls
288 .message_of_newest_dialog(webview_id)
289 {
290 Some(text) => Ok(text),
291 None => Err(()),
292 };
293
294 if let Err(error) = response_sender.send(response) {
295 warn!("Failed to send response of GetAlertText: {error}");
296 };
297 },
298 WebDriverCommandMsg::SendAlertText(webview_id, text) => {
299 self.webdriver_embedder_controls
300 .set_prompt_value_of_newest_dialog(webview_id, text);
301 },
302 WebDriverCommandMsg::TakeScreenshot(webview_id, rect, result_sender) => {
303 self.handle_webdriver_screenshot(webview_id, rect, result_sender);
304 },
305 };
306 }
307 }
308}