1use std::path::PathBuf;
6use std::rc::Rc;
7
8#[cfg(feature = "gamepad")]
9use embedder_traits::GamepadHapticEffectType;
10use embedder_traits::{
11 AlertResponse, AllowOrDeny, AuthenticationResponse, BluetoothDeviceDescription,
12 ConfirmResponse, ConsoleLogLevel, ContextMenuAction, ContextMenuElementInformation,
13 ContextMenuItem, Cursor, EmbedderControlId, EmbedderControlResponse, FilePickerRequest,
14 FilterPattern, InputEventId, InputEventResult, InputMethodType, LoadStatus, MediaSessionEvent,
15 NewWebViewDetails, Notification, PermissionFeature, PromptResponse, RgbColor, ScreenGeometry,
16 SelectElementOptionOrOptgroup, SimpleDialogRequest, TraversalId, WebResourceRequest,
17 WebResourceResponse, WebResourceResponseMsg,
18};
19use paint_api::rendering_context::RenderingContext;
20use servo_base::generic_channel::{GenericSender, SendError};
21use servo_base::id::PipelineId;
22use servo_constellation_traits::EmbedderToConstellationMessage;
23use tokio::sync::mpsc::UnboundedSender as TokioSender;
24use tokio::sync::oneshot::Sender;
25use url::Url;
26use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
27
28use crate::proxies::ConstellationProxy;
29use crate::responders::{IpcResponder, OneshotSender, ServoErrorSender};
30use crate::{RegisterOrUnregister, Servo, WebView, WebViewBuilder};
31
32pub struct NavigationRequest {
35 pub url: Url,
36 pub(crate) pipeline_id: PipelineId,
37 pub(crate) constellation_proxy: ConstellationProxy,
38 pub(crate) response_sent: bool,
39}
40
41impl NavigationRequest {
42 pub fn allow(mut self) {
43 self.constellation_proxy
44 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
45 self.pipeline_id,
46 true,
47 ));
48 self.response_sent = true;
49 }
50
51 pub fn deny(mut self) {
52 self.constellation_proxy
53 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
54 self.pipeline_id,
55 false,
56 ));
57 self.response_sent = true;
58 }
59}
60
61impl Drop for NavigationRequest {
62 fn drop(&mut self) {
63 if !self.response_sent {
64 self.constellation_proxy
65 .send(EmbedderToConstellationMessage::AllowNavigationResponse(
66 self.pipeline_id,
67 true,
68 ));
69 }
70 }
71}
72
73pub struct PermissionRequest {
77 pub(crate) requested_feature: PermissionFeature,
78 pub(crate) allow_deny_request: AllowOrDenyRequest,
79}
80
81impl PermissionRequest {
82 pub fn feature(&self) -> PermissionFeature {
83 self.requested_feature
84 }
85
86 pub fn allow(self) {
87 self.allow_deny_request.allow();
88 }
89
90 pub fn deny(self) {
91 self.allow_deny_request.deny();
92 }
93}
94
95pub struct AllowOrDenyRequest(IpcResponder<AllowOrDeny>, ServoErrorSender);
96
97impl AllowOrDenyRequest {
98 pub(crate) fn new(
99 response_sender: GenericSender<AllowOrDeny>,
100 default_response: AllowOrDeny,
101 error_sender: ServoErrorSender,
102 ) -> Self {
103 Self(
104 IpcResponder::new(response_sender, default_response),
105 error_sender,
106 )
107 }
108
109 pub fn allow(mut self) {
110 if let Err(error) = self.0.send(AllowOrDeny::Allow) {
111 self.1.raise_response_send_error(error);
112 }
113 }
114
115 pub fn deny(mut self) {
116 if let Err(error) = self.0.send(AllowOrDeny::Deny) {
117 self.1.raise_response_send_error(error);
118 }
119 }
120}
121
122#[derive(Clone, Debug, Eq, PartialEq)]
123pub struct ProtocolHandlerRegistration {
124 pub scheme: String,
125 pub url: Url,
126 pub register_or_unregister: RegisterOrUnregister,
127}
128
129pub struct BluetoothDeviceSelectionRequest {
131 devices: Vec<BluetoothDeviceDescription>,
132 responder: IpcResponder<Option<String>>,
133}
134
135impl BluetoothDeviceSelectionRequest {
136 pub(crate) fn new(
137 devices: Vec<BluetoothDeviceDescription>,
138 responder: GenericSender<Option<String>>,
139 ) -> Self {
140 Self {
141 devices,
142 responder: IpcResponder::new(responder, None),
143 }
144 }
145
146 pub fn pick_device(mut self, device: &BluetoothDeviceDescription) -> Result<(), SendError> {
148 self.responder.send(Some(device.address.clone()))
149 }
150
151 pub fn cancel(mut self) -> Result<(), SendError> {
153 self.responder.send(None)
154 }
155
156 pub fn devices(&self) -> &Vec<BluetoothDeviceDescription> {
158 &self.devices
159 }
160}
161
162pub struct AuthenticationRequest {
166 pub(crate) url: Url,
167 pub(crate) for_proxy: bool,
168 pub(crate) responder: IpcResponder<Option<AuthenticationResponse>>,
169 pub(crate) error_sender: ServoErrorSender,
170}
171
172impl AuthenticationRequest {
173 pub(crate) fn new(
174 url: Url,
175 for_proxy: bool,
176 response_sender: Sender<Option<AuthenticationResponse>>,
177 error_sender: ServoErrorSender,
178 ) -> Self {
179 Self {
180 url,
181 for_proxy,
182 responder: IpcResponder::new_same_process(
183 Box::new(OneshotSender::from(response_sender)),
184 None,
185 ),
186 error_sender,
187 }
188 }
189
190 pub fn url(&self) -> &Url {
192 &self.url
193 }
194 pub fn for_proxy(&self) -> bool {
196 self.for_proxy
197 }
198 pub fn authenticate(mut self, username: String, password: String) {
200 if let Err(error) = self
201 .responder
202 .send(Some(AuthenticationResponse { username, password }))
203 {
204 self.error_sender.raise_response_send_error(error);
205 }
206 }
207}
208
209pub struct WebResourceLoad {
213 pub request: WebResourceRequest,
214 pub(crate) responder: IpcResponder<WebResourceResponseMsg>,
215 pub(crate) error_sender: ServoErrorSender,
216}
217
218impl WebResourceLoad {
219 pub(crate) fn new(
220 web_resource_request: WebResourceRequest,
221 response_sender: TokioSender<WebResourceResponseMsg>,
222 error_sender: ServoErrorSender,
223 ) -> Self {
224 Self {
225 request: web_resource_request,
226 responder: IpcResponder::new_same_process(
227 Box::new(response_sender),
228 WebResourceResponseMsg::DoNotIntercept,
229 ),
230 error_sender,
231 }
232 }
233
234 pub fn request(&self) -> &WebResourceRequest {
236 &self.request
237 }
238 pub fn intercept(mut self, response: WebResourceResponse) -> InterceptedWebResourceLoad {
241 if let Err(error) = self.responder.send(WebResourceResponseMsg::Start(response)) {
242 self.error_sender.raise_response_send_error(error);
243 }
244 InterceptedWebResourceLoad {
245 request: self.request.clone(),
246 response_sender: self.responder,
247 finished: false,
248 error_sender: self.error_sender,
249 }
250 }
251}
252
253pub struct InterceptedWebResourceLoad {
259 pub request: WebResourceRequest,
260 pub(crate) response_sender: IpcResponder<WebResourceResponseMsg>,
261 pub(crate) finished: bool,
262 pub(crate) error_sender: ServoErrorSender,
263}
264
265impl InterceptedWebResourceLoad {
266 pub fn send_body_data(&mut self, data: Vec<u8>) {
269 if let Err(error) = self
270 .response_sender
271 .send(WebResourceResponseMsg::SendBodyData(data))
272 {
273 self.error_sender.raise_response_send_error(error);
274 }
275 }
276 pub fn finish(mut self) {
278 if let Err(error) = self
279 .response_sender
280 .send(WebResourceResponseMsg::FinishLoad)
281 {
282 self.error_sender.raise_response_send_error(error);
283 }
284 self.finished = true;
285 }
286 pub fn cancel(mut self) {
288 if let Err(error) = self
289 .response_sender
290 .send(WebResourceResponseMsg::CancelLoad)
291 {
292 self.error_sender.raise_response_send_error(error);
293 }
294 self.finished = true;
295 }
296}
297
298impl Drop for InterceptedWebResourceLoad {
299 fn drop(&mut self) {
300 if !self.finished {
301 if let Err(error) = self
302 .response_sender
303 .send(WebResourceResponseMsg::FinishLoad)
304 {
305 self.error_sender.raise_response_send_error(error);
306 }
307 }
308 }
309}
310
311pub enum EmbedderControl {
313 SelectElement(SelectElement),
315 ColorPicker(ColorPicker),
317 FilePicker(FilePicker),
319 InputMethod(InputMethodControl),
322 SimpleDialog(SimpleDialog),
327 ContextMenu(ContextMenu),
331}
332
333impl EmbedderControl {
334 pub fn id(&self) -> EmbedderControlId {
335 match self {
336 EmbedderControl::SelectElement(select_element) => select_element.id,
337 EmbedderControl::ColorPicker(color_picker) => color_picker.id,
338 EmbedderControl::FilePicker(file_picker) => file_picker.id,
339 EmbedderControl::InputMethod(input_method) => input_method.id,
340 EmbedderControl::SimpleDialog(simple_dialog) => simple_dialog.id(),
341 EmbedderControl::ContextMenu(context_menu) => context_menu.id,
342 }
343 }
344}
345
346pub struct ContextMenu {
348 pub(crate) id: EmbedderControlId,
349 pub(crate) position: DeviceIntRect,
350 pub(crate) items: Vec<ContextMenuItem>,
351 pub(crate) element_info: ContextMenuElementInformation,
352 pub(crate) response_sent: bool,
353 pub(crate) constellation_proxy: ConstellationProxy,
354}
355
356impl ContextMenu {
357 pub fn id(&self) -> EmbedderControlId {
359 self.id
360 }
361
362 pub fn position(&self) -> DeviceIntRect {
366 self.position
367 }
368
369 pub fn element_info(&self) -> &ContextMenuElementInformation {
372 &self.element_info
373 }
374
375 pub fn items(&self) -> &[ContextMenuItem] {
377 &self.items
378 }
379
380 pub fn select(mut self, action: ContextMenuAction) {
382 self.constellation_proxy
383 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
384 self.id,
385 EmbedderControlResponse::ContextMenu(Some(action)),
386 ));
387 self.response_sent = true;
388 }
389
390 pub fn dismiss(mut self) {
392 self.constellation_proxy
393 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
394 self.id,
395 EmbedderControlResponse::ContextMenu(None),
396 ));
397 self.response_sent = true;
398 }
399}
400
401impl Drop for ContextMenu {
402 fn drop(&mut self) {
403 if !self.response_sent {
404 self.constellation_proxy
405 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
406 self.id,
407 EmbedderControlResponse::ContextMenu(None),
408 ));
409 }
410 }
411}
412
413pub struct SelectElement {
415 pub(crate) id: EmbedderControlId,
416 pub(crate) options: Vec<SelectElementOptionOrOptgroup>,
417 pub(crate) selected_option: Option<usize>,
418 pub(crate) position: DeviceIntRect,
419 pub(crate) constellation_proxy: ConstellationProxy,
420 pub(crate) response_sent: bool,
421}
422
423impl SelectElement {
424 pub fn id(&self) -> EmbedderControlId {
426 self.id
427 }
428
429 pub fn position(&self) -> DeviceIntRect {
433 self.position
434 }
435
436 pub fn options(&self) -> &[SelectElementOptionOrOptgroup] {
439 &self.options
440 }
441
442 pub fn select(&mut self, id: Option<usize>) {
447 self.selected_option = id;
448 }
449
450 pub fn selected_option(&self) -> Option<usize> {
451 self.selected_option
452 }
453
454 pub fn submit(mut self) {
456 self.response_sent = true;
457 self.constellation_proxy
458 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
459 self.id,
460 EmbedderControlResponse::SelectElement(self.selected_option()),
461 ));
462 }
463}
464
465impl Drop for SelectElement {
466 fn drop(&mut self) {
467 if !self.response_sent {
468 self.constellation_proxy
469 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
470 self.id,
471 EmbedderControlResponse::SelectElement(self.selected_option()),
472 ));
473 }
474 }
475}
476
477pub struct ColorPicker {
479 pub(crate) id: EmbedderControlId,
480 pub(crate) current_color: Option<RgbColor>,
481 pub(crate) position: DeviceIntRect,
482 pub(crate) constellation_proxy: ConstellationProxy,
483 pub(crate) response_sent: bool,
484}
485
486impl ColorPicker {
487 pub fn id(&self) -> EmbedderControlId {
489 self.id
490 }
491
492 pub fn position(&self) -> DeviceIntRect {
496 self.position
497 }
498
499 pub fn current_color(&self) -> Option<RgbColor> {
502 self.current_color
503 }
504
505 pub fn select(&mut self, color: Option<RgbColor>) {
506 self.current_color = color;
507 }
508
509 pub fn submit(mut self) {
511 self.response_sent = true;
512 self.constellation_proxy
513 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
514 self.id,
515 EmbedderControlResponse::ColorPicker(self.current_color),
516 ));
517 }
518}
519
520impl Drop for ColorPicker {
521 fn drop(&mut self) {
522 if !self.response_sent {
523 self.constellation_proxy
524 .send(EmbedderToConstellationMessage::EmbedderControlResponse(
525 self.id,
526 EmbedderControlResponse::ColorPicker(self.current_color),
527 ));
528 }
529 }
530}
531
532pub struct FilePicker {
534 pub(crate) id: EmbedderControlId,
535 pub(crate) file_picker_request: FilePickerRequest,
536 pub(crate) response_sender: Option<Sender<Option<Vec<PathBuf>>>>,
537}
538
539impl FilePicker {
540 pub fn id(&self) -> EmbedderControlId {
542 self.id
543 }
544
545 pub fn filter_patterns(&self) -> &[FilterPattern] {
546 &self.file_picker_request.filter_patterns
547 }
548
549 pub fn allow_select_multiple(&self) -> bool {
550 self.file_picker_request.allow_select_multiple
551 }
552
553 pub fn current_paths(&self) -> &[PathBuf] {
556 &self.file_picker_request.current_paths
557 }
558
559 pub fn select(&mut self, paths: &[PathBuf]) {
560 self.file_picker_request.current_paths = paths.to_owned();
561 }
562
563 pub fn submit(mut self) {
565 if let Some(sender) = self.response_sender.take() {
566 let _ = sender.send(Some(std::mem::take(
567 &mut self.file_picker_request.current_paths,
568 )));
569 }
570 }
571
572 pub fn dismiss(mut self) {
574 if let Some(sender) = self.response_sender.take() {
575 let _ = sender.send(None);
576 }
577 }
578}
579
580impl Drop for FilePicker {
581 fn drop(&mut self) {
582 if let Some(sender) = self.response_sender.take() {
583 let _ = sender.send(None);
584 }
585 }
586}
587
588pub struct InputMethodControl {
590 pub(crate) id: EmbedderControlId,
591 pub(crate) input_method_type: InputMethodType,
592 pub(crate) text: String,
593 pub(crate) insertion_point: Option<u32>,
594 pub(crate) position: DeviceIntRect,
595 pub(crate) multiline: bool,
596 pub(crate) allow_virtual_keyboard: bool,
597}
598
599impl InputMethodControl {
600 pub fn id(&self) -> EmbedderControlId {
602 self.id
603 }
604
605 pub fn input_method_type(&self) -> InputMethodType {
607 self.input_method_type
608 }
609
610 pub fn text(&self) -> String {
612 self.text.clone()
613 }
614
615 pub fn insertion_point(&self) -> Option<u32> {
618 self.insertion_point
619 }
620
621 pub fn position(&self) -> DeviceIntRect {
626 self.position
627 }
628
629 pub fn multiline(&self) -> bool {
631 self.multiline
632 }
633
634 pub fn allow_virtual_keyboard(&self) -> bool {
638 self.allow_virtual_keyboard
639 }
640}
641
642pub enum SimpleDialog {
646 Alert(AlertDialog),
647 Confirm(ConfirmDialog),
648 Prompt(PromptDialog),
649}
650
651impl SimpleDialog {
652 pub fn message(&self) -> &str {
653 match self {
654 SimpleDialog::Alert(alert_dialog) => alert_dialog.message(),
655 SimpleDialog::Confirm(confirm_dialog) => confirm_dialog.message(),
656 SimpleDialog::Prompt(prompt_dialog) => prompt_dialog.message(),
657 }
658 }
659
660 pub fn confirm(self) {
661 match self {
662 SimpleDialog::Alert(alert_dialog) => alert_dialog.confirm(),
663 SimpleDialog::Confirm(confirm_dialog) => confirm_dialog.confirm(),
664 SimpleDialog::Prompt(prompt_dialog) => prompt_dialog.confirm(),
665 }
666 }
667
668 pub fn dismiss(self) {
669 match self {
670 SimpleDialog::Alert(alert_dialog) => alert_dialog.confirm(),
671 SimpleDialog::Confirm(confirm_dialog) => confirm_dialog.dismiss(),
672 SimpleDialog::Prompt(prompt_dialog) => prompt_dialog.dismiss(),
673 }
674 }
675}
676
677impl SimpleDialog {
678 fn id(&self) -> EmbedderControlId {
679 match self {
680 SimpleDialog::Alert(alert_dialog) => alert_dialog.id,
681 SimpleDialog::Confirm(confirm_dialog) => confirm_dialog.id,
682 SimpleDialog::Prompt(prompt_dialog) => prompt_dialog.id,
683 }
684 }
685}
686
687impl From<SimpleDialogRequest> for SimpleDialog {
688 fn from(simple_dialog_request: SimpleDialogRequest) -> Self {
689 match simple_dialog_request {
690 SimpleDialogRequest::Alert {
691 id,
692 message,
693 response_sender,
694 } => Self::Alert(AlertDialog {
695 id,
696 message,
697 response_sender,
698 response_sent: false,
699 }),
700 SimpleDialogRequest::Confirm {
701 id,
702 message,
703 response_sender,
704 } => Self::Confirm(ConfirmDialog {
705 id,
706 message,
707 response_sender,
708 response_sent: false,
709 }),
710 SimpleDialogRequest::Prompt {
711 id,
712 message,
713 default,
714 response_sender,
715 } => Self::Prompt(PromptDialog {
716 id,
717 message,
718 current_value: default,
719 response_sender,
720 response_sent: false,
721 }),
722 }
723 }
724}
725
726pub struct AlertDialog {
731 id: EmbedderControlId,
732 message: String,
733 response_sender: GenericSender<AlertResponse>,
734 response_sent: bool,
735}
736
737impl Drop for AlertDialog {
738 fn drop(&mut self) {
739 if !self.response_sent {
740 let _ = self.response_sender.send(AlertResponse::Ok);
741 }
742 }
743}
744
745impl AlertDialog {
746 pub fn message(&self) -> &str {
747 &self.message
748 }
749
750 pub fn confirm(self) {
752 }
754}
755
756pub struct ConfirmDialog {
762 id: EmbedderControlId,
763 message: String,
764 response_sender: GenericSender<ConfirmResponse>,
765 response_sent: bool,
766}
767
768impl ConfirmDialog {
769 pub fn message(&self) -> &str {
770 &self.message
771 }
772
773 pub fn dismiss(mut self) {
775 let _ = self.response_sender.send(ConfirmResponse::Cancel);
776 self.response_sent = true;
777 }
778
779 pub fn confirm(mut self) {
781 let _ = self.response_sender.send(ConfirmResponse::Ok);
782 self.response_sent = true;
783 }
784}
785
786impl Drop for ConfirmDialog {
787 fn drop(&mut self) {
788 if !self.response_sent {
789 let _ = self.response_sender.send(ConfirmResponse::Cancel);
790 }
791 }
792}
793
794pub struct PromptDialog {
803 id: EmbedderControlId,
804 message: String,
805 current_value: String,
806 response_sender: GenericSender<PromptResponse>,
807 response_sent: bool,
808}
809
810impl Drop for PromptDialog {
811 fn drop(&mut self) {
812 if !self.response_sent {
813 let _ = self.response_sender.send(PromptResponse::Cancel);
814 }
815 }
816}
817
818impl PromptDialog {
819 pub fn message(&self) -> &str {
820 &self.message
821 }
822
823 pub fn current_value(&self) -> &str {
824 &self.current_value
825 }
826
827 pub fn set_current_value(&mut self, new_value: &str) {
828 self.current_value = new_value.to_owned()
829 }
830
831 pub fn dismiss(mut self) {
833 let _ = self.response_sender.send(PromptResponse::Cancel);
834 self.response_sent = true;
835 }
836
837 pub fn confirm(mut self) {
840 let _ = self
841 .response_sender
842 .send(PromptResponse::Ok(self.current_value.clone()));
843 self.response_sent = true;
844 }
845}
846
847pub struct CreateNewWebViewRequest {
848 pub(crate) servo: Servo,
849 pub(crate) responder: IpcResponder<Option<NewWebViewDetails>>,
850}
851
852impl CreateNewWebViewRequest {
853 pub fn builder(self, rendering_context: Rc<dyn RenderingContext>) -> WebViewBuilder {
854 WebViewBuilder::new_for_create_request(&self.servo, rendering_context, self.responder)
855 }
856}
857
858pub trait WebViewDelegate {
859 fn screen_geometry(&self, _webview: WebView) -> Option<ScreenGeometry> {
863 None
864 }
865 fn notify_url_changed(&self, _webview: WebView, _url: Url) {}
868 fn notify_page_title_changed(&self, _webview: WebView, _title: Option<String>) {}
871 fn notify_status_text_changed(&self, _webview: WebView, _status: Option<String>) {}
874 fn notify_focus_changed(&self, _webview: WebView, _focused: bool) {}
877 fn notify_animating_changed(&self, _webview: WebView, _animating: bool) {}
882 fn notify_load_status_changed(&self, _webview: WebView, _status: LoadStatus) {}
885 fn notify_cursor_changed(&self, _webview: WebView, _: Cursor) {}
888 fn notify_favicon_changed(&self, _webview: WebView) {}
891 fn notify_new_frame_ready(&self, _webview: WebView) {}
893 fn notify_history_changed(&self, _webview: WebView, _entries: Vec<Url>, _current: usize) {}
897 fn notify_traversal_complete(&self, _webview: WebView, _: TraversalId) {}
899 fn notify_closed(&self, _webview: WebView) {}
903
904 fn notify_input_event_handled(&self, _webview: WebView, _: InputEventId, _: InputEventResult) {}
908 fn notify_crashed(&self, _webview: WebView, _reason: String, _backtrace: Option<String>) {}
910 fn notify_media_session_event(&self, _webview: WebView, _event: MediaSessionEvent) {}
913 fn notify_fullscreen_state_changed(&self, _webview: WebView, _: bool) {}
919
920 fn request_navigation(&self, _webview: WebView, _navigation_request: NavigationRequest) {}
923 fn request_unload(&self, _webview: WebView, _unload_request: AllowOrDenyRequest) {}
926 fn request_move_to(&self, _webview: WebView, _: DeviceIntPoint) {}
928 fn request_protocol_handler(
934 &self,
935 _webview: WebView,
936 _protocol_handler_registration: ProtocolHandlerRegistration,
937 _allow_deny_request: AllowOrDenyRequest,
938 ) {
939 }
940 fn request_resize_to(&self, _webview: WebView, _requested_outer_size: DeviceIntSize) {}
946 fn request_create_new(&self, _parent_webview: WebView, _: CreateNewWebViewRequest) {}
966 fn request_permission(&self, _webview: WebView, _: PermissionRequest) {}
970
971 fn request_authentication(
972 &self,
973 _webview: WebView,
974 _authentication_request: AuthenticationRequest,
975 ) {
976 }
977
978 fn show_bluetooth_device_dialog(&self, _webview: WebView, _: BluetoothDeviceSelectionRequest) {}
980
981 fn show_embedder_control(&self, _webview: WebView, _embedder_control: EmbedderControl) {}
984
985 fn hide_embedder_control(&self, _webview: WebView, _control_id: EmbedderControlId) {}
990
991 #[cfg(feature = "gamepad")]
995 fn play_gamepad_haptic_effect(
996 &self,
997 _webview: WebView,
998 _: usize,
999 _: GamepadHapticEffectType,
1000 _: Box<dyn FnOnce(bool)>,
1001 ) {
1002 }
1003 #[cfg(feature = "gamepad")]
1007 fn stop_gamepad_haptic_effect(&self, _webview: WebView, _: usize, _: Box<dyn FnOnce(bool)>) {}
1008
1009 fn load_web_resource(&self, _webview: WebView, _load: WebResourceLoad) {}
1017
1018 fn show_notification(&self, _webview: WebView, _notification: Notification) {}
1020
1021 fn show_console_message(&self, _webview: WebView, _level: ConsoleLogLevel, _message: String) {}
1024
1025 fn notify_accessibility_tree_update(
1032 &self,
1033 _webview: WebView,
1034 _tree_update: accesskit::TreeUpdate,
1035 ) {
1036 }
1037}
1038
1039pub(crate) struct DefaultWebViewDelegate;
1040impl WebViewDelegate for DefaultWebViewDelegate {}
1041
1042#[cfg(test)]
1043mod test {
1044 use super::*;
1045
1046 #[test]
1047 fn test_allow_deny_request() {
1048 use servo_base::generic_channel;
1049
1050 use crate::responders::ServoErrorChannel;
1051
1052 for default_response in [AllowOrDeny::Allow, AllowOrDeny::Deny] {
1053 let errors = ServoErrorChannel::default();
1055 let (sender, receiver) =
1056 generic_channel::channel().expect("Failed to create IPC channel");
1057 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1058 request.allow();
1059 assert_eq!(receiver.try_recv().ok(), Some(AllowOrDeny::Allow));
1060 assert_eq!(receiver.try_recv().ok(), None);
1061 assert!(errors.try_recv().is_none());
1062
1063 let errors = ServoErrorChannel::default();
1065 let (sender, receiver) =
1066 generic_channel::channel().expect("Failed to create IPC channel");
1067 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1068 request.deny();
1069 assert_eq!(receiver.try_recv().ok(), Some(AllowOrDeny::Deny));
1070 assert_eq!(receiver.try_recv().ok(), None);
1071 assert!(errors.try_recv().is_none());
1072
1073 let errors = ServoErrorChannel::default();
1075 let (sender, receiver) =
1076 generic_channel::channel().expect("Failed to create IPC channel");
1077 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1078 drop(request);
1079 assert_eq!(receiver.try_recv().ok(), Some(default_response));
1080 assert_eq!(receiver.try_recv().ok(), None);
1081 assert!(errors.try_recv().is_none());
1082
1083 let errors = ServoErrorChannel::default();
1085 let (sender, receiver) =
1086 generic_channel::channel().expect("Failed to create IPC channel");
1087 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1088 drop(receiver);
1089 request.allow();
1090 assert!(errors.try_recv().is_some());
1091
1092 let errors = ServoErrorChannel::default();
1094 let (sender, receiver) =
1095 generic_channel::channel().expect("Failed to create IPC channel");
1096 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1097 drop(receiver);
1098 request.deny();
1099 assert!(errors.try_recv().is_some());
1100
1101 let errors = ServoErrorChannel::default();
1103 let (sender, receiver) =
1104 generic_channel::channel().expect("Failed to create IPC channel");
1105 let request = AllowOrDenyRequest::new(sender, default_response, errors.sender());
1106 drop(receiver);
1107 drop(request);
1108 assert!(errors.try_recv().is_none());
1109 }
1110 }
1111
1112 #[test]
1113 fn test_authentication_request() {
1114 use crate::responders::ServoErrorChannel;
1115
1116 let url = Url::parse("https://example.com").expect("Guaranteed by argument");
1117
1118 let errors = ServoErrorChannel::default();
1120 let (sender, mut receiver) = tokio::sync::oneshot::channel();
1121 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
1122 request.authenticate("diffie".to_owned(), "hunter2".to_owned());
1123 assert_eq!(
1124 receiver.try_recv().ok(),
1125 Some(Some(AuthenticationResponse {
1126 username: "diffie".to_owned(),
1127 password: "hunter2".to_owned(),
1128 }))
1129 );
1130 assert_eq!(receiver.try_recv().ok(), None);
1131 assert!(errors.try_recv().is_none());
1132
1133 let errors = ServoErrorChannel::default();
1135 let (sender, mut receiver) = tokio::sync::oneshot::channel();
1136 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
1137 drop(request);
1138 assert_eq!(receiver.try_recv().ok(), Some(None));
1139 assert_eq!(receiver.try_recv().ok(), None);
1140 assert!(errors.try_recv().is_none());
1141
1142 let errors = ServoErrorChannel::default();
1144 let (sender, receiver) = tokio::sync::oneshot::channel();
1145 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
1146 drop(receiver);
1147 request.authenticate("diffie".to_owned(), "hunter2".to_owned());
1148 assert!(errors.try_recv().is_some());
1149
1150 let errors = ServoErrorChannel::default();
1152 let (sender, receiver) = tokio::sync::oneshot::channel();
1153 let request = AuthenticationRequest::new(url.clone(), false, sender, errors.sender());
1154 drop(receiver);
1155 drop(request);
1156 assert!(errors.try_recv().is_none());
1157 }
1158
1159 #[test]
1160 fn test_web_resource_load() {
1161 use http::{HeaderMap, Method, StatusCode};
1162
1163 use crate::responders::ServoErrorChannel;
1164
1165 let web_resource_request = || WebResourceRequest {
1166 method: Method::GET,
1167 headers: HeaderMap::default(),
1168 url: Url::parse("https://example.com").expect("Guaranteed by argument"),
1169 is_for_main_frame: false,
1170 is_redirect: false,
1171 };
1172 let web_resource_response = || {
1173 WebResourceResponse::new(
1174 Url::parse("https://diffie.test").expect("Guaranteed by argument"),
1175 )
1176 .status_code(StatusCode::IM_A_TEAPOT)
1177 };
1178
1179 let errors = ServoErrorChannel::default();
1181 let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
1182 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1183 request.intercept(web_resource_response()).cancel();
1184 assert!(matches!(
1185 receiver.try_recv(),
1186 Ok(WebResourceResponseMsg::Start(_))
1187 ));
1188 assert!(matches!(
1189 receiver.try_recv(),
1190 Ok(WebResourceResponseMsg::CancelLoad)
1191 ));
1192 assert!(matches!(receiver.try_recv(), Err(_)));
1193 assert!(errors.try_recv().is_none());
1194
1195 let errors = ServoErrorChannel::default();
1197 let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
1198 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1199 drop(request.intercept(web_resource_response()));
1200 assert!(matches!(
1201 receiver.try_recv(),
1202 Ok(WebResourceResponseMsg::Start(_))
1203 ));
1204 assert!(matches!(
1205 receiver.try_recv(),
1206 Ok(WebResourceResponseMsg::FinishLoad)
1207 ));
1208 assert!(matches!(receiver.try_recv(), Err(_)));
1209 assert!(errors.try_recv().is_none());
1210
1211 let errors = ServoErrorChannel::default();
1213 let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
1214 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1215 drop(request);
1216 assert!(matches!(
1217 receiver.try_recv(),
1218 Ok(WebResourceResponseMsg::DoNotIntercept)
1219 ));
1220 assert!(matches!(receiver.try_recv(), Err(_)));
1221 assert!(errors.try_recv().is_none());
1222
1223 let errors = ServoErrorChannel::default();
1225 let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
1226 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1227 drop(receiver);
1228 request.intercept(web_resource_response()).cancel();
1229 assert!(errors.try_recv().is_some());
1230
1231 let errors = ServoErrorChannel::default();
1233 let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
1234 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1235 drop(receiver);
1236 drop(request.intercept(web_resource_response()));
1237 assert!(errors.try_recv().is_some());
1238
1239 let errors = ServoErrorChannel::default();
1241 let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
1242 let request = WebResourceLoad::new(web_resource_request(), sender, errors.sender());
1243 drop(receiver);
1244 drop(request);
1245 assert!(errors.try_recv().is_none());
1246 }
1247}