Skip to content

Commit

Permalink
remove page and move functionality to browing context
Browse files Browse the repository at this point in the history
Allow for adding history items

Fixed nested iframe test failure

Cleanup and small refactors

fixup
  • Loading branch information
cbrewster committed May 11, 2016
1 parent 392135b commit cbc5ca6
Show file tree
Hide file tree
Showing 9 changed files with 461 additions and 479 deletions.
59 changes: 32 additions & 27 deletions components/script/devtools.rs
Expand Up @@ -15,17 +15,16 @@ use dom::bindings::conversions::{FromJSValConvertible, jsstring_to_str};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::browsingcontext::{BrowsingContext, IterableContext};
use dom::element::Element;
use dom::node::Node;
use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{ObjectClassName, RootedObject, RootedValue};
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
use page::{IterablePage, Page};
use script_thread::get_page;
use script_thread::get_browsing_context;
use std::ffi::CStr;
use std::rc::Rc;
use std::str;
use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left};
use util::str::DOMString;
Expand Down Expand Up @@ -66,28 +65,31 @@ pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<Eva
reply.send(result).unwrap();
}

pub fn handle_get_root_node(page: &Rc<Page>, pipeline: PipelineId, reply: IpcSender<NodeInfo>) {
let page = get_page(&*page, pipeline);
let document = page.document();
pub fn handle_get_root_node(context: &Root<BrowsingContext>, pipeline: PipelineId, reply: IpcSender<NodeInfo>) {
let context = get_browsing_context(context, pipeline);
let document = context.active_document();

let node = document.upcast::<Node>();
reply.send(node.summarize()).unwrap();
}

pub fn handle_get_document_element(page: &Rc<Page>,
pub fn handle_get_document_element(context: &Root<BrowsingContext>,
pipeline: PipelineId,
reply: IpcSender<NodeInfo>) {
let page = get_page(&*page, pipeline);
let document = page.document();
let context = get_browsing_context(context, pipeline);
let document = context.active_document();
let document_element = document.GetDocumentElement().unwrap();

let node = document_element.upcast::<Node>();
reply.send(node.summarize()).unwrap();
}

fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String) -> Root<Node> {
let page = get_page(&*page, pipeline);
let document = page.document();
fn find_node_by_unique_id(context: &Root<BrowsingContext>,
pipeline: PipelineId,
node_id: String)
-> Root<Node> {
let context = get_browsing_context(context, pipeline);
let document = context.active_document();
let node = document.upcast::<Node>();

for candidate in node.traverse_preorder() {
Expand All @@ -99,29 +101,29 @@ fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String
panic!("couldn't find node with unique id {}", node_id)
}

pub fn handle_get_children(page: &Rc<Page>,
pub fn handle_get_children(context: &Root<BrowsingContext>,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<Vec<NodeInfo>>) {
let parent = find_node_by_unique_id(&*page, pipeline, node_id);
let parent = find_node_by_unique_id(context, pipeline, node_id);
let children = parent.children()
.map(|child| child.summarize())
.collect();
reply.send(children).unwrap();
}

pub fn handle_get_layout(page: &Rc<Page>,
pub fn handle_get_layout(context: &Root<BrowsingContext>,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<ComputedNodeLayout>) {
let node = find_node_by_unique_id(&*page, pipeline, node_id);
let node = find_node_by_unique_id(context, pipeline, node_id);

let elem = node.downcast::<Element>().expect("should be getting layout of element");
let rect = elem.GetBoundingClientRect();
let width = rect.Width() as f32;
let height = rect.Height() as f32;

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

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

pub fn handle_modify_attribute(page: &Rc<Page>,
pub fn handle_modify_attribute(context: &Root<BrowsingContext>,
pipeline: PipelineId,
node_id: String,
modifications: Vec<Modification>) {
let node = find_node_by_unique_id(&*page, pipeline, node_id);
let node = find_node_by_unique_id(context, pipeline, node_id);
let elem = node.downcast::<Element>().expect("should be getting layout of element");

for modification in modifications {
Expand All @@ -222,22 +224,25 @@ pub fn handle_wants_live_notifications(global: &GlobalRef, send_notifications: b
global.set_devtools_wants_updates(send_notifications);
}

pub fn handle_set_timeline_markers(page: &Rc<Page>,
pub fn handle_set_timeline_markers(context: &Root<BrowsingContext>,
marker_types: Vec<TimelineMarkerType>,
reply: IpcSender<TimelineMarker>) {
let window = page.window();
let window = context.active_window();
window.set_devtools_timeline_markers(marker_types, reply);
}

pub fn handle_drop_timeline_markers(page: &Rc<Page>, marker_types: Vec<TimelineMarkerType>) {
let window = page.window();
pub fn handle_drop_timeline_markers(context: &Root<BrowsingContext>,
marker_types: Vec<TimelineMarkerType>) {
let window = context.active_window();
window.drop_devtools_timeline_markers(marker_types);
}

pub fn handle_request_animation_frame(page: &Rc<Page>, id: PipelineId, actor_name: String) {
let page = page.find(id).expect("There is no such page");
let doc = page.document();
let devtools_sender = page.window().devtools_chan().unwrap();
pub fn handle_request_animation_frame(context: &Root<BrowsingContext>,
id: PipelineId,
actor_name: String) {
let context = context.find(id).expect("There is no such context");
let doc = context.active_document();
let devtools_sender = context.active_window().devtools_chan().unwrap();
doc.request_animation_frame(box move |time| {
let msg = ScriptToDevtoolsControlMsg::FramerateTick(actor_name, time);
devtools_sender.send(msg).unwrap();
Expand Down
140 changes: 129 additions & 11 deletions components/script/dom/browsingcontext.rs
Expand Up @@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
Expand All @@ -22,27 +23,48 @@ use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass, J
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle};
use js::jsapi::{MutableHandleValue, ObjectOpResult, RootedObject, RootedValue};
use js::jsval::{UndefinedValue, PrivateValue};
use msg::constellation_msg::{PipelineId, SubpageId};
use std::cell::Cell;
use url::Url;
use util::str::DOMString;

#[dom_struct]
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 this context's session history
history: DOMRefCell<Vec<SessionHistoryEntry>>,
active_index: usize,

/// The index of the active session history entry
active_index: Cell<usize>,

/// Stores the child browsing contexts (ex. iframe browsing context)
children: DOMRefCell<Vec<JS<BrowsingContext>>>,

frame_element: Option<JS<Element>>,
}

impl BrowsingContext {
pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
pub fn new_inherited(frame_element: Option<&Element>, id: PipelineId) -> BrowsingContext {
BrowsingContext {
reflector: Reflector::new(),
id: id,
needs_reflow: Cell::new(true),
history: DOMRefCell::new(vec![]),
active_index: 0,
active_index: Cell::new(0),
children: DOMRefCell::new(vec![]),
frame_element: frame_element.map(JS::from_ref),
}
}

#[allow(unsafe_code)]
pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
pub fn new(window: &Window, frame_element: Option<&Element>, id: PipelineId) -> Root<BrowsingContext> {
unsafe {
let WindowProxyHandler(handler) = window.windowproxy_handler();
assert!(!handler.is_null());
Expand All @@ -57,7 +79,7 @@ impl BrowsingContext {
NewWindowProxy(cx, parent, handler));
assert!(!window_proxy.ptr.is_null());

let object = box BrowsingContext::new_inherited(frame_element);
let object = box BrowsingContext::new_inherited(frame_element, id);

let raw = Box::into_raw(object);
SetProxyExtra(window_proxy.ptr, 0, &PrivateValue(raw as *const _));
Expand All @@ -70,12 +92,20 @@ impl BrowsingContext {

pub fn init(&self, document: &Document) {
assert!(self.history.borrow().is_empty());
assert_eq!(self.active_index, 0);
self.history.borrow_mut().push(SessionHistoryEntry::new(document));
assert_eq!(self.active_index.get(), 0);
self.history.borrow_mut().push(SessionHistoryEntry::new(document, document.url().clone(), document.Title()));
}

pub fn push_history(&self, document: &Document) {
let mut history = self.history.borrow_mut();
// Clear all session history entries after the active index
history.drain((self.active_index.get() + 1)..);
history.push(SessionHistoryEntry::new(document, document.url().clone(), document.Title()));
self.active_index.set(self.active_index.get() + 1);
}

pub fn active_document(&self) -> Root<Document> {
Root::from_ref(&*self.history.borrow()[self.active_index].document)
Root::from_ref(&self.history.borrow()[self.active_index.get()].document)
}

pub fn active_window(&self) -> Root<Window> {
Expand All @@ -91,6 +121,92 @@ impl BrowsingContext {
assert!(!window_proxy.get().is_null());
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(&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_subpage(&self, subpage_id: SubpageId) -> Option<Root<Window>> {
self.children.borrow().iter().find(|context| {
let window = context.active_window();
window.subpage() == Some(subpage_id)
}).map(|context| context.active_window())
}

pub fn clear_session_history(&self) {
self.active_index.set(0);
self.history.borrow_mut().clear();
}
}

pub struct ContextIterator {
stack: Vec<Root<BrowsingContext>>,
}

pub trait IterableContext {
fn iter(&self) -> ContextIterator;
fn find(&self, id: PipelineId) -> Option<Root<BrowsingContext>>;
}

impl IterableContext for BrowsingContext {
fn iter(&self) -> ContextIterator {
ContextIterator {
stack: vec!(Root::from_ref(self)),
}
}

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()
}
}

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()
.cloned()
.map(|ref c| Root::from_ref(&**c)));
}
popped
}
}

// This isn't a DOM struct, just a convenience struct
Expand All @@ -100,14 +216,16 @@ impl BrowsingContext {
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
document: JS<Document>,
children: Vec<JS<BrowsingContext>>,
url: Url,
title: DOMString,
}

impl SessionHistoryEntry {
fn new(document: &Document) -> SessionHistoryEntry {
fn new(document: &Document, url: Url, title: DOMString) -> SessionHistoryEntry {
SessionHistoryEntry {
document: JS::from_ref(document),
children: vec![],
url: url,
title: title,
}
}
}
Expand Down
8 changes: 2 additions & 6 deletions components/script/dom/htmliframeelement.rs
Expand Up @@ -36,7 +36,6 @@ use layout_interface::ReflowQueryType;
use msg::constellation_msg::{ConstellationChan, LoadData};
use msg::constellation_msg::{NavigationDirection, PipelineId, SubpageId};
use net_traits::response::HttpsState;
use page::IterablePage;
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg};
use std::ascii::AsciiExt;
Expand Down Expand Up @@ -418,11 +417,8 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
self.subpage_id.get().and_then(|subpage_id| {
let window = window_from_node(self);
let window = window.r();
let children = window.page().children.borrow();
children.iter().find(|page| {
let window = page.window();
window.subpage() == Some(subpage_id)
}).map(|page| page.window())
let browsing_context = window.browsing_context();
browsing_context.find_child_by_subpage(subpage_id)
})
}

Expand Down
8 changes: 4 additions & 4 deletions components/script/dom/storage.rs
Expand Up @@ -10,12 +10,12 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::browsingcontext::IterableContext;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper;
use ipc_channel::ipc;
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
use page::IterablePage;
use script_runtime::ScriptChan;
use script_thread::{MainThreadRunnable, ScriptThread};
use task_source::dom_manipulation::DOMManipulationTask;
Expand Down Expand Up @@ -199,9 +199,9 @@ impl MainThreadRunnable for StorageEventRunnable {
Some(storage)
);

let root_page = script_thread.root_page();
for it_page in root_page.iter() {
let it_window_root = it_page.window();
let root_context = script_thread.root_browsing_context();
for it_context in root_context.iter() {
let it_window_root = it_context.active_window();
let it_window = it_window_root.r();
assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
// TODO: Such a Document object is not necessarily fully active, but events fired on such
Expand Down

0 comments on commit cbc5ca6

Please sign in to comment.