Skip to content

Commit

Permalink
Replace script thread root browsing context by a collection of docume…
Browse files Browse the repository at this point in the history
…nts.
  • Loading branch information
Alan Jeffrey committed Nov 8, 2016
1 parent dae007f commit 90e9c91
Show file tree
Hide file tree
Showing 8 changed files with 494 additions and 668 deletions.
6 changes: 5 additions & 1 deletion components/constellation/constellation.rs
Expand Up @@ -1623,12 +1623,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
pipeline_id: PipelineId,
event: MozBrowserEvent) {
assert!(PREFS.is_mozbrowser_enabled());
let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);

// Find the script channel for the given parent pipeline,
// and pass the event to that script thread.
// If the pipeline lookup fails, it is because we have torn down the pipeline,
// so it is reasonable to silently ignore the event.
let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
match self.pipelines.get(&parent_pipeline_id) {
Some(pipeline) => pipeline.trigger_mozbrowser_event(frame_id, event),
None => warn!("Pipeline {:?} handling mozbrowser event after closure.", parent_pipeline_id),
Expand Down Expand Up @@ -2206,6 +2206,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

// Close a frame (and all children)
fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
debug!("Closing frame {:?}.", frame_id);
// Store information about the pipelines to be closed. Then close the
// pipelines, before removing ourself from the frames hash map. This
// ordering is vital - so that if close_pipeline() ends up closing
Expand Down Expand Up @@ -2241,10 +2242,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
};
parent_pipeline.remove_child(frame_id);
}
debug!("Closed frame {:?}.", frame_id);
}

// Close all pipelines at and beneath a given frame
fn close_pipeline(&mut self, pipeline_id: PipelineId, exit_mode: ExitPipelineMode) {
debug!("Closing pipeline {:?}.", pipeline_id);
// Store information about the frames to be closed. Then close the
// frames, before removing ourself from the pipelines hash map. This
// ordering is vital - so that if close_frames() ends up closing
Expand Down Expand Up @@ -2284,6 +2287,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
ExitPipelineMode::Normal => pipeline.exit(),
ExitPipelineMode::Force => pipeline.force_exit(),
}
debug!("Closed pipeline {:?}.", pipeline_id);
}

// Randomly close a pipeline -if --random-pipeline-closure-probability is set
Expand Down
108 changes: 40 additions & 68 deletions components/script/devtools.rs
Expand Up @@ -17,15 +17,15 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
use dom::browsingcontext::BrowsingContext;
use dom::element::Element;
use dom::globalscope::GlobalScope;
use dom::node::Node;
use dom::node::{Node, window_from_node};
use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{JSAutoCompartment, ObjectClassName};
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
use script_thread::Documents;
use std::ffi::CStr;
use std::str;
use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top};
Expand Down Expand Up @@ -72,53 +72,35 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
reply.send(result).unwrap();
}

pub fn handle_get_root_node(context: &BrowsingContext, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
let context = match context.find(pipeline) {
Some(found_context) => found_context,
None => return reply.send(None).unwrap()
};

let document = context.active_document();

let node = document.upcast::<Node>();
reply.send(Some(node.summarize())).unwrap();
pub fn handle_get_root_node(documents: &Documents, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
let info = documents.find_document(pipeline)
.map(|document| document.upcast::<Node>().summarize());
reply.send(info).unwrap();
}

pub fn handle_get_document_element(context: &BrowsingContext,
pub fn handle_get_document_element(documents: &Documents,
pipeline: PipelineId,
reply: IpcSender<Option<NodeInfo>>) {
let context = match context.find(pipeline) {
Some(found_context) => found_context,
None => return reply.send(None).unwrap()
};

let document = context.active_document();
let document_element = document.GetDocumentElement().unwrap();

let node = document_element.upcast::<Node>();
reply.send(Some(node.summarize())).unwrap();
let info = documents.find_document(pipeline)
.and_then(|document| document.GetDocumentElement())
.map(|element| element.upcast::<Node>().summarize());
reply.send(info).unwrap();
}

fn find_node_by_unique_id(context: &BrowsingContext,
fn find_node_by_unique_id(documents: &Documents,
pipeline: PipelineId,
node_id: &str)
-> Option<Root<Node>> {
let context = match context.find(pipeline) {
Some(found_context) => found_context,
None => return None
};

let document = context.active_document();
let node = document.upcast::<Node>();

node.traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
documents.find_document(pipeline).and_then(|document|
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
)
}

pub fn handle_get_children(context: &BrowsingContext,
pub fn handle_get_children(documents: &Documents,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<Option<Vec<NodeInfo>>>) {
match find_node_by_unique_id(context, pipeline, &*node_id) {
match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return reply.send(None).unwrap(),
Some(parent) => {
let children = parent.children()
Expand All @@ -130,11 +112,11 @@ pub fn handle_get_children(context: &BrowsingContext,
};
}

pub fn handle_get_layout(context: &BrowsingContext,
pub fn handle_get_layout(documents: &Documents,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<Option<ComputedNodeLayout>>) {
let node = match find_node_by_unique_id(context, pipeline, &*node_id) {
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return reply.send(None).unwrap(),
Some(found_node) => found_node
};
Expand All @@ -144,7 +126,7 @@ pub fn handle_get_layout(context: &BrowsingContext,
let width = rect.Width() as f32;
let height = rect.Height() as f32;

let window = context.active_window();
let window = window_from_node(&*node);
let elem = node.downcast::<Element>().expect("should be getting layout of element");
let computed_style = window.GetComputedStyle(elem, None);

Expand Down Expand Up @@ -223,11 +205,11 @@ pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
reply.send(messages).unwrap();
}

pub fn handle_modify_attribute(context: &BrowsingContext,
pub fn handle_modify_attribute(documents: &Documents,
pipeline: PipelineId,
node_id: String,
modifications: Vec<Modification>) {
let node = match find_node_by_unique_id(context, pipeline, &*node_id) {
let node = match find_node_by_unique_id(documents, pipeline, &*node_id) {
None => return warn!("node id {} for pipeline id {} is not found", &node_id, &pipeline),
Some(found_node) => found_node
};
Expand All @@ -249,49 +231,39 @@ pub fn handle_wants_live_notifications(global: &GlobalScope, send_notifications:
global.set_devtools_wants_updates(send_notifications);
}

pub fn handle_set_timeline_markers(context: &BrowsingContext,
pub fn handle_set_timeline_markers(documents: &Documents,
pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>,
reply: IpcSender<Option<TimelineMarker>>) {
match context.find(pipeline) {
match documents.find_window(pipeline) {
None => reply.send(None).unwrap(),
Some(context) => context.active_window().set_devtools_timeline_markers(marker_types, reply),
Some(window) => window.set_devtools_timeline_markers(marker_types, reply),
}
}

pub fn handle_drop_timeline_markers(context: &BrowsingContext,
pub fn handle_drop_timeline_markers(documents: &Documents,
pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>) {
if let Some(context) = context.find(pipeline) {
context.active_window().drop_devtools_timeline_markers(marker_types);
if let Some(window) = documents.find_window(pipeline) {
window.drop_devtools_timeline_markers(marker_types);
}
}

pub fn handle_request_animation_frame(context: &BrowsingContext,
pub fn handle_request_animation_frame(documents: &Documents,
id: PipelineId,
actor_name: String) {
let context = match context.find(id) {
None => return warn!("context for pipeline id {} is not found", id),
Some(found_node) => found_node
};

let doc = context.active_document();
let devtools_sender =
context.active_window().upcast::<GlobalScope>().devtools_chan().unwrap().clone();
doc.request_animation_frame(box move |time| {
let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name, time);
devtools_sender.send(msg).unwrap();
});
if let Some(doc) = documents.find_document(id) {
let devtools_sender = doc.window().upcast::<GlobalScope>().devtools_chan().unwrap().clone();
doc.request_animation_frame(box move |time| {
let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name, time);
devtools_sender.send(msg).unwrap();
});
}
}

pub fn handle_reload(context: &BrowsingContext,
pub fn handle_reload(documents: &Documents,
id: PipelineId) {
let context = match context.find(id) {
None => return warn!("context for pipeline id {} is not found", id),
Some(found_node) => found_node
};

let win = context.active_window();
let location = win.Location();
location.Reload();
if let Some(win) = documents.find_window(id) {
win.Location().Reload();
}
}
83 changes: 6 additions & 77 deletions components/script/dom/browsingcontext.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand All @@ -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());
Expand All @@ -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 _));
Expand Down Expand Up @@ -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)]
Expand Down

0 comments on commit 90e9c91

Please sign in to comment.