Allow windows to share browsing contexts.

This commit is contained in:
Alan Jeffrey 2017-01-13 18:17:01 -06:00
parent fc67878edf
commit 403499a9d5
11 changed files with 168 additions and 108 deletions

View file

@ -41,7 +41,7 @@ use dom::bindings::str::DOMString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::WRAP_CALLBACKS;
use dom::browsingcontext::BrowsingContext;
use dom::document::{Document, DocumentSource, FocusType, IsHTMLDocument, TouchEventResult};
use dom::document::{Document, DocumentSource, FocusType, HasBrowsingContext, IsHTMLDocument, TouchEventResult};
use dom::element::Element;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::globalscope::GlobalScope;
@ -391,13 +391,15 @@ impl<'a> Iterator for DocumentsIter<'a> {
}
}
#[derive(JSTraceable)]
// ScriptThread instances are rooted on creation, so this is okay
#[allow(unrooted_must_root)]
pub struct ScriptThread {
/// The documents for pipelines managed by this thread
documents: DOMRefCell<Documents>,
/// The browsing contexts known by this thread
/// TODO: this map grows, but never shrinks. Issue #15258.
browsing_contexts: DOMRefCell<HashMap<FrameId, JS<BrowsingContext>>>,
/// A list of data pertaining to loads that have not yet received a network response
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
/// A map to store service worker registrations for a given origin
@ -651,6 +653,7 @@ impl ScriptThread {
ScriptThread {
documents: DOMRefCell::new(Documents::new()),
browsing_contexts: DOMRefCell::new(HashMap::new()),
incomplete_loads: DOMRefCell::new(vec!()),
registration_map: DOMRefCell::new(HashMap::new()),
job_queue_map: Rc::new(JobQueue::new()),
@ -1514,29 +1517,26 @@ impl ScriptThread {
load.pipeline_id == id
});
if let Some(idx) = idx {
let chan = if let Some(idx) = idx {
let load = self.incomplete_loads.borrow_mut().remove(idx);
// Tell the layout thread to begin shutting down, and wait until it
// processed this message.
let (response_chan, response_port) = channel();
let chan = &load.layout_chan;
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
debug!("shutting down layout for page {}", id);
response_port.recv().unwrap();
chan.send(message::Msg::ExitNow).ok();
}
}
if let Some(document) = self.documents.borrow_mut().remove(id) {
shut_down_layout(document.window());
load.layout_chan.clone()
} else if let Some(document) = self.documents.borrow_mut().remove(id) {
let window = document.window();
if discard_bc == DiscardBrowsingContext::Yes {
if let Some(context) = document.browsing_context() {
context.discard();
}
window.browsing_context().discard();
}
let _ = self.constellation_chan.send(ConstellationMsg::PipelineExited(id));
}
window.clear_js_runtime();
window.layout_chan().clone()
} else {
return warn!("Exiting nonexistant pipeline {}.", id);
};
let (response_chan, response_port) = channel();
chan.send(message::Msg::PrepareToExit(response_chan)).ok();
debug!("shutting down layout for page {}", id);
response_port.recv().unwrap();
chan.send(message::Msg::ExitNow).ok();
self.constellation_chan.send(ConstellationMsg::PipelineExited(id)).ok();
debug!("Exited pipeline {}.", id);
}
@ -1693,8 +1693,18 @@ impl ScriptThread {
self.webvr_thread.clone());
let frame_element = frame_element.r().map(Castable::upcast);
let browsing_context = BrowsingContext::new(&window, frame_element);
window.init_browsing_context(&browsing_context);
match self.browsing_contexts.borrow_mut().entry(incomplete.frame_id) {
hash_map::Entry::Vacant(entry) => {
let browsing_context = BrowsingContext::new(&window, frame_element);
entry.insert(JS::from_ref(&*browsing_context));
window.init_browsing_context(&browsing_context);
},
hash_map::Entry::Occupied(entry) => {
let browsing_context = entry.get();
browsing_context.set_window_proxy(&window);
window.init_browsing_context(browsing_context);
},
}
let last_modified = metadata.headers.as_ref().and_then(|headers| {
headers.get().map(|&LastModified(HttpDate(ref tm))| dom_last_modified(tm))
@ -1735,7 +1745,7 @@ impl ScriptThread {
.map(ReferrerPolicy::from);
let document = Document::new(&window,
Some(&browsing_context),
HasBrowsingContext::Yes,
Some(final_url.clone()),
incomplete.origin,
is_html_document,
@ -2139,29 +2149,6 @@ impl Drop for ScriptThread {
}
}
/// Shuts down layout for the given window.
fn shut_down_layout(window: &Window) {
// Tell the layout thread to begin shutting down, and wait until it
// processed this message.
let (response_chan, response_port) = channel();
let chan = window.layout_chan().clone();
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
let _ = response_port.recv();
}
// The browsing context is cleared by window.clear_js_runtime(), so we need to save a copy
let browsing_context = window.browsing_context();
// Drop our references to the JSContext and DOM objects.
window.clear_js_runtime();
// Discard the browsing context.
browsing_context.discard();
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
chan.send(message::Msg::ExitNow).ok();
}
fn dom_last_modified(tm: &Tm) -> String {
tm.to_local().strftime("%m/%d/%Y %H:%M:%S").unwrap().to_string()
}