constellation/browsingcontext.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use base::id::{BrowsingContextGroupId, BrowsingContextId, PipelineId, WebViewId};
6use embedder_traits::ViewportDetails;
7use log::warn;
8use rustc_hash::{FxHashMap, FxHashSet};
9
10use crate::pipeline::Pipeline;
11
12/// Because a browsing context is only constructed once the document that's
13/// going to be in it becomes active (i.e. not when a pipeline is spawned), some
14/// values needed in browsing context are not easily available at the point of
15/// constructing it. Thus, every time a pipeline is created for a browsing
16/// context which doesn't exist yet, these values needed for the new browsing
17/// context are stored here so that they may be available later.
18#[derive(Debug)]
19pub struct NewBrowsingContextInfo {
20 /// The parent pipeline that contains this browsing context. `None` if this
21 /// is a top level browsing context.
22 pub parent_pipeline_id: Option<PipelineId>,
23
24 /// Whether this browsing context is in private browsing mode.
25 pub is_private: bool,
26
27 /// Whether this browsing context inherits a secure context.
28 pub inherited_secure_context: Option<bool>,
29
30 /// Whether this browsing context should be throttled, using less resources
31 /// by stopping animations and running timers at a heavily limited rate.
32 pub throttled: bool,
33}
34
35/// The constellation's view of a browsing context.
36/// Each browsing context has a session history, caused by navigation and
37/// traversing the history. Each browsing context has its current entry, plus
38/// past and future entries. The past is sorted chronologically, the future is
39/// sorted reverse chronologically: in particular prev.pop() is the latest
40/// past entry, and next.pop() is the earliest future entry.
41pub struct BrowsingContext {
42 /// The browsing context group id where the top-level of this bc is found.
43 pub bc_group_id: BrowsingContextGroupId,
44
45 /// The browsing context id.
46 pub id: BrowsingContextId,
47
48 /// The top-level browsing context ancestor
49 pub webview_id: WebViewId,
50
51 /// The [`ViewportDetails`] of the frame that this [`BrowsingContext`] represents.
52 pub viewport_details: ViewportDetails,
53
54 /// Whether this browsing context is in private browsing mode.
55 pub is_private: bool,
56
57 /// Whether this browsing context inherits a secure context.
58 pub inherited_secure_context: Option<bool>,
59
60 /// Whether this browsing context should be throttled, using less resources
61 /// by stopping animations and running timers at a heavily limited rate.
62 pub throttled: bool,
63
64 /// The pipeline for the current session history entry.
65 pub pipeline_id: PipelineId,
66
67 /// The parent pipeline that contains this browsing context. `None` if this
68 /// is a top level browsing context.
69 pub parent_pipeline_id: Option<PipelineId>,
70
71 /// All the pipelines that have been presented or will be presented in
72 /// this browsing context.
73 pub pipelines: FxHashSet<PipelineId>,
74}
75
76impl BrowsingContext {
77 /// Create a new browsing context.
78 /// Note this just creates the browsing context, it doesn't add it to the constellation's set of browsing contexts.
79 #[allow(clippy::too_many_arguments)]
80 pub fn new(
81 bc_group_id: BrowsingContextGroupId,
82 id: BrowsingContextId,
83 webview_id: WebViewId,
84 pipeline_id: PipelineId,
85 parent_pipeline_id: Option<PipelineId>,
86 viewport_details: ViewportDetails,
87 is_private: bool,
88 inherited_secure_context: Option<bool>,
89 throttled: bool,
90 ) -> BrowsingContext {
91 let mut pipelines = FxHashSet::default();
92 pipelines.insert(pipeline_id);
93 BrowsingContext {
94 bc_group_id,
95 id,
96 webview_id,
97 viewport_details,
98 is_private,
99 inherited_secure_context,
100 throttled,
101 pipeline_id,
102 parent_pipeline_id,
103 pipelines,
104 }
105 }
106
107 pub fn update_current_entry(&mut self, pipeline_id: PipelineId) {
108 self.pipeline_id = pipeline_id;
109 }
110
111 /// Is this a top-level browsing context?
112 pub fn is_top_level(&self) -> bool {
113 self.id == self.webview_id
114 }
115}
116
117/// An iterator over browsing contexts, returning the descendant
118/// contexts whose active documents are fully active, in depth-first
119/// order.
120pub struct FullyActiveBrowsingContextsIterator<'a> {
121 /// The browsing contexts still to iterate over.
122 pub stack: Vec<BrowsingContextId>,
123
124 /// The set of all browsing contexts.
125 pub browsing_contexts: &'a FxHashMap<BrowsingContextId, BrowsingContext>,
126
127 /// The set of all pipelines. We use this to find the active
128 /// children of a frame, which are the iframes in the currently
129 /// active document.
130 pub pipelines: &'a FxHashMap<PipelineId, Pipeline>,
131}
132
133impl<'a> Iterator for FullyActiveBrowsingContextsIterator<'a> {
134 type Item = &'a BrowsingContext;
135 fn next(&mut self) -> Option<&'a BrowsingContext> {
136 loop {
137 let browsing_context_id = self.stack.pop()?;
138 let browsing_context = match self.browsing_contexts.get(&browsing_context_id) {
139 Some(browsing_context) => browsing_context,
140 None => {
141 warn!(
142 "BrowsingContext {:?} iterated after closure.",
143 browsing_context_id
144 );
145 continue;
146 },
147 };
148 let pipeline = match self.pipelines.get(&browsing_context.pipeline_id) {
149 Some(pipeline) => pipeline,
150 None => {
151 warn!(
152 "Pipeline {:?} iterated after closure.",
153 browsing_context.pipeline_id
154 );
155 continue;
156 },
157 };
158 self.stack.extend(pipeline.children.iter());
159 return Some(browsing_context);
160 }
161 }
162}
163
164/// An iterator over browsing contexts, returning all descendant
165/// contexts in depth-first order. Note that this iterator returns all
166/// contexts, not just the fully active ones.
167pub struct AllBrowsingContextsIterator<'a> {
168 /// The browsing contexts still to iterate over.
169 pub stack: Vec<BrowsingContextId>,
170
171 /// The set of all browsing contexts.
172 pub browsing_contexts: &'a FxHashMap<BrowsingContextId, BrowsingContext>,
173
174 /// The set of all pipelines. We use this to find the
175 /// children of a browsing context, which are the iframes in all documents
176 /// in the session history.
177 pub pipelines: &'a FxHashMap<PipelineId, Pipeline>,
178}
179
180impl<'a> Iterator for AllBrowsingContextsIterator<'a> {
181 type Item = &'a BrowsingContext;
182 fn next(&mut self) -> Option<&'a BrowsingContext> {
183 let pipelines = self.pipelines;
184 loop {
185 let browsing_context_id = self.stack.pop()?;
186 let browsing_context = match self.browsing_contexts.get(&browsing_context_id) {
187 Some(browsing_context) => browsing_context,
188 None => {
189 warn!(
190 "BrowsingContext {:?} iterated after closure.",
191 browsing_context_id
192 );
193 continue;
194 },
195 };
196 let child_browsing_context_ids = browsing_context
197 .pipelines
198 .iter()
199 .filter_map(|pipeline_id| pipelines.get(pipeline_id))
200 .flat_map(|pipeline| pipeline.children.iter());
201 self.stack.extend(child_browsing_context_ids);
202 return Some(browsing_context);
203 }
204 }
205}