1use base::id::WebViewId;
6use rustc_hash::FxHashMap;
7
8#[derive(Debug)]
9pub struct WebViewManager<WebView> {
10 webviews: FxHashMap<WebViewId, WebView>,
13
14 focus_order: Vec<WebViewId>,
16
17 is_focused: bool,
19}
20
21impl<WebView> Default for WebViewManager<WebView> {
22 fn default() -> Self {
23 Self {
24 webviews: FxHashMap::default(),
25 focus_order: Vec::default(),
26 is_focused: false,
27 }
28 }
29}
30
31impl<WebView> WebViewManager<WebView> {
32 pub fn add(&mut self, webview_id: WebViewId, webview: WebView) {
33 self.webviews.insert(webview_id, webview);
34 }
35
36 pub fn remove(&mut self, webview_id: WebViewId) -> Option<WebView> {
37 if self.focus_order.last() == Some(&webview_id) {
38 self.is_focused = false;
39 }
40 self.focus_order.retain(|b| *b != webview_id);
41 self.webviews.remove(&webview_id)
42 }
43
44 pub fn get(&self, webview_id: WebViewId) -> Option<&WebView> {
45 self.webviews.get(&webview_id)
46 }
47
48 pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> {
49 self.webviews.get_mut(&webview_id)
50 }
51
52 pub fn focused_webview(&self) -> Option<(WebViewId, &WebView)> {
53 if !self.is_focused {
54 return None;
55 }
56
57 if let Some(webview_id) = self.focus_order.last().cloned() {
58 debug_assert!(
59 self.webviews.contains_key(&webview_id),
60 "BUG: webview in .focus_order not in .webviews!",
61 );
62 self.get(webview_id).map(|webview| (webview_id, webview))
63 } else {
64 debug_assert!(false, "BUG: .is_focused but no webviews in .focus_order!");
65 None
66 }
67 }
68
69 pub fn focus(&mut self, webview_id: WebViewId) -> Result<(), ()> {
70 if !self.webviews.contains_key(&webview_id) {
71 return Err(());
72 }
73 self.focus_order.retain(|b| *b != webview_id);
74 self.focus_order.push(webview_id);
75 self.is_focused = true;
76 Ok(())
77 }
78
79 pub fn unfocus(&mut self) {
80 self.is_focused = false;
81 }
82}
83
84#[cfg(test)]
85mod test {
86 use base::id::{
87 BrowsingContextId, Index, PipelineNamespace, PipelineNamespaceId, TEST_PAINTER_ID,
88 WebViewId,
89 };
90
91 use crate::webview_manager::WebViewManager;
92
93 fn id(namespace_id: u32, index: u32) -> WebViewId {
94 WebViewId::mock_for_testing(BrowsingContextId {
95 namespace_id: PipelineNamespaceId(namespace_id),
96 index: Index::new(index).expect("Incorrect test case"),
97 })
98 }
99
100 fn webviews_sorted<WebView: Clone>(
101 webviews: &WebViewManager<WebView>,
102 ) -> Vec<(WebViewId, WebView)> {
103 let mut keys = webviews.webviews.keys().collect::<Vec<_>>();
104 keys.sort_unstable();
105 keys.iter()
106 .map(|&id| {
107 (
108 *id,
109 webviews
110 .webviews
111 .get(id)
112 .cloned()
113 .expect("Incorrect test case"),
114 )
115 })
116 .collect()
117 }
118
119 #[test]
120 fn test() {
121 PipelineNamespace::install(PipelineNamespaceId(0));
122 let mut webviews = WebViewManager::default();
123
124 webviews.add(WebViewId::new(TEST_PAINTER_ID), 'a');
126 webviews.add(WebViewId::new(TEST_PAINTER_ID), 'b');
127 webviews.add(WebViewId::new(TEST_PAINTER_ID), 'c');
128 assert_eq!(
129 webviews_sorted(&webviews),
130 vec![(id(0, 1), 'a'), (id(0, 2), 'b'), (id(0, 3), 'c'),]
131 );
132 assert!(webviews.focus_order.is_empty());
133 assert_eq!(webviews.is_focused, false);
134
135 let _ = webviews.focus(id(0, 2));
137 assert_eq!(webviews.focus_order, vec![id(0, 2)]);
138 assert_eq!(webviews.is_focused, true);
139 let _ = webviews.focus(id(0, 1));
140 assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1)]);
141 assert_eq!(webviews.is_focused, true);
142 let _ = webviews.focus(id(0, 3));
143 assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1), id(0, 3)]);
144 assert_eq!(webviews.is_focused, true);
145
146 webviews.unfocus();
148 assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1), id(0, 3)]);
149 assert_eq!(webviews.is_focused, false);
150
151 let _ = webviews.focus(id(0, 1));
153 assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 3), id(0, 1)]);
154 assert_eq!(webviews.is_focused, true);
155
156 webviews.remove(id(1, 1));
158 assert_eq!(webviews.is_focused, true);
159 webviews.remove(id(1, 2));
160 assert_eq!(webviews.is_focused, true);
161 webviews.remove(id(2, 1));
162 assert_eq!(webviews.is_focused, true);
163 webviews.remove(id(2, 2));
164 assert_eq!(webviews.is_focused, true);
165 webviews.remove(id(2, 3));
166 assert_eq!(webviews.is_focused, true);
167 webviews.remove(id(2, 4));
168 assert_eq!(webviews.is_focused, true);
169 webviews.remove(id(3, 1));
170 assert_eq!(webviews.is_focused, true);
171 webviews.remove(id(4, 1));
172 assert_eq!(webviews.is_focused, true);
173 webviews.remove(id(0, 2));
174 assert_eq!(webviews.is_focused, true);
175 webviews.remove(id(0, 1));
176 assert_eq!(webviews.is_focused, false);
177 webviews.remove(id(0, 3));
178 assert_eq!(webviews.is_focused, false);
179
180 assert!(webviews_sorted(&webviews).is_empty());
182 assert!(webviews.focus_order.is_empty());
183 }
184}