mirror of
https://github.com/servo/servo.git
synced 2025-07-30 18:50:36 +01:00
Replace script thread root browsing context by a collection of documents.
This commit is contained in:
parent
dae007fd16
commit
90e9c910f4
8 changed files with 494 additions and 668 deletions
|
@ -2,7 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
|
||||
|
@ -37,15 +36,9 @@ use std::cell::Cell;
|
|||
pub struct BrowsingContext {
|
||||
reflector: Reflector,
|
||||
|
||||
/// Pipeline id associated with this context.
|
||||
id: PipelineId,
|
||||
|
||||
/// Indicates if reflow is required when reloading.
|
||||
needs_reflow: Cell<bool>,
|
||||
|
||||
/// Stores the child browsing contexts (ex. iframe browsing context)
|
||||
children: DOMRefCell<Vec<JS<BrowsingContext>>>,
|
||||
|
||||
/// The current active document.
|
||||
/// Note that the session history is stored in the constellation,
|
||||
/// in the script thread we just track the current active document.
|
||||
|
@ -56,19 +49,17 @@ pub struct BrowsingContext {
|
|||
}
|
||||
|
||||
impl BrowsingContext {
|
||||
pub fn new_inherited(frame_element: Option<&Element>, id: PipelineId) -> BrowsingContext {
|
||||
pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
|
||||
BrowsingContext {
|
||||
reflector: Reflector::new(),
|
||||
id: id,
|
||||
needs_reflow: Cell::new(true),
|
||||
children: DOMRefCell::new(vec![]),
|
||||
active_document: Default::default(),
|
||||
frame_element: frame_element.map(JS::from_ref),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(window: &Window, frame_element: Option<&Element>, id: PipelineId) -> Root<BrowsingContext> {
|
||||
pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
|
||||
unsafe {
|
||||
let WindowProxyHandler(handler) = window.windowproxy_handler();
|
||||
assert!(!handler.is_null());
|
||||
|
@ -81,7 +72,7 @@ impl BrowsingContext {
|
|||
rooted!(in(cx) let window_proxy = NewWindowProxy(cx, parent, handler));
|
||||
assert!(!window_proxy.is_null());
|
||||
|
||||
let object = box BrowsingContext::new_inherited(frame_element, id);
|
||||
let object = box BrowsingContext::new_inherited(frame_element);
|
||||
|
||||
let raw = Box::into_raw(object);
|
||||
SetProxyExtra(window_proxy.get(), 0, &PrivateValue(raw as *const _));
|
||||
|
@ -118,82 +109,20 @@ impl BrowsingContext {
|
|||
window_proxy.get()
|
||||
}
|
||||
|
||||
pub fn remove(&self, id: PipelineId) -> Option<Root<BrowsingContext>> {
|
||||
let remove_idx = self.children
|
||||
.borrow()
|
||||
.iter()
|
||||
.position(|context| context.id == id);
|
||||
match remove_idx {
|
||||
Some(idx) => Some(Root::from_ref(&*self.children.borrow_mut().remove(idx))),
|
||||
None => {
|
||||
self.children
|
||||
.borrow_mut()
|
||||
.iter_mut()
|
||||
.filter_map(|context| context.remove(id))
|
||||
.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reflow_status(&self, status: bool) -> bool {
|
||||
let old = self.needs_reflow.get();
|
||||
self.needs_reflow.set(status);
|
||||
old
|
||||
}
|
||||
|
||||
pub fn pipeline_id(&self) -> PipelineId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn push_child_context(&self, context: &BrowsingContext) {
|
||||
self.children.borrow_mut().push(JS::from_ref(&context));
|
||||
}
|
||||
|
||||
pub fn find_child_by_id(&self, pipeline_id: PipelineId) -> Option<Root<Window>> {
|
||||
self.children.borrow().iter().find(|context| {
|
||||
let window = context.active_window();
|
||||
window.upcast::<GlobalScope>().pipeline_id() == pipeline_id
|
||||
}).map(|context| context.active_window())
|
||||
pub fn active_pipeline_id(&self) -> Option<PipelineId> {
|
||||
self.active_document.get()
|
||||
.map(|doc| doc.window().upcast::<GlobalScope>().pipeline_id())
|
||||
}
|
||||
|
||||
pub fn unset_active_document(&self) {
|
||||
self.active_document.set(None)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ContextIterator {
|
||||
ContextIterator {
|
||||
stack: vec!(Root::from_ref(self)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find(&self, id: PipelineId) -> Option<Root<BrowsingContext>> {
|
||||
if self.id == id {
|
||||
return Some(Root::from_ref(self));
|
||||
}
|
||||
|
||||
self.children.borrow()
|
||||
.iter()
|
||||
.filter_map(|c| c.find(id))
|
||||
.next()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ContextIterator {
|
||||
stack: Vec<Root<BrowsingContext>>,
|
||||
}
|
||||
|
||||
impl Iterator for ContextIterator {
|
||||
type Item = Root<BrowsingContext>;
|
||||
|
||||
fn next(&mut self) -> Option<Root<BrowsingContext>> {
|
||||
let popped = self.stack.pop();
|
||||
if let Some(ref context) = popped {
|
||||
self.stack.extend(context.children.borrow()
|
||||
.iter()
|
||||
.map(|c| Root::from_ref(&**c)));
|
||||
}
|
||||
popped
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -42,6 +42,7 @@ use js::jsval::{NullValue, UndefinedValue};
|
|||
use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
|
||||
use net_traits::response::HttpsState;
|
||||
use script_layout_interface::message::ReflowQueryType;
|
||||
use script_thread::ScriptThread;
|
||||
use script_traits::{IFrameLoadInfo, LoadData, MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
||||
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||
use servo_atoms::Atom;
|
||||
|
@ -235,7 +236,7 @@ impl HTMLIFrameElement {
|
|||
pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) {
|
||||
// TODO(#9592): assert that the load blocker is present at all times when we
|
||||
// can guarantee that it's created for the case of iframe.reload().
|
||||
assert_eq!(loaded_pipeline, self.pipeline_id().unwrap());
|
||||
if Some(loaded_pipeline) != self.pipeline_id() { return; }
|
||||
|
||||
// TODO A cross-origin child document would not be easily accessible
|
||||
// from this script thread. It's unclear how to implement
|
||||
|
@ -268,13 +269,16 @@ impl HTMLIFrameElement {
|
|||
}
|
||||
|
||||
pub fn get_content_window(&self) -> Option<Root<Window>> {
|
||||
self.pipeline_id.get().and_then(|pipeline_id| {
|
||||
let window = window_from_node(self);
|
||||
let browsing_context = window.browsing_context();
|
||||
browsing_context.find_child_by_id(pipeline_id)
|
||||
})
|
||||
self.pipeline_id.get()
|
||||
.and_then(|pipeline_id| ScriptThread::find_document(pipeline_id))
|
||||
.and_then(|document| {
|
||||
if self.global().get_url().origin() == document.global().get_url().origin() {
|
||||
Some(Root::from_ref(document.window()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait HTMLIFrameElementLayoutMethods {
|
||||
|
|
|
@ -97,6 +97,13 @@ impl NodeList {
|
|||
panic!("called as_simple_list() on a children node list")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> NodeListIterator {
|
||||
NodeListIterator {
|
||||
nodes: self,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, HeapSizeOf)]
|
||||
|
@ -277,3 +284,18 @@ impl ChildrenList {
|
|||
self.last_index.set(0u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NodeListIterator<'a> {
|
||||
nodes: &'a NodeList,
|
||||
offset: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for NodeListIterator<'a> {
|
||||
type Item = Root<Node>;
|
||||
|
||||
fn next(&mut self) -> Option<Root<Node>> {
|
||||
let result = self.nodes.Item(self.offset);
|
||||
self.offset = self.offset + 1;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ use dom::bindings::str::DOMString;
|
|||
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::storageevent::StorageEvent;
|
||||
use dom::urlhelper::UrlHelper;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use net_traits::IpcSend;
|
||||
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
||||
|
@ -193,14 +192,16 @@ impl Runnable for StorageEventRunnable {
|
|||
Some(&storage)
|
||||
);
|
||||
|
||||
let root_context = script_thread.root_browsing_context();
|
||||
for it_context in root_context.iter() {
|
||||
let it_window = it_context.active_window();
|
||||
assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
|
||||
// TODO: Such a Document object is not necessarily fully active, but events fired on such
|
||||
// objects are ignored by the event loop until the Document becomes fully active again.
|
||||
if global.pipeline_id() != it_window.upcast::<GlobalScope>().pipeline_id() {
|
||||
storage_event.upcast::<Event>().fire(it_window.upcast());
|
||||
// TODO: This is only iterating over documents in the current script
|
||||
// thread, so we are not firing events to other script threads.
|
||||
// NOTE: once that is fixed, we can remove borrow_documents from ScriptThread.
|
||||
for (id, document) in script_thread.borrow_documents().iter() {
|
||||
if ev_url.origin() == document.window().get_url().origin() {
|
||||
// TODO: Such a Document object is not necessarily fully active, but events fired on such
|
||||
// objects are ignored by the event loop until the Document becomes fully active again.
|
||||
if global.pipeline_id() != id {
|
||||
storage_event.upcast::<Event>().fire(document.window().upcast());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue