1use cbf::data::{
20 auxiliary_window::{
21 AuxiliaryWindowCloseReason, AuxiliaryWindowId, AuxiliaryWindowKind,
22 AuxiliaryWindowResolution, PermissionPromptResult, PermissionPromptType,
23 },
24 dialog::DialogType,
25 download::DownloadPromptResult,
26 extension::{ExtensionInstallPromptResult, ExtensionUninstallPromptResult},
27 ids::WindowId,
28 transient_browsing_context::{
29 TransientBrowsingContextCloseReason, TransientBrowsingContextKind,
30 },
31 window_open::{
32 WindowBounds, WindowDescriptor, WindowKind, WindowOpenReason, WindowOpenRequest,
33 WindowOpenResult, WindowState,
34 },
35};
36use cbf::event::{BrowserEvent, BrowsingContextEvent, TransientBrowsingContextEvent};
37
38use crate::data::{
39 browsing_context_open::ChromeBrowsingContextOpenResult,
40 download::ChromeDownloadPromptResult,
41 extension::ChromeExtensionInfo,
42 ids::PopupId,
43 lifecycle::{ChromeBackendErrorInfo, ChromeBackendStopReason},
44 profile::ChromeProfileInfo,
45 prompt_ui::{
46 PromptUiCloseReason, PromptUiDialogResult, PromptUiExtensionInstallResult,
47 PromptUiExtensionUninstallResult, PromptUiId, PromptUiKind, PromptUiPermissionType,
48 PromptUiResolution, PromptUiResolutionResult,
49 },
50 tab_open::{TabOpenHint, TabOpenResult},
51};
52use crate::ffi::IpcEvent;
53
54#[derive(Debug, Clone)]
56pub enum ChromeEvent {
57 Ipc(Box<IpcEvent>),
59 BackendReady,
61 BackendStopped { reason: ChromeBackendStopReason },
63 BackendError {
65 info: ChromeBackendErrorInfo,
66 terminal_hint: bool,
67 },
68 ProfilesListed { profiles: Vec<ChromeProfileInfo> },
70}
71
72pub fn to_generic_event(event: &ChromeEvent) -> Option<BrowserEvent> {
78 match event {
79 ChromeEvent::Ipc(raw) => map_ipc_event_to_generic(raw),
80 ChromeEvent::BackendReady => Some(BrowserEvent::BackendReady),
81 ChromeEvent::BackendStopped { reason } => Some(BrowserEvent::BackendStopped {
82 reason: reason.clone(),
83 }),
84 ChromeEvent::BackendError {
85 info,
86 terminal_hint,
87 } => Some(BrowserEvent::BackendError {
88 info: info.clone(),
89 terminal_hint: *terminal_hint,
90 }),
91 ChromeEvent::ProfilesListed { profiles } => Some(BrowserEvent::ProfilesListed {
92 profiles: profiles.iter().cloned().map(Into::into).collect(),
93 }),
94 }
95}
96
97pub fn map_ipc_event_to_generic(event: &IpcEvent) -> Option<BrowserEvent> {
103 match event {
104 IpcEvent::SurfaceHandleUpdated { .. } => None,
105 IpcEvent::ExtensionPopupOpened {
106 profile_id,
107 browsing_context_id,
108 popup_id,
109 title,
110 ..
111 } => Some(BrowserEvent::TransientBrowsingContext {
112 profile_id: profile_id.clone(),
113 transient_browsing_context_id: PopupId::new(*popup_id)
114 .to_transient_browsing_context_id(),
115 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
116 event: Box::new(TransientBrowsingContextEvent::Opened {
117 kind: TransientBrowsingContextKind::Popup,
118 title: Some(title.clone()),
119 }),
120 }),
121 IpcEvent::ExtensionPopupSurfaceHandleUpdated { .. } => None,
122 IpcEvent::ExtensionPopupPreferredSizeChanged {
123 profile_id,
124 browsing_context_id,
125 popup_id,
126 width,
127 height,
128 } => Some(BrowserEvent::TransientBrowsingContext {
129 profile_id: profile_id.clone(),
130 transient_browsing_context_id: PopupId::new(*popup_id)
131 .to_transient_browsing_context_id(),
132 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
133 event: Box::new(TransientBrowsingContextEvent::Resized {
134 width: *width,
135 height: *height,
136 }),
137 }),
138 IpcEvent::ExtensionPopupContextMenuRequested {
139 profile_id,
140 browsing_context_id,
141 popup_id,
142 menu,
143 } => Some(BrowserEvent::TransientBrowsingContext {
144 profile_id: profile_id.clone(),
145 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
146 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
147 event: Box::new(TransientBrowsingContextEvent::ContextMenuRequested {
148 menu: menu.clone().into(),
149 }),
150 }),
151 IpcEvent::ExtensionPopupChoiceMenuRequested {
152 profile_id,
153 browsing_context_id,
154 popup_id,
155 request_id,
156 ..
157 } => Some(BrowserEvent::TransientBrowsingContext {
158 profile_id: profile_id.clone(),
159 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
160 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
161 event: Box::new(TransientBrowsingContextEvent::ChoiceMenuRequested {
162 request_id: *request_id,
163 }),
164 }),
165 IpcEvent::ExtensionPopupCursorChanged {
166 profile_id,
167 browsing_context_id,
168 popup_id,
169 cursor_type,
170 } => Some(BrowserEvent::TransientBrowsingContext {
171 profile_id: profile_id.clone(),
172 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
173 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
174 event: Box::new(TransientBrowsingContextEvent::CursorChanged {
175 cursor_type: *cursor_type,
176 }),
177 }),
178 IpcEvent::ExtensionPopupTitleUpdated {
179 profile_id,
180 browsing_context_id,
181 popup_id,
182 title,
183 } => Some(BrowserEvent::TransientBrowsingContext {
184 profile_id: profile_id.clone(),
185 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
186 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
187 event: Box::new(TransientBrowsingContextEvent::TitleUpdated {
188 title: title.clone(),
189 }),
190 }),
191 IpcEvent::ExtensionPopupJavaScriptDialogRequested {
192 profile_id,
193 browsing_context_id,
194 popup_id,
195 request_id,
196 r#type,
197 message,
198 default_prompt_text,
199 reason,
200 } => Some(BrowserEvent::TransientBrowsingContext {
201 profile_id: profile_id.clone(),
202 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
203 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
204 event: Box::new(TransientBrowsingContextEvent::JavaScriptDialogRequested {
205 request_id: *request_id,
206 message: message.clone(),
207 default_prompt_text: default_prompt_text.clone(),
208 r#type: *r#type,
209 beforeunload_reason: if *r#type == DialogType::BeforeUnload {
210 Some((*reason).into())
211 } else {
212 None
213 },
214 }),
215 }),
216 IpcEvent::ExtensionPopupCloseRequested {
217 profile_id,
218 browsing_context_id,
219 popup_id,
220 } => Some(BrowserEvent::TransientBrowsingContext {
221 profile_id: profile_id.clone(),
222 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
223 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
224 event: Box::new(TransientBrowsingContextEvent::CloseRequested),
225 }),
226 IpcEvent::ExtensionPopupRenderProcessGone {
227 profile_id,
228 browsing_context_id,
229 popup_id,
230 crashed,
231 } => Some(BrowserEvent::TransientBrowsingContext {
232 profile_id: profile_id.clone(),
233 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
234 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
235 event: Box::new(TransientBrowsingContextEvent::RenderProcessGone { crashed: *crashed }),
236 }),
237 IpcEvent::ExtensionPopupClosed {
238 profile_id,
239 browsing_context_id,
240 popup_id,
241 } => Some(BrowserEvent::TransientBrowsingContext {
242 profile_id: profile_id.clone(),
243 transient_browsing_context_id: PopupId::new(*popup_id)
244 .to_transient_browsing_context_id(),
245 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
246 event: Box::new(TransientBrowsingContextEvent::Closed {
247 reason: TransientBrowsingContextCloseReason::Unknown,
248 }),
249 }),
250 IpcEvent::TabCreated {
251 profile_id,
252 browsing_context_id,
253 request_id,
254 } => Some(BrowserEvent::BrowsingContext {
255 profile_id: profile_id.clone(),
256 browsing_context_id: browsing_context_id.to_browsing_context_id(),
257 event: Box::new(BrowsingContextEvent::Created {
258 request_id: *request_id,
259 }),
260 }),
261 IpcEvent::DevToolsOpened { .. } => None,
262 IpcEvent::ImeBoundsUpdated {
263 profile_id,
264 browsing_context_id,
265 update,
266 } => Some(BrowserEvent::BrowsingContext {
267 profile_id: profile_id.clone(),
268 browsing_context_id: browsing_context_id.to_browsing_context_id(),
269 event: Box::new(BrowsingContextEvent::ImeBoundsUpdated {
270 update: update.clone().into(),
271 }),
272 }),
273 IpcEvent::ExtensionPopupImeBoundsUpdated {
274 profile_id,
275 browsing_context_id,
276 popup_id,
277 update,
278 } => Some(BrowserEvent::TransientBrowsingContext {
279 profile_id: profile_id.clone(),
280 transient_browsing_context_id: popup_id.to_transient_browsing_context_id(),
281 parent_browsing_context_id: browsing_context_id.to_browsing_context_id(),
282 event: Box::new(TransientBrowsingContextEvent::ImeBoundsUpdated {
283 update: update.clone().into(),
284 }),
285 }),
286 IpcEvent::ContextMenuRequested {
287 profile_id,
288 browsing_context_id,
289 menu,
290 } => Some(BrowserEvent::BrowsingContext {
291 profile_id: profile_id.clone(),
292 browsing_context_id: browsing_context_id.to_browsing_context_id(),
293 event: Box::new(BrowsingContextEvent::ContextMenuRequested {
294 menu: menu.clone().into(),
295 }),
296 }),
297 IpcEvent::ChoiceMenuRequested {
298 profile_id,
299 browsing_context_id,
300 request_id,
301 ..
302 } => Some(BrowserEvent::BrowsingContext {
303 profile_id: profile_id.clone(),
304 browsing_context_id: browsing_context_id.to_browsing_context_id(),
305 event: Box::new(BrowsingContextEvent::ChoiceMenuRequested {
306 request_id: *request_id,
307 }),
308 }),
309 IpcEvent::TabOpenRequested {
310 profile_id,
311 request_id,
312 source_tab_id,
313 target_url,
314 open_hint,
315 user_gesture,
316 } => match open_hint {
317 TabOpenHint::NewWindow | TabOpenHint::Popup => {
318 Some(BrowserEvent::WindowOpenRequested {
319 profile_id: profile_id.clone(),
320 request: WindowOpenRequest {
321 request_id: *request_id,
322 reason: WindowOpenReason::Navigation,
323 opener_window_id: None,
324 opener_browsing_context_id: source_tab_id
325 .map(|id| id.to_browsing_context_id()),
326 target_url: Some(target_url.clone()),
327 requested_kind: if matches!(open_hint, TabOpenHint::Popup) {
328 WindowKind::Popup
329 } else {
330 WindowKind::Normal
331 },
332 user_gesture: *user_gesture,
333 },
334 })
335 }
336 _ => Some(BrowserEvent::BrowsingContextOpenRequested {
337 profile_id: profile_id.clone(),
338 request_id: *request_id,
339 source_browsing_context_id: source_tab_id.map(|id| id.to_browsing_context_id()),
340 target_url: target_url.clone(),
341 open_hint: open_hint
342 .to_browsing_context_open_hint()
343 .map(Into::into)
344 .unwrap_or_else(|| {
345 unreachable!(
346 "window-oriented tab-open hints are mapped to WindowOpenRequested"
347 )
348 }),
349 user_gesture: *user_gesture,
350 }),
351 },
352 IpcEvent::TabOpenResolved {
353 profile_id,
354 request_id,
355 result,
356 } => match result {
357 TabOpenResult::OpenedNewTab { tab_id } => Some(BrowserEvent::WindowOpenResolved {
358 profile_id: profile_id.clone(),
359 request_id: *request_id,
360 result: WindowOpenResult::OpenedNewWindow {
361 window: synthetic_window_descriptor(
362 WindowId::new(tab_id.get()),
363 WindowKind::Normal,
364 true,
365 ),
366 },
367 }),
368 _ => Some(BrowserEvent::BrowsingContextOpenResolved {
369 profile_id: profile_id.clone(),
370 request_id: *request_id,
371 result: ChromeBrowsingContextOpenResult::from(*result).into(),
372 }),
373 },
374 IpcEvent::NavigationStateChanged {
375 profile_id,
376 browsing_context_id,
377 url,
378 can_go_back,
379 can_go_forward,
380 is_loading,
381 } => Some(BrowserEvent::BrowsingContext {
382 profile_id: profile_id.clone(),
383 browsing_context_id: browsing_context_id.to_browsing_context_id(),
384 event: Box::new(BrowsingContextEvent::NavigationStateChanged {
385 url: url.clone(),
386 can_go_back: *can_go_back,
387 can_go_forward: *can_go_forward,
388 is_loading: *is_loading,
389 }),
390 }),
391 IpcEvent::CursorChanged {
392 profile_id,
393 browsing_context_id,
394 cursor_type,
395 } => Some(BrowserEvent::BrowsingContext {
396 profile_id: profile_id.clone(),
397 browsing_context_id: browsing_context_id.to_browsing_context_id(),
398 event: Box::new(BrowsingContextEvent::CursorChanged {
399 cursor_type: *cursor_type,
400 }),
401 }),
402 IpcEvent::TitleUpdated {
403 profile_id,
404 browsing_context_id,
405 title,
406 } => Some(BrowserEvent::BrowsingContext {
407 profile_id: profile_id.clone(),
408 browsing_context_id: browsing_context_id.to_browsing_context_id(),
409 event: Box::new(BrowsingContextEvent::TitleUpdated {
410 title: title.clone(),
411 }),
412 }),
413 IpcEvent::FaviconUrlUpdated {
414 profile_id,
415 browsing_context_id,
416 url,
417 } => Some(BrowserEvent::BrowsingContext {
418 profile_id: profile_id.clone(),
419 browsing_context_id: browsing_context_id.to_browsing_context_id(),
420 event: Box::new(BrowsingContextEvent::FaviconUrlUpdated { url: url.clone() }),
421 }),
422 IpcEvent::BeforeUnloadDialogRequested {
423 profile_id,
424 browsing_context_id,
425 request_id,
426 reason,
427 } => Some(BrowserEvent::BrowsingContext {
428 profile_id: profile_id.clone(),
429 browsing_context_id: browsing_context_id.to_browsing_context_id(),
430 event: Box::new(BrowsingContextEvent::JavaScriptDialogRequested {
431 request_id: *request_id,
432 message: String::new(),
433 default_prompt_text: None,
434 r#type: cbf::data::dialog::DialogType::BeforeUnload,
435 beforeunload_reason: Some((*reason).into()),
436 }),
437 }),
438 IpcEvent::JavaScriptDialogRequested {
439 profile_id,
440 browsing_context_id,
441 request_id,
442 r#type,
443 message,
444 default_prompt_text,
445 reason,
446 } => Some(BrowserEvent::BrowsingContext {
447 profile_id: profile_id.clone(),
448 browsing_context_id: browsing_context_id.to_browsing_context_id(),
449 event: Box::new(BrowsingContextEvent::JavaScriptDialogRequested {
450 request_id: *request_id,
451 message: message.clone(),
452 default_prompt_text: default_prompt_text.clone(),
453 r#type: *r#type,
454 beforeunload_reason: if *r#type == DialogType::BeforeUnload {
455 Some((*reason).into())
456 } else {
457 None
458 },
459 }),
460 }),
461 IpcEvent::TabClosed {
462 profile_id,
463 browsing_context_id,
464 } => Some(BrowserEvent::BrowsingContext {
465 profile_id: profile_id.clone(),
466 browsing_context_id: browsing_context_id.to_browsing_context_id(),
467 event: Box::new(BrowsingContextEvent::Closed),
468 }),
469 IpcEvent::TabResizeAcknowledged { .. } => None,
470 IpcEvent::TabDomHtmlRead {
471 profile_id,
472 browsing_context_id,
473 request_id,
474 html,
475 } => Some(BrowserEvent::BrowsingContext {
476 profile_id: profile_id.clone(),
477 browsing_context_id: browsing_context_id.to_browsing_context_id(),
478 event: Box::new(BrowsingContextEvent::DomHtmlRead {
479 request_id: *request_id,
480 html: html.clone(),
481 }),
482 }),
483 IpcEvent::DragStartRequested {
484 profile_id,
485 browsing_context_id,
486 request,
487 } => Some(BrowserEvent::BrowsingContext {
488 profile_id: profile_id.clone(),
489 browsing_context_id: browsing_context_id.to_browsing_context_id(),
490 event: Box::new(BrowsingContextEvent::DragStartRequested {
491 request: request.clone().into(),
492 }),
493 }),
494 IpcEvent::ShutdownBlocked {
495 request_id,
496 dirty_browsing_context_ids,
497 } => Some(BrowserEvent::ShutdownBlocked {
498 request_id: *request_id,
499 dirty_browsing_context_ids: dirty_browsing_context_ids
500 .iter()
501 .copied()
502 .map(|id| id.to_browsing_context_id())
503 .collect(),
504 }),
505 IpcEvent::ShutdownProceeding { request_id } => Some(BrowserEvent::ShutdownProceeding {
506 request_id: *request_id,
507 }),
508 IpcEvent::ShutdownCancelled { request_id } => Some(BrowserEvent::ShutdownCancelled {
509 request_id: *request_id,
510 }),
511 IpcEvent::ExtensionsListed {
512 profile_id,
513 extensions,
514 } => Some(BrowserEvent::ExtensionsListed {
515 profile_id: profile_id.clone(),
516 extensions: extensions
517 .iter()
518 .cloned()
519 .map(ChromeExtensionInfo::into)
520 .collect(),
521 }),
522 IpcEvent::PromptUiOpenRequested {
523 profile_id,
524 source_tab_id,
525 request_id,
526 kind,
527 } => Some(BrowserEvent::AuxiliaryWindowOpenRequested {
528 profile_id: profile_id.clone(),
529 request_id: *request_id,
530 source_browsing_context_id: source_tab_id.map(|tab_id| tab_id.to_browsing_context_id()),
531 kind: prompt_ui_kind_to_auxiliary_window_kind(kind),
532 }),
533 IpcEvent::PromptUiResolved {
534 profile_id,
535 source_tab_id,
536 request_id,
537 resolution,
538 } => Some(BrowserEvent::AuxiliaryWindowResolved {
539 profile_id: profile_id.clone(),
540 request_id: *request_id,
541 source_browsing_context_id: source_tab_id.map(|tab_id| tab_id.to_browsing_context_id()),
542 resolution: prompt_ui_resolution_to_auxiliary_window_resolution(resolution),
543 }),
544 IpcEvent::ExtensionRuntimeWarning {
545 profile_id,
546 browsing_context_id,
547 detail,
548 } => Some(BrowserEvent::BrowsingContext {
549 profile_id: profile_id.clone(),
550 browsing_context_id: browsing_context_id.to_browsing_context_id(),
551 event: Box::new(BrowsingContextEvent::ExtensionRuntimeWarning {
552 detail: detail.clone(),
553 }),
554 }),
555 IpcEvent::PromptUiOpened {
556 profile_id,
557 source_tab_id,
558 prompt_ui_id,
559 kind,
560 title,
561 modal,
562 } => Some(BrowserEvent::AuxiliaryWindowOpened {
563 profile_id: profile_id.clone(),
564 source_browsing_context_id: source_tab_id.map(|tab_id| tab_id.to_browsing_context_id()),
565 window_id: prompt_ui_id_to_auxiliary_window_id(*prompt_ui_id),
566 kind: prompt_ui_kind_to_auxiliary_window_kind(kind),
567 title: title.clone(),
568 modal: *modal,
569 }),
570 IpcEvent::PromptUiClosed {
571 profile_id,
572 source_tab_id,
573 prompt_ui_id,
574 kind,
575 reason,
576 } => Some(BrowserEvent::AuxiliaryWindowClosed {
577 profile_id: profile_id.clone(),
578 source_browsing_context_id: source_tab_id.map(|tab_id| tab_id.to_browsing_context_id()),
579 window_id: prompt_ui_id_to_auxiliary_window_id(*prompt_ui_id),
580 kind: prompt_ui_kind_to_auxiliary_window_kind(kind),
581 reason: prompt_ui_close_reason_to_auxiliary_window_close_reason(reason),
582 }),
583 IpcEvent::DownloadCreated {
584 profile_id,
585 download,
586 } => Some(BrowserEvent::DownloadCreated {
587 profile_id: profile_id.clone(),
588 download_id: download.download_id.into(),
589 source_browsing_context_id: download
590 .source_tab_id
591 .map(|tab_id| tab_id.to_browsing_context_id()),
592 file_name: download.file_name.clone(),
593 total_bytes: download.total_bytes,
594 target_path: download.target_path.clone(),
595 }),
596 IpcEvent::DownloadUpdated {
597 profile_id,
598 download,
599 } => Some(BrowserEvent::DownloadUpdated {
600 profile_id: profile_id.clone(),
601 download_id: download.download_id.into(),
602 source_browsing_context_id: download
603 .source_tab_id
604 .map(|tab_id| tab_id.to_browsing_context_id()),
605 state: download.state.into(),
606 file_name: download.file_name.clone(),
607 received_bytes: download.received_bytes,
608 total_bytes: download.total_bytes,
609 target_path: download.target_path.clone(),
610 can_resume: download.can_resume,
611 is_paused: download.is_paused,
612 }),
613 IpcEvent::DownloadCompleted {
614 profile_id,
615 download,
616 } => Some(BrowserEvent::DownloadCompleted {
617 profile_id: profile_id.clone(),
618 download_id: download.download_id.into(),
619 source_browsing_context_id: download
620 .source_tab_id
621 .map(|tab_id| tab_id.to_browsing_context_id()),
622 outcome: download.outcome.into(),
623 file_name: download.file_name.clone(),
624 received_bytes: download.received_bytes,
625 total_bytes: download.total_bytes,
626 target_path: download.target_path.clone(),
627 }),
628 }
629}
630
631fn synthetic_window_descriptor(
632 window_id: WindowId,
633 kind: WindowKind,
634 focused: bool,
635) -> WindowDescriptor {
636 WindowDescriptor {
637 window_id,
638 kind,
639 state: WindowState::Normal,
640 focused,
641 incognito: false,
642 always_on_top: false,
643 bounds: WindowBounds {
644 left: 0,
645 top: 0,
646 width: 1280,
647 height: 720,
648 },
649 }
650}
651
652fn prompt_ui_permission_to_permission_prompt_type(
653 permission: &PromptUiPermissionType,
654 permission_key: Option<&str>,
655) -> PermissionPromptType {
656 match permission {
657 PromptUiPermissionType::Geolocation => PermissionPromptType::Geolocation,
658 PromptUiPermissionType::Notifications => PermissionPromptType::Notifications,
659 PromptUiPermissionType::AudioCapture => PermissionPromptType::AudioCapture,
660 PromptUiPermissionType::VideoCapture => PermissionPromptType::VideoCapture,
661 PromptUiPermissionType::Unknown => permission_key
662 .map(str::trim)
663 .filter(|value| !value.is_empty())
664 .map(|value| PermissionPromptType::Other(value.to_string()))
665 .unwrap_or(PermissionPromptType::Unknown),
666 }
667}
668
669fn prompt_ui_kind_to_auxiliary_window_kind(kind: &PromptUiKind) -> AuxiliaryWindowKind {
670 match kind {
671 PromptUiKind::PermissionPrompt {
672 permission,
673 permission_key,
674 } => AuxiliaryWindowKind::PermissionPrompt {
675 permission: prompt_ui_permission_to_permission_prompt_type(
676 permission,
677 permission_key.as_deref(),
678 ),
679 },
680 PromptUiKind::DownloadPrompt {
681 download_id,
682 file_name,
683 total_bytes,
684 suggested_path,
685 reason,
686 } => AuxiliaryWindowKind::DownloadPrompt {
687 download_id: (*download_id).into(),
688 file_name: file_name.clone(),
689 total_bytes: *total_bytes,
690 suggested_path: suggested_path.clone(),
691 action_hint: (*reason).into(),
692 },
693 PromptUiKind::ExtensionInstallPrompt {
694 extension_id,
695 extension_name,
696 permission_names,
697 } => AuxiliaryWindowKind::ExtensionInstallPrompt {
698 extension_id: extension_id.clone(),
699 extension_name: extension_name.clone(),
700 permission_names: permission_names.clone(),
701 },
702 PromptUiKind::ExtensionUninstallPrompt {
703 extension_id,
704 extension_name,
705 triggering_extension_name,
706 can_report_abuse,
707 } => AuxiliaryWindowKind::ExtensionUninstallPrompt {
708 extension_id: extension_id.clone(),
709 extension_name: extension_name.clone(),
710 triggering_extension_name: triggering_extension_name.clone(),
711 can_report_abuse: *can_report_abuse,
712 },
713 PromptUiKind::PrintPreviewDialog => AuxiliaryWindowKind::PrintPreviewDialog,
714 PromptUiKind::Unknown => AuxiliaryWindowKind::Unknown,
715 }
716}
717
718fn prompt_ui_resolution_to_auxiliary_window_resolution(
719 resolution: &PromptUiResolution,
720) -> AuxiliaryWindowResolution {
721 match resolution {
722 PromptUiResolution::PermissionPrompt {
723 permission,
724 permission_key,
725 result,
726 } => AuxiliaryWindowResolution::PermissionPrompt {
727 permission: prompt_ui_permission_to_permission_prompt_type(
728 permission,
729 permission_key.as_deref(),
730 ),
731 result: match result {
732 PromptUiResolutionResult::Allowed => PermissionPromptResult::Allowed,
733 PromptUiResolutionResult::Denied => PermissionPromptResult::Denied,
734 PromptUiResolutionResult::Aborted => PermissionPromptResult::Aborted,
735 PromptUiResolutionResult::Unknown => PermissionPromptResult::Unknown,
736 },
737 },
738 PromptUiResolution::DownloadPrompt {
739 download_id,
740 destination_path,
741 result,
742 } => AuxiliaryWindowResolution::DownloadPrompt {
743 download_id: (*download_id).into(),
744 destination_path: destination_path.clone(),
745 result: match result {
746 ChromeDownloadPromptResult::Allowed => DownloadPromptResult::Allowed,
747 ChromeDownloadPromptResult::Denied => DownloadPromptResult::Denied,
748 ChromeDownloadPromptResult::Aborted => DownloadPromptResult::Aborted,
749 },
750 },
751 PromptUiResolution::ExtensionInstallPrompt {
752 extension_id,
753 result,
754 detail,
755 } => AuxiliaryWindowResolution::ExtensionInstallPrompt {
756 extension_id: extension_id.clone(),
757 result: match result {
758 PromptUiExtensionInstallResult::Accepted => ExtensionInstallPromptResult::Accepted,
759 PromptUiExtensionInstallResult::AcceptedWithWithheldPermissions => {
760 ExtensionInstallPromptResult::AcceptedWithWithheldPermissions
761 }
762 PromptUiExtensionInstallResult::UserCanceled => {
763 ExtensionInstallPromptResult::UserCanceled
764 }
765 PromptUiExtensionInstallResult::Aborted => ExtensionInstallPromptResult::Aborted,
766 },
767 detail: detail.clone(),
768 },
769 PromptUiResolution::ExtensionUninstallPrompt {
770 extension_id,
771 result,
772 detail,
773 report_abuse,
774 } => AuxiliaryWindowResolution::ExtensionUninstallPrompt {
775 extension_id: extension_id.clone(),
776 result: match result {
777 PromptUiExtensionUninstallResult::Accepted => {
778 ExtensionUninstallPromptResult::Accepted
779 }
780 PromptUiExtensionUninstallResult::UserCanceled => {
781 ExtensionUninstallPromptResult::UserCanceled
782 }
783 PromptUiExtensionUninstallResult::Aborted => {
784 ExtensionUninstallPromptResult::Aborted
785 }
786 PromptUiExtensionUninstallResult::Failed => ExtensionUninstallPromptResult::Failed,
787 },
788 detail: detail.clone(),
789 report_abuse: *report_abuse,
790 },
791 PromptUiResolution::PrintPreviewDialog { result } => match result {
792 PromptUiDialogResult::Proceeded => AuxiliaryWindowResolution::Unknown,
793 PromptUiDialogResult::Canceled => AuxiliaryWindowResolution::Unknown,
794 PromptUiDialogResult::Aborted => AuxiliaryWindowResolution::Unknown,
795 PromptUiDialogResult::Unknown => AuxiliaryWindowResolution::Unknown,
796 },
797 PromptUiResolution::Unknown => AuxiliaryWindowResolution::Unknown,
798 }
799}
800
801fn prompt_ui_id_to_auxiliary_window_id(value: PromptUiId) -> AuxiliaryWindowId {
802 AuxiliaryWindowId::new(value.get())
803}
804
805fn prompt_ui_close_reason_to_auxiliary_window_close_reason(
806 value: &PromptUiCloseReason,
807) -> AuxiliaryWindowCloseReason {
808 match value {
809 PromptUiCloseReason::UserCanceled => AuxiliaryWindowCloseReason::UserCanceled,
810 PromptUiCloseReason::HostForced => AuxiliaryWindowCloseReason::HostForced,
811 PromptUiCloseReason::SystemDismissed => AuxiliaryWindowCloseReason::SystemDismissed,
812 PromptUiCloseReason::Unknown => AuxiliaryWindowCloseReason::Unknown,
813 }
814}
815
816#[cfg(test)]
817mod tests {
818 use cbf::{
819 data::{
820 auxiliary_window::{
821 AuxiliaryWindowCloseReason, AuxiliaryWindowId, AuxiliaryWindowKind,
822 AuxiliaryWindowResolution, PermissionPromptResult, PermissionPromptType,
823 },
824 download::DownloadPromptActionHint,
825 extension::{ExtensionInstallPromptResult, ExtensionUninstallPromptResult},
826 ids::{BrowsingContextId, TransientBrowsingContextId},
827 transient_browsing_context::{
828 TransientBrowsingContextCloseReason, TransientBrowsingContextKind,
829 },
830 },
831 event::{BrowserEvent, BrowsingContextEvent, TransientBrowsingContextEvent},
832 };
833
834 use super::map_ipc_event_to_generic;
835 use crate::{
836 data::{
837 download::ChromeDownloadPromptReason,
838 ids::{PopupId, TabId},
839 prompt_ui::{
840 PromptUiCloseReason, PromptUiExtensionInstallResult,
841 PromptUiExtensionUninstallResult, PromptUiId, PromptUiKind, PromptUiResolution,
842 },
843 },
844 ffi::IpcEvent,
845 };
846
847 #[test]
848 fn tab_created_maps_tab_id_into_browsing_context_id() {
849 let event = IpcEvent::TabCreated {
850 profile_id: "default".to_string(),
851 browsing_context_id: TabId::new(7),
852 request_id: 1,
853 };
854
855 let mapped = map_ipc_event_to_generic(&event).unwrap();
856 assert!(matches!(
857 mapped,
858 BrowserEvent::BrowsingContext {
859 browsing_context_id,
860 event,
861 ..
862 } if browsing_context_id == BrowsingContextId::new(7)
863 && matches!(*event, BrowsingContextEvent::Created { request_id: 1 })
864 ));
865 }
866
867 #[test]
868 fn shutdown_blocked_maps_dirty_tab_ids_into_browsing_context_ids() {
869 let event = IpcEvent::ShutdownBlocked {
870 request_id: 9,
871 dirty_browsing_context_ids: vec![TabId::new(2), TabId::new(3)],
872 };
873
874 let mapped = map_ipc_event_to_generic(&event).unwrap();
875 assert!(matches!(
876 mapped,
877 BrowserEvent::ShutdownBlocked {
878 request_id: 9,
879 dirty_browsing_context_ids
880 } if dirty_browsing_context_ids
881 == vec![BrowsingContextId::new(2), BrowsingContextId::new(3)]
882 ));
883 }
884
885 #[test]
886 fn extension_popup_opened_maps_into_transient_browsing_context() {
887 let event = IpcEvent::ExtensionPopupOpened {
888 profile_id: "default".to_string(),
889 browsing_context_id: TabId::new(44),
890 popup_id: 88,
891 extension_id: "ext".to_string(),
892 title: "Popup".to_string(),
893 };
894
895 let mapped = map_ipc_event_to_generic(&event).unwrap();
896 assert!(matches!(
897 mapped,
898 BrowserEvent::TransientBrowsingContext {
899 transient_browsing_context_id,
900 parent_browsing_context_id,
901 event,
902 ..
903 } if transient_browsing_context_id == TransientBrowsingContextId::new(88)
904 && parent_browsing_context_id == BrowsingContextId::new(44)
905 && matches!(
906 *event,
907 TransientBrowsingContextEvent::Opened {
908 kind: TransientBrowsingContextKind::Popup,
909 title: Some(ref title),
910 } if title == "Popup"
911 )
912 ));
913 }
914
915 #[test]
916 fn extension_popup_closed_maps_into_transient_browsing_context() {
917 let event = IpcEvent::ExtensionPopupClosed {
918 profile_id: "default".to_string(),
919 browsing_context_id: TabId::new(44),
920 popup_id: 88,
921 };
922
923 let mapped = map_ipc_event_to_generic(&event).unwrap();
924 assert!(matches!(
925 mapped,
926 BrowserEvent::TransientBrowsingContext {
927 transient_browsing_context_id,
928 parent_browsing_context_id,
929 event,
930 ..
931 } if transient_browsing_context_id == TransientBrowsingContextId::new(88)
932 && parent_browsing_context_id == BrowsingContextId::new(44)
933 && matches!(
934 *event,
935 TransientBrowsingContextEvent::Closed {
936 reason: TransientBrowsingContextCloseReason::Unknown
937 }
938 )
939 ));
940 }
941
942 #[test]
943 fn extension_popup_ime_bounds_maps_into_transient_browsing_context() {
944 let event = IpcEvent::ExtensionPopupImeBoundsUpdated {
945 profile_id: "default".to_string(),
946 browsing_context_id: TabId::new(44),
947 popup_id: PopupId::new(88),
948 update: crate::data::ime::ChromeImeBoundsUpdate {
949 composition: None,
950 selection: Some(crate::data::ime::ChromeTextSelectionBounds {
951 range_start: 1,
952 range_end: 1,
953 caret_rect: crate::data::ime::ChromeImeRect {
954 x: 10,
955 y: 20,
956 width: 2,
957 height: 16,
958 },
959 first_selection_rect: crate::data::ime::ChromeImeRect {
960 x: 10,
961 y: 20,
962 width: 2,
963 height: 16,
964 },
965 }),
966 },
967 };
968
969 let mapped = map_ipc_event_to_generic(&event).unwrap();
970 assert!(matches!(
971 mapped,
972 BrowserEvent::TransientBrowsingContext {
973 transient_browsing_context_id,
974 parent_browsing_context_id,
975 event,
976 ..
977 } if transient_browsing_context_id == TransientBrowsingContextId::new(88)
978 && parent_browsing_context_id == BrowsingContextId::new(44)
979 && matches!(
980 *event,
981 TransientBrowsingContextEvent::ImeBoundsUpdated { ref update }
982 if update.selection.as_ref().is_some_and(|selection| selection.range_start == 1)
983 )
984 ));
985 }
986
987 #[test]
988 fn prompt_ui_requested_maps_into_permission_auxiliary_window() {
989 let event = IpcEvent::PromptUiOpenRequested {
990 profile_id: "default".to_string(),
991 source_tab_id: Some(TabId::new(44)),
992 request_id: 12,
993 kind: PromptUiKind::PermissionPrompt {
994 permission: crate::data::prompt_ui::PromptUiPermissionType::Geolocation,
995 permission_key: None,
996 },
997 };
998
999 let mapped = map_ipc_event_to_generic(&event).unwrap();
1000 assert!(matches!(
1001 mapped,
1002 BrowserEvent::AuxiliaryWindowOpenRequested {
1003 profile_id,
1004 request_id: 12,
1005 source_browsing_context_id: Some(source_browsing_context_id),
1006 kind: AuxiliaryWindowKind::PermissionPrompt {
1007 permission: PermissionPromptType::Geolocation
1008 },
1009 } if profile_id == "default"
1010 && source_browsing_context_id == BrowsingContextId::new(44)
1011 ));
1012 }
1013
1014 #[test]
1015 fn prompt_ui_resolved_maps_into_permission_auxiliary_resolution() {
1016 let event = IpcEvent::PromptUiResolved {
1017 profile_id: "default".to_string(),
1018 source_tab_id: Some(TabId::new(44)),
1019 request_id: 12,
1020 resolution: crate::data::prompt_ui::PromptUiResolution::PermissionPrompt {
1021 permission: crate::data::prompt_ui::PromptUiPermissionType::Geolocation,
1022 permission_key: None,
1023 result: crate::data::prompt_ui::PromptUiResolutionResult::Denied,
1024 },
1025 };
1026
1027 let mapped = map_ipc_event_to_generic(&event).unwrap();
1028 assert!(matches!(
1029 mapped,
1030 BrowserEvent::AuxiliaryWindowResolved {
1031 profile_id,
1032 request_id: 12,
1033 source_browsing_context_id: Some(source_browsing_context_id),
1034 resolution: AuxiliaryWindowResolution::PermissionPrompt {
1035 permission: PermissionPromptType::Geolocation,
1036 result: PermissionPromptResult::Denied
1037 },
1038 } if profile_id == "default"
1039 && source_browsing_context_id == BrowsingContextId::new(44)
1040 ));
1041 }
1042
1043 #[test]
1044 fn prompt_ui_requested_maps_unknown_with_key_to_other_permission_prompt() {
1045 let event = IpcEvent::PromptUiOpenRequested {
1046 profile_id: "default".to_string(),
1047 source_tab_id: Some(TabId::new(44)),
1048 request_id: 12,
1049 kind: PromptUiKind::PermissionPrompt {
1050 permission: crate::data::prompt_ui::PromptUiPermissionType::Unknown,
1051 permission_key: Some("window_management".to_string()),
1052 },
1053 };
1054
1055 let mapped = map_ipc_event_to_generic(&event).unwrap();
1056 assert!(matches!(
1057 mapped,
1058 BrowserEvent::AuxiliaryWindowOpenRequested {
1059 source_browsing_context_id: Some(source_browsing_context_id),
1060 kind: AuxiliaryWindowKind::PermissionPrompt {
1061 permission: PermissionPromptType::Other(ref key)
1062 },
1063 ..
1064 } if source_browsing_context_id == BrowsingContextId::new(44)
1065 && key == "window_management"
1066 ));
1067 }
1068
1069 #[test]
1070 fn prompt_ui_requested_maps_download_reason_into_auxiliary_window() {
1071 let event = IpcEvent::PromptUiOpenRequested {
1072 profile_id: "default".to_string(),
1073 source_tab_id: Some(TabId::new(12)),
1074 request_id: 71,
1075 kind: PromptUiKind::DownloadPrompt {
1076 download_id: crate::data::download::ChromeDownloadId::new(55),
1077 file_name: "file.bin".to_string(),
1078 total_bytes: Some(42),
1079 suggested_path: Some("/tmp/file.bin".to_string()),
1080 reason: ChromeDownloadPromptReason::SaveAs,
1081 },
1082 };
1083
1084 let mapped = map_ipc_event_to_generic(&event).unwrap();
1085 assert!(matches!(
1086 mapped,
1087 BrowserEvent::AuxiliaryWindowOpenRequested {
1088 request_id: 71,
1089 source_browsing_context_id: Some(source_browsing_context_id),
1090 kind: AuxiliaryWindowKind::DownloadPrompt {
1091 action_hint: DownloadPromptActionHint::SelectDestination,
1092 ..
1093 },
1094 ..
1095 } if source_browsing_context_id == BrowsingContextId::new(12)
1096 ));
1097 }
1098
1099 #[test]
1100 fn prompt_ui_requested_maps_dlp_reason_into_deny_action_hint() {
1101 let event = IpcEvent::PromptUiOpenRequested {
1102 profile_id: "default".to_string(),
1103 source_tab_id: Some(TabId::new(12)),
1104 request_id: 72,
1105 kind: PromptUiKind::DownloadPrompt {
1106 download_id: crate::data::download::ChromeDownloadId::new(56),
1107 file_name: "file.bin".to_string(),
1108 total_bytes: Some(42),
1109 suggested_path: Some("/tmp/file.bin".to_string()),
1110 reason: ChromeDownloadPromptReason::DlpBlocked,
1111 },
1112 };
1113
1114 let mapped = map_ipc_event_to_generic(&event).unwrap();
1115 assert!(matches!(
1116 mapped,
1117 BrowserEvent::AuxiliaryWindowOpenRequested {
1118 request_id: 72,
1119 source_browsing_context_id: Some(source_browsing_context_id),
1120 kind: AuxiliaryWindowKind::DownloadPrompt {
1121 action_hint: DownloadPromptActionHint::Deny,
1122 ..
1123 },
1124 ..
1125 } if source_browsing_context_id == BrowsingContextId::new(12)
1126 ));
1127 }
1128
1129 #[test]
1130 fn prompt_ui_open_requested_maps_extension_install_kind() {
1131 let event = IpcEvent::PromptUiOpenRequested {
1132 profile_id: "default".to_string(),
1133 source_tab_id: Some(TabId::new(9)),
1134 request_id: 2,
1135 kind: PromptUiKind::ExtensionInstallPrompt {
1136 extension_id: "ext".to_string(),
1137 extension_name: "ExtName".to_string(),
1138 permission_names: vec!["tabs".to_string()],
1139 },
1140 };
1141
1142 let mapped = map_ipc_event_to_generic(&event).unwrap();
1143 assert!(matches!(
1144 mapped,
1145 BrowserEvent::AuxiliaryWindowOpenRequested {
1146 request_id: 2,
1147 source_browsing_context_id: Some(source_browsing_context_id),
1148 kind: AuxiliaryWindowKind::ExtensionInstallPrompt {
1149 ref extension_id,
1150 ref extension_name,
1151 ref permission_names,
1152 },
1153 ..
1154 } if source_browsing_context_id == BrowsingContextId::new(9)
1155 && extension_id == "ext"
1156 && extension_name == "ExtName"
1157 && permission_names == &vec!["tabs".to_string()]
1158 ));
1159 }
1160
1161 #[test]
1162 fn prompt_ui_resolved_maps_extension_install_resolution() {
1163 let event = IpcEvent::PromptUiResolved {
1164 profile_id: "default".to_string(),
1165 source_tab_id: Some(TabId::new(9)),
1166 request_id: 5,
1167 resolution: PromptUiResolution::ExtensionInstallPrompt {
1168 extension_id: "ext".to_string(),
1169 result: PromptUiExtensionInstallResult::UserCanceled,
1170 detail: Some("user dismissed".to_string()),
1171 },
1172 };
1173
1174 let mapped = map_ipc_event_to_generic(&event).unwrap();
1175 assert!(matches!(
1176 mapped,
1177 BrowserEvent::AuxiliaryWindowResolved {
1178 request_id: 5,
1179 source_browsing_context_id: Some(source_browsing_context_id),
1180 resolution: AuxiliaryWindowResolution::ExtensionInstallPrompt {
1181 ref extension_id,
1182 result: ExtensionInstallPromptResult::UserCanceled,
1183 detail: Some(ref detail),
1184 },
1185 ..
1186 } if source_browsing_context_id == BrowsingContextId::new(9)
1187 && extension_id == "ext"
1188 && detail == "user dismissed"
1189 ));
1190 }
1191
1192 #[test]
1193 fn prompt_ui_open_requested_maps_extension_uninstall_kind() {
1194 let event = IpcEvent::PromptUiOpenRequested {
1195 profile_id: "default".to_string(),
1196 source_tab_id: None,
1197 request_id: 6,
1198 kind: PromptUiKind::ExtensionUninstallPrompt {
1199 extension_id: "ext".to_string(),
1200 extension_name: "ExtName".to_string(),
1201 triggering_extension_name: Some("Trigger".to_string()),
1202 can_report_abuse: true,
1203 },
1204 };
1205
1206 let mapped = map_ipc_event_to_generic(&event).unwrap();
1207 assert!(matches!(
1208 mapped,
1209 BrowserEvent::AuxiliaryWindowOpenRequested {
1210 request_id: 6,
1211 source_browsing_context_id: None,
1212 kind: AuxiliaryWindowKind::ExtensionUninstallPrompt {
1213 ref extension_id,
1214 ref extension_name,
1215 ref triggering_extension_name,
1216 can_report_abuse: true,
1217 },
1218 ..
1219 } if extension_id == "ext"
1220 && extension_name == "ExtName"
1221 && triggering_extension_name.as_deref() == Some("Trigger")
1222 ));
1223 }
1224
1225 #[test]
1226 fn prompt_ui_resolved_maps_extension_uninstall_resolution() {
1227 let event = IpcEvent::PromptUiResolved {
1228 profile_id: "default".to_string(),
1229 source_tab_id: None,
1230 request_id: 7,
1231 resolution: PromptUiResolution::ExtensionUninstallPrompt {
1232 extension_id: "ext".to_string(),
1233 result: PromptUiExtensionUninstallResult::Failed,
1234 detail: Some("uninstall_failed".to_string()),
1235 report_abuse: true,
1236 },
1237 };
1238
1239 let mapped = map_ipc_event_to_generic(&event).unwrap();
1240 assert!(matches!(
1241 mapped,
1242 BrowserEvent::AuxiliaryWindowResolved {
1243 request_id: 7,
1244 source_browsing_context_id: None,
1245 resolution: AuxiliaryWindowResolution::ExtensionUninstallPrompt {
1246 ref extension_id,
1247 result: ExtensionUninstallPromptResult::Failed,
1248 detail: Some(ref detail),
1249 report_abuse: true,
1250 },
1251 ..
1252 } if extension_id == "ext" && detail == "uninstall_failed"
1253 ));
1254 }
1255
1256 #[test]
1257 fn prompt_ui_opened_maps_into_auxiliary_window_opened() {
1258 let event = IpcEvent::PromptUiOpened {
1259 profile_id: "default".to_string(),
1260 source_tab_id: Some(TabId::new(11)),
1261 prompt_ui_id: PromptUiId::new(88),
1262 kind: PromptUiKind::PrintPreviewDialog,
1263 title: Some("Print".to_string()),
1264 modal: true,
1265 };
1266
1267 let mapped = map_ipc_event_to_generic(&event).unwrap();
1268 assert!(matches!(
1269 mapped,
1270 BrowserEvent::AuxiliaryWindowOpened {
1271 source_browsing_context_id: Some(source_browsing_context_id),
1272 window_id,
1273 kind: AuxiliaryWindowKind::PrintPreviewDialog,
1274 title: Some(ref title),
1275 modal: true,
1276 ..
1277 } if source_browsing_context_id == BrowsingContextId::new(11)
1278 && window_id == AuxiliaryWindowId::new(88)
1279 && title == "Print"
1280 ));
1281 }
1282
1283 #[test]
1284 fn prompt_ui_closed_maps_into_auxiliary_window_closed() {
1285 let event = IpcEvent::PromptUiClosed {
1286 profile_id: "default".to_string(),
1287 source_tab_id: Some(TabId::new(11)),
1288 prompt_ui_id: PromptUiId::new(88),
1289 kind: PromptUiKind::PrintPreviewDialog,
1290 reason: PromptUiCloseReason::SystemDismissed,
1291 };
1292
1293 let mapped = map_ipc_event_to_generic(&event).unwrap();
1294 assert!(matches!(
1295 mapped,
1296 BrowserEvent::AuxiliaryWindowClosed {
1297 source_browsing_context_id: Some(source_browsing_context_id),
1298 window_id,
1299 kind: AuxiliaryWindowKind::PrintPreviewDialog,
1300 reason: AuxiliaryWindowCloseReason::SystemDismissed,
1301 ..
1302 } if source_browsing_context_id == BrowsingContextId::new(11)
1303 && window_id == AuxiliaryWindowId::new(88)
1304 ));
1305 }
1306}