diff options
Diffstat (limited to 'components/script/dom')
20 files changed, 547 insertions, 164 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 203bf60f340..9274c6cafb7 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -4643,7 +4643,6 @@ class CGBindingRoot(CGThing): 'dom::bindings::proxyhandler::{fill_property_descriptor, get_expando_object}', 'dom::bindings::proxyhandler::{get_property_descriptor}', 'dom::bindings::str::ByteString', - 'page::JSPageInfo', 'libc', 'util::str::DOMString', 'std::borrow::ToOwned', diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index dc42d0da6e0..3d17778c6b1 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -11,7 +11,7 @@ use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::js::{JS, JSRef, Root, Unrooted}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; -use dom::window; +use dom::window::{self, WindowHelpers}; use script_task::ScriptChan; use net::resource_task::ResourceTask; @@ -84,7 +84,7 @@ impl<'a> GlobalRef<'a> { /// Get the `ResourceTask` for this global scope. pub fn resource_task(&self) -> ResourceTask { match *self { - GlobalRef::Window(ref window) => window.page().resource_task.clone(), + GlobalRef::Window(ref window) => window.resource_task().clone(), GlobalRef::Worker(ref worker) => worker.resource_task().clone(), } } diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 56c9b58288d..706c228c0b2 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -45,6 +45,8 @@ use js::JSFUN_CONSTRUCTOR; use js; /// Proxy handler for a WindowProxy. +#[allow(raw_pointer_derive)] +#[derive(Copy)] pub struct WindowProxyHandler(pub *const libc::c_void); #[allow(raw_pointer_derive)] diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index e21533bbfe0..a3af0a8b02a 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -71,14 +71,12 @@ impl BrowserContext { fn create_window_proxy(&mut self) { let win = self.active_window().root(); let win = win.r(); - let page = win.page(); - let js_info = page.js_info(); - let WindowProxyHandler(handler) = js_info.as_ref().unwrap().dom_static.windowproxy_handler; + let WindowProxyHandler(handler) = win.windowproxy_handler(); assert!(!handler.is_null()); let parent = win.reflector().get_jsobject(); - let cx = js_info.as_ref().unwrap().js_context.ptr; + let cx = win.get_cx(); let wrapper = with_compartment(cx, parent, || unsafe { WrapperNew(cx, parent, handler) }); diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs index 4dec1c3bd45..6308556ef2e 100644 --- a/components/script/dom/console.rs +++ b/components/script/dom/console.rs @@ -7,6 +7,7 @@ use dom::bindings::codegen::Bindings::ConsoleBinding::ConsoleMethods; use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; +use dom::window::WindowHelpers; use devtools_traits::{DevtoolsControlMsg, ConsoleMessage}; use util::str::DOMString; @@ -66,8 +67,8 @@ fn propagate_console_msg(console: &JSRef<Console>, console_message: ConsoleMessa let global = console.global.root(); match global.r() { GlobalRef::Window(window_ref) => { - let pipelineId = window_ref.page().id; - console.global.root().r().as_window().page().devtools_chan.as_ref().map(|chan| { + let pipelineId = window_ref.pipeline(); + console.global.root().r().as_window().devtools_chan().as_ref().map(|chan| { chan.send(DevtoolsControlMsg::SendConsoleMessage( pipelineId, console_message.clone())).unwrap(); }); diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 2337e6c061a..e1be98f99af 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -14,7 +14,7 @@ use dom::document::DocumentHelpers; use dom::element::{Element, ElementHelpers, StylePriority}; use dom::htmlelement::HTMLElement; use dom::node::{window_from_node, document_from_node, NodeDamage, Node}; -use dom::window::Window; +use dom::window::{Window, WindowHelpers}; use util::str::DOMString; use string_cache::Atom; use style::properties::{is_supported_property, longhands_from_shorthand, parse_style_attribute}; @@ -222,9 +222,8 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { let owner = self.owner.root(); let window = window_from_node(owner.r()).root(); let window = window.r(); - let page = window.page(); let decl_block = parse_style_attribute(synthesized_declaration.as_slice(), - &page.get_url()); + &window.get_url()); // Step 7 if decl_block.normal.len() == 0 { @@ -271,9 +270,8 @@ impl<'a> CSSStyleDeclarationMethods for JSRef<'a, CSSStyleDeclaration> { let owner = self.owner.root(); let window = window_from_node(owner.r()).root(); let window = window.r(); - let page = window.page(); let decl_block = parse_style_attribute(property.as_slice(), - &page.get_url()); + &window.get_url()); let element: JSRef<Element> = ElementCast::from_ref(owner.r()); // Step 5 diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 6e5413ebdc8..1d611a6a643 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -11,7 +11,6 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; -use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::{DocumentDerived, EventCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast}; use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast, NodeCast}; @@ -59,12 +58,14 @@ use dom::treewalker::TreeWalker; use dom::uievent::UIEvent; use dom::window::{Window, WindowHelpers}; +use layout_interface::{HitTestResponse, MouseOverResponse}; use msg::compositor_msg::ScriptListener; use msg::constellation_msg::{Key, KeyState, KeyModifiers}; use msg::constellation_msg::{SUPER, ALT, SHIFT, CONTROL}; use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl}; use net::cookie_storage::CookieSource::NonHTTP; use script_task::Runnable; +use script_traits::UntrustedNodeAddress; use util::namespace; use util::str::{DOMString, split_html_space_chars}; use layout_interface::{ReflowGoal, ReflowQueryType}; @@ -201,6 +202,8 @@ pub trait DocumentHelpers<'a> { fn register_named_element(self, element: JSRef<Element>, id: Atom); fn load_anchor_href(self, href: DOMString); fn find_fragment_node(self, fragid: DOMString) -> Option<Temporary<Element>>; + fn hit_test(self, point: &Point2D<f32>) -> Option<UntrustedNodeAddress>; + fn get_nodes_under_mouse(self, point: &Point2D<f32>) -> Vec<UntrustedNodeAddress>; fn set_ready_state(self, state: DocumentReadyState); fn get_focused_element(self) -> Option<Temporary<Element>>; fn begin_focus_transaction(self); @@ -264,7 +267,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { Quirks => { let window = self.window.root(); let window = window.r(); - let LayoutChan(ref layout_chan) = window.page().layout_chan; + let LayoutChan(ref layout_chan) = window.layout_chan(); layout_chan.send(Msg::SetQuirksMode).unwrap(); } NoQuirks | LimitedQuirks => {} @@ -377,6 +380,44 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { }) } + fn hit_test(self, point: &Point2D<f32>) -> Option<UntrustedNodeAddress> { + let root = self.GetDocumentElement().root(); + let root = match root.r() { + Some(root) => root, + None => return None, + }; + let root: JSRef<Node> = NodeCast::from_ref(root); + let win = self.window.root(); + let address = match win.r().layout().hit_test(root.to_trusted_node_address(), *point) { + Ok(HitTestResponse(node_address)) => { + Some(node_address) + } + Err(()) => { + debug!("layout query error"); + None + } + }; + address + } + + fn get_nodes_under_mouse(self, point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> { + let root = self.GetDocumentElement().root(); + let root = match root.r() { + Some(root) => root, + None => return vec!(), + }; + let root: JSRef<Node> = NodeCast::from_ref(root); + let win = self.window.root(); + match win.r().layout().mouse_over(root.to_trusted_node_address(), *point) { + Ok(MouseOverResponse(node_address)) => { + node_address + } + Err(()) => { + vec!() + } + } + } + // https://html.spec.whatwg.org/multipage/dom.html#current-document-readiness fn set_ready_state(self, state: DocumentReadyState) { self.ready_state.set(state); @@ -416,7 +457,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { /// Sends this document's title to the compositor. fn send_title_to_compositor(self) { let window = self.window().root(); - window.r().page().send_title_to_compositor(); + window.r().compositor().set_title(window.r().pipeline(), Some(self.Title())); } fn dirty_all_nodes(self) { @@ -428,10 +469,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { fn handle_click_event(self, js_runtime: *mut JSRuntime, _button: uint, point: Point2D<f32>) { debug!("ClickEvent: clicked at {:?}", point); - let window = self.window.root(); - let window = window.r(); - let page = window.page(); - let node = match page.hit_test(&point) { + let node = match self.hit_test(&point) { Some(node_address) => { debug!("node address is {:?}", node_address.0); node::from_untrusted_node_address(js_runtime, node_address) @@ -460,48 +498,40 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { return; } - match *page.frame() { - Some(ref frame) => { - let window = frame.window.root(); - let doc = window.r().Document().root(); - doc.r().begin_focus_transaction(); - - // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-click - let x = point.x as i32; - let y = point.y as i32; - let event = MouseEvent::new(window.r(), - "click".to_owned(), - true, - true, - Some(window.r()), - 0i32, - x, y, x, y, - false, false, false, false, - 0i16, - None).root(); - let event: JSRef<Event> = EventCast::from_ref(event.r()); - - // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#trusted-events - event.set_trusted(true); - // https://html.spec.whatwg.org/multipage/interaction.html#run-authentic-click-activation-steps - el.authentic_click_activation(event); - - doc.r().commit_focus_transaction(); - window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery); - } - None => {} - } + self.begin_focus_transaction(); + + let window = self.window.root(); + + // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-click + let x = point.x as i32; + let y = point.y as i32; + let event = MouseEvent::new(window.r(), + "click".to_owned(), + true, + true, + Some(window.r()), + 0i32, + x, y, x, y, + false, false, false, false, + 0i16, + None).root(); + let event: JSRef<Event> = EventCast::from_ref(event.r()); + + // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#trusted-events + event.set_trusted(true); + // https://html.spec.whatwg.org/multipage/interaction.html#run-authentic-click-activation-steps + el.authentic_click_activation(event); + + self.commit_focus_transaction(); + window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery); } /// Return need force reflow or not fn handle_mouse_move_event(self, js_runtime: *mut JSRuntime, point: Point2D<f32>, prev_mouse_over_targets: &mut Vec<JS<Node>>) -> bool { - let window = self.window.root(); - let window = window.r(); - let page = window.page(); let mut needs_reflow = false; // Build a list of elements that are currently under the mouse. - let mouse_over_addresses = page.get_nodes_under_mouse(&point); + let mouse_over_addresses = self.get_nodes_under_mouse(&point); let mouse_over_targets: Vec<JS<Node>> = mouse_over_addresses.iter() .filter_map(|node_address| { let node = node::from_untrusted_node_address(js_runtime, *node_address); @@ -534,27 +564,24 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { let top_most_node = node::from_untrusted_node_address(js_runtime, mouse_over_addresses[0]).root(); - if let Some(ref frame) = *page.frame() { - let window = frame.window.root(); - - let x = point.x.to_i32().unwrap_or(0); - let y = point.y.to_i32().unwrap_or(0); - - let mouse_event = MouseEvent::new(window.r(), - "mousemove".to_owned(), - true, - true, - Some(window.r()), - 0i32, - x, y, x, y, - false, false, false, false, - 0i16, - None).root(); - - let event: JSRef<Event> = EventCast::from_ref(mouse_event.r()); - let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r()); - event.fire(target); - } + let x = point.x.to_i32().unwrap_or(0); + let y = point.y.to_i32().unwrap_or(0); + + let window = self.window.root(); + let mouse_event = MouseEvent::new(window.r(), + "mousemove".to_owned(), + true, + true, + Some(window.r()), + 0i32, + x, y, x, y, + false, false, false, false, + 0i16, + None).root(); + + let event: JSRef<Event> = EventCast::from_ref(mouse_event.r()); + let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r()); + event.fire(target); } // Store the current mouse over targets for next frame @@ -1259,7 +1286,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { fn Location(self) -> Temporary<Location> { let window = self.window.root(); let window = window.r(); - self.location.or_init(|| Location::new(window, window.page_clone())) + self.location.or_init(|| Location::new(window)) } // http://dom.spec.whatwg.org/#dom-parentnode-children @@ -1298,10 +1325,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { return Err(Security); } let window = self.window.root(); - let window = window.r(); - let page = window.page(); let (tx, rx) = channel(); - let _ = page.resource_task.send(GetCookiesForUrl(url, tx, NonHTTP)); + let _ = window.r().resource_task().send(GetCookiesForUrl(url, tx, NonHTTP)); let cookies = rx.recv().unwrap(); Ok(cookies.unwrap_or("".to_owned())) } @@ -1314,9 +1339,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { return Err(Security); } let window = self.window.root(); - let window = window.r(); - let page = window.page(); - let _ = page.resource_task.send(SetCookiesForUrl(url, cookie, NonHTTP)); + let _ = window.r().resource_task().send(SetCookiesForUrl(url, cookie, NonHTTP)); Ok(()) } diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index 91d5d96a615..88429277f19 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -12,7 +12,7 @@ use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::document::{Document, DocumentHelpers, IsHTMLDocument}; use dom::document::DocumentSource; -use dom::window::Window; +use dom::window::{Window, WindowHelpers}; use parse::html::{HTMLInput, parse_html}; use util::str::DOMString; diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index e609169ff05..eaf683ce3bd 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -16,6 +16,7 @@ use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; +use dom::window::WindowHelpers; use cssparser::RGBA; use util::str::{self, DOMString}; diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index dd5cd1cb7e0..f3528185211 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -26,6 +26,7 @@ use dom::htmlmediaelement::HTMLMediaElementTypeId; use dom::htmltablecellelement::HTMLTableCellElementTypeId; use dom::node::{Node, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; +use dom::window::WindowHelpers; use util::str::DOMString; diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index ddc8d42b661..9c2148334e2 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -215,7 +215,7 @@ impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> { } // This is wrong. https://html.spec.whatwg.org/multipage/forms.html#planned-navigation - win.r().script_chan().send(ScriptMsg::TriggerLoad(win.r().page().id, load_data)).unwrap(); + win.r().script_chan().send(ScriptMsg::TriggerLoad(win.r().pipeline(), load_data)).unwrap(); } fn get_form_dataset<'b>(self, submitter: Option<FormSubmitter<'b>>) -> Vec<FormDatum> { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index b4f9b577b7b..3afcb2f4af2 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -20,8 +20,8 @@ use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId, window_from_node}; use dom::urlhelper::UrlHelper; use dom::virtualmethods::VirtualMethods; -use dom::window::Window; -use page::{IterablePage, Page}; +use dom::window::{Window, WindowHelpers}; +use page::IterablePage; use msg::constellation_msg::{PipelineId, SubpageId, ConstellationChan}; use msg::constellation_msg::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; @@ -62,7 +62,7 @@ pub trait HTMLIFrameElementHelpers { fn get_url(self) -> Option<Url>; /// http://www.whatwg.org/html/#process-the-iframe-attributes fn process_the_iframe_attributes(self); - fn generate_new_subpage_id(self, page: &Page) -> (SubpageId, Option<SubpageId>); + fn generate_new_subpage_id(self) -> (SubpageId, Option<SubpageId>); } impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { @@ -78,15 +78,16 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { None } else { let window = window_from_node(self).root(); - UrlParser::new().base_url(&window.r().page().get_url()) + UrlParser::new().base_url(&window.r().get_url()) .parse(url.as_slice()).ok() } }) } - fn generate_new_subpage_id(self, page: &Page) -> (SubpageId, Option<SubpageId>) { + fn generate_new_subpage_id(self) -> (SubpageId, Option<SubpageId>) { let old_subpage_id = self.subpage_id.get(); - let subpage_id = page.get_next_subpage_id(); + let win = window_from_node(self).root(); + let subpage_id = win.r().get_next_subpage_id(); self.subpage_id.set(Some(subpage_id)); (subpage_id, old_subpage_id) } @@ -105,14 +106,13 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { let window = window_from_node(self).root(); let window = window.r(); - let page = window.page(); - let (new_subpage_id, old_subpage_id) = self.generate_new_subpage_id(page); + let (new_subpage_id, old_subpage_id) = self.generate_new_subpage_id(); - self.containing_page_pipeline_id.set(Some(page.id)); + self.containing_page_pipeline_id.set(Some(window.pipeline())); - let ConstellationChan(ref chan) = page.constellation_chan; + let ConstellationChan(ref chan) = window.constellation_chan(); chan.send(ConstellationMsg::ScriptLoadedURLInIFrame(url, - page.id, + window.pipeline(), new_subpage_id, old_subpage_id, sandboxed)).unwrap(); @@ -172,14 +172,10 @@ impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { let window = window_from_node(self).root(); let window = window.r(); let children = window.page().children.borrow(); - let child = children.iter().find(|child| { - child.subpage_id.unwrap() == subpage_id - }); - child.and_then(|page| { - page.frame.borrow().as_ref().map(|frame| { - Temporary::new(frame.window.clone()) - }) - }) + children.iter().find(|child| { + let window = child.window().root(); + window.r().subpage() == Some(subpage_id) + }).map(|page| page.window()) }) } @@ -189,7 +185,7 @@ impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> { Some(self_url) => self_url, None => return None, }; - let win_url = window_from_node(self).root().r().page().get_url(); + let win_url = window_from_node(self).root().r().get_url(); if UrlHelper::SameOrigin(&self_url, &win_url) { Some(window.r().Document()) diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 2f8d09bb759..6b2f0b3dc2f 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -17,6 +17,7 @@ use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeTypeId, NodeHelpers, NodeDamage, window_from_node}; use dom::virtualmethods::VirtualMethods; +use dom::window::WindowHelpers; use net::image_cache_task; use util::geometry::to_px; use util::str::DOMString; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 4f8f2aa14b8..ab0c45a22d5 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -17,6 +17,7 @@ use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; +use dom::window::WindowHelpers; use layout_interface::{LayoutChan, Msg}; use util::str::{DOMString, HTML_SPACE_CHARACTERS}; @@ -130,9 +131,9 @@ impl<'a> PrivateHTMLLinkElementHelpers for JSRef<'a, HTMLLinkElement> { fn handle_stylesheet_url(self, href: &str) { let window = window_from_node(self).root(); let window = window.r(); - match UrlParser::new().base_url(&window.page().get_url()).parse(href) { + match UrlParser::new().base_url(&window.get_url()).parse(href) { Ok(url) => { - let LayoutChan(ref layout_chan) = window.page().layout_chan; + let LayoutChan(ref layout_chan) = window.layout_chan(); layout_chan.send(Msg::LoadStylesheet(url)).unwrap(); } Err(e) => debug!("Parsing url {} failed: {}", href, e) diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 853d6709fcb..e9809a6e2cb 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -25,7 +25,7 @@ use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId, document_from_node, window_from_node, CloneChildrenFlag}; use dom::virtualmethods::VirtualMethods; -use dom::window::ScriptHelpers; +use dom::window::{WindowHelpers, ScriptHelpers}; use script_task::{ScriptMsg, Runnable}; use encoding::all::UTF_8; @@ -214,8 +214,7 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { // Step 14. let window = window_from_node(self).root(); let window = window.r(); - let page = window.page(); - let base_url = page.get_url(); + let base_url = window.get_url(); let load = match element.get_attribute(ns!(""), &atom!("src")).root() { // Step 14. @@ -243,7 +242,7 @@ impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> { // state of the element's `crossorigin` content attribute, the origin being // the origin of the script element's node document, and the default origin // behaviour set to taint. - ScriptOrigin::External(load_whole_resource(&page.resource_task, url)) + ScriptOrigin::External(load_whole_resource(&window.resource_task(), url)) } } }, diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 6fc3e1a2039..945831a35b1 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -12,6 +12,7 @@ use dom::element::ElementTypeId; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeHelpers, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; +use dom::window::WindowHelpers; use layout_interface::{LayoutChan, Msg}; use util::str::DOMString; use style::stylesheets::{Origin, Stylesheet}; @@ -52,11 +53,11 @@ impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> { let win = window_from_node(node).root(); let win = win.r(); - let url = win.page().get_url(); + let url = win.get_url(); let data = node.GetTextContent().expect("Element.textContent must be a string"); let sheet = Stylesheet::from_str(data.as_slice(), url, Origin::Author); - let LayoutChan(ref layout_chan) = win.page().layout_chan; + let LayoutChan(ref layout_chan) = win.layout_chan(); layout_chan.send(Msg::AddStylesheet(sheet)).unwrap(); } } diff --git a/components/script/dom/location.rs b/components/script/dom/location.rs index 614b623e5b9..13cc1a05c65 100644 --- a/components/script/dom/location.rs +++ b/components/script/dom/location.rs @@ -5,33 +5,31 @@ use dom::bindings::codegen::Bindings::LocationBinding; use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::urlhelper::UrlHelper; use dom::window::Window; use dom::window::WindowHelpers; -use page::Page; use util::str::DOMString; - -use std::rc::Rc; +use url::Url; #[dom_struct] pub struct Location { reflector_: Reflector, - page: Rc<Page>, + window: JS<Window>, } impl Location { - fn new_inherited(page: Rc<Page>) -> Location { + fn new_inherited(window: JSRef<Window>) -> Location { Location { reflector_: Reflector::new(), - page: page + window: JS::from_rooted(window) } } - pub fn new(window: JSRef<Window>, page: Rc<Page>) -> Temporary<Location> { - reflect_dom_object(box Location::new_inherited(page), + pub fn new(window: JSRef<Window>) -> Temporary<Location> { + reflect_dom_object(box Location::new_inherited(window), GlobalRef::Window(window), LocationBinding::Wrap) } @@ -40,11 +38,11 @@ impl Location { impl<'a> LocationMethods for JSRef<'a, Location> { // https://html.spec.whatwg.org/multipage/browsers.html#dom-location-assign fn Assign(self, url: DOMString) { - self.page.frame().as_ref().unwrap().window.root().r().load_url(url); + self.window.root().r().load_url(url); } fn Href(self) -> DOMString { - UrlHelper::Href(&self.page.get_url()) + UrlHelper::Href(&self.get_url()) } fn Stringify(self) -> DOMString { @@ -52,11 +50,21 @@ impl<'a> LocationMethods for JSRef<'a, Location> { } fn Search(self) -> DOMString { - UrlHelper::Search(&self.page.get_url()) + UrlHelper::Search(&self.get_url()) } fn Hash(self) -> DOMString { - UrlHelper::Hash(&self.page.get_url()) + UrlHelper::Hash(&self.get_url()) } } +trait PrivateLocationHelpers { + fn get_url(self) -> Url; +} + +impl<'a> PrivateLocationHelpers for JSRef<'a, Location> { + fn get_url(self) -> Url { + let window = self.window.root(); + window.r().get_url() + } +} diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index d00aa9961b1..b1cba9ccd3e 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -80,6 +80,7 @@ macro_rules! make_url_or_base_getter( fn $attr(self) -> DOMString { use dom::element::{Element, AttributeHandlers}; use dom::bindings::codegen::InheritTypes::ElementCast; + use dom::window::WindowHelpers; #[allow(unused_imports)] use std::ascii::AsciiExt; let element: JSRef<Element> = ElementCast::from_ref(self); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a7b5e5484d6..7526c2490d2 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -41,7 +41,7 @@ use dom::nodelist::NodeList; use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; use dom::virtualmethods::{VirtualMethods, vtable_for}; -use dom::window::Window; +use dom::window::{Window, WindowHelpers}; use geom::rect::Rect; use layout_interface::{LayoutChan, Msg}; use devtools_traits::NodeInfo; @@ -737,11 +737,11 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { } fn get_bounding_content_box(self) -> Rect<Au> { - window_from_node(self).root().r().page().content_box_query(self.to_trusted_node_address()) + window_from_node(self).root().r().content_box_query(self.to_trusted_node_address()) } fn get_content_boxes(self) -> Vec<Rect<Au>> { - window_from_node(self).root().r().page().content_boxes_query(self.to_trusted_node_address()) + window_from_node(self).root().r().content_boxes_query(self.to_trusted_node_address()) } // http://dom.spec.whatwg.org/#dom-parentnode-queryselector diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 27b297e21f2..30b1e6baaa0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -8,50 +8,59 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WindowBinding; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; -use dom::bindings::codegen::InheritTypes::EventTargetCast; +use dom::bindings::codegen::InheritTypes::{NodeCast, EventTargetCast}; use dom::bindings::global::global_object_for_js_object; use dom::bindings::error::{report_pending_exception, Fallible}; use dom::bindings::error::Error::InvalidCharacter; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{MutNullableJS, JSRef, Temporary}; -use dom::bindings::utils::Reflectable; +use dom::bindings::js::{MutNullableJS, JSRef, Temporary, OptionalRootable, RootedReference}; +use dom::bindings::utils::{GlobalStaticData, Reflectable, WindowProxyHandler}; use dom::browsercontext::BrowserContext; use dom::console::Console; -use dom::document::Document; +use dom::document::{Document, DocumentHelpers}; use dom::element::Element; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::location::Location; use dom::navigator::Navigator; -use dom::node::window_from_node; +use dom::node::{window_from_node, Node, TrustedNodeAddress, NodeHelpers}; use dom::performance::Performance; use dom::screen::Screen; use dom::storage::Storage; -use layout_interface::{ReflowGoal, ReflowQueryType}; +use layout_interface::{ReflowGoal, ReflowQueryType, LayoutRPC, LayoutChan, Reflow, Msg}; +use layout_interface::{ContentBoxResponse, ContentBoxesResponse}; use page::Page; use script_task::{TimerSource, ScriptChan}; use script_task::ScriptMsg; use script_traits::ScriptControlChan; use timers::{IsInterval, TimerId, TimerManager, TimerCallback}; +use devtools_traits::DevtoolsControlChan; use msg::compositor_msg::ScriptListener; -use msg::constellation_msg::LoadData; +use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData}; use net::image_cache_task::ImageCacheTask; +use net::resource_task::ResourceTask; use net::storage_task::StorageTask; +use util::geometry::{self, Au, MAX_RECT}; use util::str::{DOMString,HTML_SPACE_CHARACTERS}; +use geom::{Point2D, Rect, Size2D}; use js::jsapi::JS_EvaluateUCScript; use js::jsapi::JSContext; use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::{JSVal, UndefinedValue}; -use js::rust::with_compartment; +use js::rust::{Cx, with_compartment}; use url::{Url, UrlParser}; use libc; use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD}; -use std::cell::{Ref, RefMut}; +use std::cell::{Cell, Ref, RefMut}; use std::default::Default; use std::ffi::CString; +use std::mem::replace; +use std::num::Float; use std::rc::Rc; +use std::sync::mpsc::{channel, Receiver}; +use std::sync::mpsc::TryRecvError::{Empty, Disconnected}; use time; #[dom_struct] @@ -71,18 +80,80 @@ pub struct Window { screen: MutNullableJS<Screen>, session_storage: MutNullableJS<Storage>, timers: TimerManager, + + /// For providing instructions to an optional devtools server. + devtools_chan: Option<DevtoolsControlChan>, + + /// A flag to indicate whether the developer tools have requested live updates of + /// page changes. + devtools_wants_updates: Cell<bool>, + + next_subpage_id: Cell<SubpageId>, + + /// Pending resize event, if any. + resize_event: Cell<Option<WindowSizeData>>, + + /// Pipeline id associated with this page. + id: PipelineId, + + /// Subpage id associated with this page, if any. + subpage_id: Option<SubpageId>, + + /// Unique id for last reflow request; used for confirming completion reply. + last_reflow_id: Cell<uint>, + + /// Global static data related to the DOM. + dom_static: GlobalStaticData, + + /// The JavaScript context. + js_context: DOMRefCell<Option<Rc<Cx>>>, + + /// A handle for communicating messages to the layout task. + layout_chan: LayoutChan, + + /// A handle to perform RPC calls into the layout, quickly. + layout_rpc: Box<LayoutRPC+'static>, + + /// The port that we will use to join layout. If this is `None`, then layout is not running. + layout_join_port: DOMRefCell<Option<Receiver<()>>>, + + /// The current size of the window, in pixels. + window_size: Cell<WindowSizeData>, + + /// Associated resource task for use by DOM objects like XMLHttpRequest + resource_task: ResourceTask, + + /// A handle for communicating messages to the storage task. + storage_task: StorageTask, + + /// A handle for communicating messages to the constellation task. + constellation_chan: ConstellationChan, + + /// Pending scroll to fragment event, if any + fragment_name: DOMRefCell<Option<String>>, + + /// An enlarged rectangle around the page contents visible in the viewport, used + /// to prevent creating display list items for content that is far away from the viewport. + page_clip_rect: Cell<Rect<Au>>, } impl Window { pub fn get_cx(&self) -> *mut JSContext { - let js_info = self.page().js_info(); - (*js_info.as_ref().unwrap().js_context).ptr + self.js_context.borrow().as_ref().unwrap().ptr } pub fn script_chan(&self) -> Box<ScriptChan+Send> { self.script_chan.clone() } + pub fn pipeline(&self) -> PipelineId { + self.id.clone() + } + + pub fn subpage(&self) -> Option<SubpageId> { + self.subpage_id.clone() + } + pub fn control_chan<'a>(&'a self) -> &'a ScriptControlChan { &self.control_chan } @@ -103,16 +174,8 @@ impl Window { &*self.page } - pub fn page_clone(&self) -> Rc<Page> { - self.page.clone() - } - - pub fn get_url(&self) -> Url { - self.page().get_url() - } - pub fn storage_task(&self) -> StorageTask { - self.page().storage_task.clone() + self.storage_task.clone() } } @@ -197,12 +260,11 @@ impl<'a> WindowMethods for JSRef<'a, Window> { } fn Close(self) { - self.script_chan.send(ScriptMsg::ExitWindow(self.page.id.clone())).unwrap(); + self.script_chan.send(ScriptMsg::ExitWindow(self.id.clone())).unwrap(); } fn Document(self) -> Temporary<Document> { - let frame = self.page().frame(); - Temporary::new(frame.as_ref().unwrap().document.clone()) + self.browser_context().as_ref().unwrap().active_document() } fn Location(self) -> Temporary<Location> { @@ -230,7 +292,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { args, timeout, IsInterval::NonInterval, - TimerSource::FromWindow(self.page.id.clone()), + TimerSource::FromWindow(self.id.clone()), self.script_chan.clone()) } @@ -239,7 +301,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { args, timeout, IsInterval::NonInterval, - TimerSource::FromWindow(self.page.id.clone()), + TimerSource::FromWindow(self.id.clone()), self.script_chan.clone()) } @@ -252,7 +314,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { args, timeout, IsInterval::Interval, - TimerSource::FromWindow(self.page.id.clone()), + TimerSource::FromWindow(self.id.clone()), self.script_chan.clone()) } @@ -261,7 +323,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { args, timeout, IsInterval::Interval, - TimerSource::FromWindow(self.page.id.clone()), + TimerSource::FromWindow(self.id.clone()), self.script_chan.clone()) } @@ -330,10 +392,35 @@ impl<'a> WindowMethods for JSRef<'a, Window> { } pub trait WindowHelpers { + fn clear_js_context(self); + fn clear_js_context_for_script_deallocation(self); fn flush_layout(self, goal: ReflowGoal, query: ReflowQueryType); fn init_browser_context(self, doc: JSRef<Document>, frame_element: Option<JSRef<Element>>); fn load_url(self, href: DOMString); fn handle_fire_timer(self, timer_id: TimerId); + fn reflow(self, goal: ReflowGoal, query_type: ReflowQueryType); + fn join_layout(self); + fn layout(&self) -> &LayoutRPC; + fn content_box_query(self, content_box_request: TrustedNodeAddress) -> Rect<Au>; + fn content_boxes_query(self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>>; + fn handle_reflow_complete_msg(self, reflow_id: uint); + fn handle_resize_inactive_msg(self, new_size: WindowSizeData); + fn set_fragment_name(self, fragment: Option<String>); + fn steal_fragment_name(self) -> Option<String>; + fn set_window_size(self, size: WindowSizeData); + fn window_size(self) -> WindowSizeData; + fn get_url(self) -> Url; + fn resource_task(self) -> ResourceTask; + fn devtools_chan(self) -> Option<DevtoolsControlChan>; + fn layout_chan(self) -> LayoutChan; + fn constellation_chan(self) -> ConstellationChan; + fn windowproxy_handler(self) -> WindowProxyHandler; + fn get_next_subpage_id(self) -> SubpageId; + fn layout_is_idle(self) -> bool; + fn set_resize_event(self, event: WindowSizeData); + fn steal_resize_event(self) -> Option<WindowSizeData>; + fn set_page_clip_rect_with_new_viewport(self, viewport: Rect<f32>) -> bool; + fn set_devtools_wants_updates(self, value: bool); fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>>; fn thaw(self); fn freeze(self); @@ -373,8 +460,132 @@ impl<'a, T: Reflectable> ScriptHelpers for JSRef<'a, T> { } impl<'a> WindowHelpers for JSRef<'a, Window> { + fn clear_js_context(self) { + *self.js_context.borrow_mut() = None; + *self.browser_context.borrow_mut() = None; + } + + #[allow(unsafe_blocks)] + fn clear_js_context_for_script_deallocation(self) { + unsafe { + *self.js_context.borrow_for_script_deallocation() = None; + *self.browser_context.borrow_for_script_deallocation() = None; + } + } + fn flush_layout(self, goal: ReflowGoal, query: ReflowQueryType) { - self.page().flush_layout(goal, query); + self.reflow(goal, query); + } + + /// Reflows the page if it's possible to do so and the page is dirty. This method will wait + /// for the layout thread to complete (but see the `TODO` below). If there is no window size + /// yet, the page is presumed invisible and no reflow is performed. + /// + /// TODO(pcwalton): Only wait for style recalc, since we have off-main-thread layout. + fn reflow(self, goal: ReflowGoal, query_type: ReflowQueryType) { + let document = self.Document().root(); + let root = document.r().GetDocumentElement().root(); + let root = match root.r() { + Some(root) => root, + None => return, + }; + + debug!("script: performing reflow for goal {:?}", goal); + + let root: JSRef<Node> = NodeCast::from_ref(root); + if !root.get_has_dirty_descendants() { + debug!("root has no dirty descendants; avoiding reflow"); + return + } + + debug!("script: performing reflow for goal {:?}", goal); + + // Layout will let us know when it's done. + let (join_chan, join_port) = channel(); + + { + let mut layout_join_port = self.layout_join_port.borrow_mut(); + *layout_join_port = Some(join_port); + } + + let last_reflow_id = &self.last_reflow_id; + last_reflow_id.set(last_reflow_id.get() + 1); + + let window_size = self.window_size.get(); + + // Send new document and relevant styles to layout. + let reflow = box Reflow { + document_root: root.to_trusted_node_address(), + url: self.get_url(), + iframe: self.subpage_id.is_some(), + goal: goal, + window_size: window_size, + script_chan: self.control_chan.clone(), + script_join_chan: join_chan, + id: last_reflow_id.get(), + query_type: query_type, + page_clip_rect: self.page_clip_rect.get(), + }; + + let LayoutChan(ref chan) = self.layout_chan; + chan.send(Msg::Reflow(reflow)).unwrap(); + + debug!("script: layout forked"); + + self.join_layout(); + } + + // FIXME(cgaebel): join_layout is racey. What if the compositor triggers a + // reflow between the "join complete" message and returning from this + // function? + + /// Sends a ping to layout and waits for the response. The response will arrive when the + /// layout task has finished any pending request messages. + fn join_layout(self) { + let mut layout_join_port = self.layout_join_port.borrow_mut(); + if let Some(join_port) = replace(&mut *layout_join_port, None) { + match join_port.try_recv() { + Err(Empty) => { + info!("script: waiting on layout"); + join_port.recv().unwrap(); + } + Ok(_) => {} + Err(Disconnected) => { + panic!("Layout task failed while script was waiting for a result."); + } + } + + debug!("script: layout joined") + } + } + + fn layout(&self) -> &LayoutRPC { + &*self.layout_rpc + } + + fn content_box_query(self, content_box_request: TrustedNodeAddress) -> Rect<Au> { + self.flush_layout(ReflowGoal::ForScriptQuery, ReflowQueryType::ContentBoxQuery(content_box_request)); + self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough? + let ContentBoxResponse(rect) = self.layout_rpc.content_box(); + rect + } + + fn content_boxes_query(self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>> { + self.flush_layout(ReflowGoal::ForScriptQuery, ReflowQueryType::ContentBoxesQuery(content_boxes_request)); + self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough? + let ContentBoxesResponse(rects) = self.layout_rpc.content_boxes(); + rects + } + + fn handle_reflow_complete_msg(self, reflow_id: uint) { + let last_reflow_id = self.last_reflow_id.get(); + if last_reflow_id == reflow_id { + *self.layout_join_port.borrow_mut() = None; + } + } + + fn handle_resize_inactive_msg(self, new_size: WindowSizeData) { + self.window_size.set(new_size); } fn init_browser_context(self, doc: JSRef<Document>, frame_element: Option<JSRef<Element>>) { @@ -383,17 +594,17 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { /// Commence a new URL load which will either replace this window or scroll to a fragment. fn load_url(self, href: DOMString) { - let base_url = self.page().get_url(); + let base_url = self.get_url(); debug!("current page url is {}", base_url); let url = UrlParser::new().base_url(&base_url).parse(href.as_slice()); // FIXME: handle URL parse errors more gracefully. let url = url.unwrap(); match url.fragment { Some(fragment) => { - self.script_chan.send(ScriptMsg::TriggerFragment(self.page.id, fragment)).unwrap(); + self.script_chan.send(ScriptMsg::TriggerFragment(self.id, fragment)).unwrap(); }, None => { - self.script_chan.send(ScriptMsg::TriggerLoad(self.page.id, LoadData::new(url))).unwrap(); + self.script_chan.send(ScriptMsg::TriggerLoad(self.id, LoadData::new(url))).unwrap(); } } } @@ -403,6 +614,97 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { self.flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery); } + fn set_fragment_name(self, fragment: Option<String>) { + *self.fragment_name.borrow_mut() = fragment; + } + + fn steal_fragment_name(self) -> Option<String> { + self.fragment_name.borrow_mut().take() + } + + fn set_window_size(self, size: WindowSizeData) { + self.window_size.set(size); + } + + fn window_size(self) -> WindowSizeData { + self.window_size.get() + } + + fn get_url(self) -> Url { + let doc = self.Document().root(); + doc.r().url() + } + + fn resource_task(self) -> ResourceTask { + self.resource_task.clone() + } + + fn devtools_chan(self) -> Option<DevtoolsControlChan> { + self.devtools_chan.clone() + } + + fn layout_chan(self) -> LayoutChan { + self.layout_chan.clone() + } + + fn constellation_chan(self) -> ConstellationChan { + self.constellation_chan.clone() + } + + fn windowproxy_handler(self) -> WindowProxyHandler { + self.dom_static.windowproxy_handler + } + + fn get_next_subpage_id(self) -> SubpageId { + let subpage_id = self.next_subpage_id.get(); + let SubpageId(id_num) = subpage_id; + self.next_subpage_id.set(SubpageId(id_num + 1)); + subpage_id + } + + fn layout_is_idle(self) -> bool { + self.layout_join_port.borrow().is_none() + } + + fn set_resize_event(self, event: WindowSizeData) { + self.resize_event.set(Some(event)); + } + + fn steal_resize_event(self) -> Option<WindowSizeData> { + let event = self.resize_event.get(); + self.resize_event.set(None); + event + } + + fn set_page_clip_rect_with_new_viewport(self, viewport: Rect<f32>) -> bool { + // We use a clipping rectangle that is five times the size of the of the viewport, + // so that we don't collect display list items for areas too far outside the viewport, + // but also don't trigger reflows every time the viewport changes. + static VIEWPORT_EXPANSION: f32 = 2.0; // 2 lengths on each side plus original length is 5 total. + let proposed_clip_rect = geometry::f32_rect_to_au_rect( + viewport.inflate(viewport.size.width * VIEWPORT_EXPANSION, + viewport.size.height * VIEWPORT_EXPANSION)); + let clip_rect = self.page_clip_rect.get(); + if proposed_clip_rect == clip_rect { + return false; + } + + let had_clip_rect = clip_rect != MAX_RECT; + if had_clip_rect && !should_move_clip_rect(clip_rect, viewport) { + return false; + } + + self.page_clip_rect.set(proposed_clip_rect); + + // If we didn't have a clip rect, the previous display doesn't need rebuilding + // because it was built for infinite clip (MAX_RECT). + had_clip_rect + } + + fn set_devtools_wants_updates(self, value: bool) { + self.devtools_wants_updates.set(value); + } + // https://html.spec.whatwg.org/multipage/browsers.html#accessing-other-browsing-contexts fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option<Temporary<Window>> { None @@ -419,13 +721,28 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { } impl Window { - pub fn new(cx: *mut JSContext, + pub fn new(js_context: Rc<Cx>, page: Rc<Page>, script_chan: Box<ScriptChan+Send>, control_chan: ScriptControlChan, compositor: Box<ScriptListener+'static>, - image_cache_task: ImageCacheTask) + image_cache_task: ImageCacheTask, + resource_task: ResourceTask, + storage_task: StorageTask, + devtools_chan: Option<DevtoolsControlChan>, + constellation_chan: ConstellationChan, + layout_chan: LayoutChan, + id: PipelineId, + subpage_id: Option<SubpageId>, + window_size: WindowSizeData) -> Temporary<Window> { + let layout_rpc: Box<LayoutRPC> = { + let (rpc_send, rpc_recv) = channel(); + let LayoutChan(ref lchan) = layout_chan; + lchan.send(Msg::GetRPC(rpc_send)).unwrap(); + rpc_recv.recv().unwrap() + }; + let win = box Window { eventtarget: EventTarget::new_inherited(EventTargetTypeId::Window), script_chan: script_chan, @@ -435,6 +752,7 @@ impl Window { page: page, navigator: Default::default(), image_cache_task: image_cache_task, + devtools_chan: devtools_chan, browser_context: DOMRefCell::new(None), performance: Default::default(), navigation_start: time::get_time().sec as u64, @@ -442,8 +760,43 @@ impl Window { screen: Default::default(), session_storage: Default::default(), timers: TimerManager::new(), + id: id, + subpage_id: subpage_id, + dom_static: GlobalStaticData::new(), + js_context: DOMRefCell::new(Some(js_context.clone())), + resource_task: resource_task, + storage_task: storage_task, + constellation_chan: constellation_chan, + page_clip_rect: Cell::new(MAX_RECT), + fragment_name: DOMRefCell::new(None), + last_reflow_id: Cell::new(0), + resize_event: Cell::new(None), + next_subpage_id: Cell::new(SubpageId(0)), + layout_chan: layout_chan, + layout_rpc: layout_rpc, + layout_join_port: DOMRefCell::new(None), + window_size: Cell::new(window_size), + devtools_wants_updates: Cell::new(false), }; - WindowBinding::Wrap(cx, win) + WindowBinding::Wrap(js_context.ptr, win) } } + +fn should_move_clip_rect(clip_rect: Rect<Au>, new_viewport: Rect<f32>) -> bool{ + let clip_rect = Rect(Point2D(geometry::to_frac_px(clip_rect.origin.x) as f32, + geometry::to_frac_px(clip_rect.origin.y) as f32), + Size2D(geometry::to_frac_px(clip_rect.size.width) as f32, + geometry::to_frac_px(clip_rect.size.height) as f32)); + + // We only need to move the clip rect if the viewport is getting near the edge of + // our preexisting clip rect. We use half of the size of the viewport as a heuristic + // for "close." + static VIEWPORT_SCROLL_MARGIN_SIZE: f32 = 0.5; + let viewport_scroll_margin = new_viewport.size * VIEWPORT_SCROLL_MARGIN_SIZE; + + (clip_rect.origin.x - new_viewport.origin.x).abs() <= viewport_scroll_margin.width || + (clip_rect.max_x() - new_viewport.max_x()).abs() <= viewport_scroll_margin.width || + (clip_rect.origin.y - new_viewport.origin.y).abs() <= viewport_scroll_margin.height || + (clip_rect.max_y() - new_viewport.max_y()).abs() <= viewport_scroll_margin.height +} |