From e839758a577a5702777946efa3445e6e6f9f5942 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Mon, 12 May 2014 15:25:14 -0400 Subject: [PATCH] servo: Merge #2403 - Move the loading of documents in iframes into HTMLIFrameElement (from Ms2ger:iframe-loading); r=jdm Right now, the load is kicked off inside the parser glue. This is unfortunate for several reasons: 1) we'd like to replace the current parser (libhubbub) by our own parser, written in Rust, so code intertwined with the parser will have to be rewritten; 2) it is impossible to support dynamically (i.e. from script) created iframes in this way; 3) the code flow around loading subdocuments is complicated needlessly. This commit adds the constellation channel (on which the message to actually load the document is sent) as a field on the Page, to allow HTMLIFrameElement to access it. In rewriting the code, support for dynamically created iframes is added, and a task failure is avoided when the value of the src attribute can not be parsed. Source-Repo: https://github.com/servo/servo Source-Revision: 1e361e8b6f04d7848d40fd19090511c0c3f16a97 --- .../script/dom/htmliframeelement.rs | 54 +++++++++++++++++-- .../script/html/hubbub_html_parser.rs | 38 +------------ servo/src/components/script/script_task.rs | 38 ++++++------- 3 files changed, 70 insertions(+), 60 deletions(-) diff --git a/servo/src/components/script/dom/htmliframeelement.rs b/servo/src/components/script/dom/htmliframeelement.rs index 9f77cda68290..f92fddabdaa2 100644 --- a/servo/src/components/script/dom/htmliframeelement.rs +++ b/servo/src/components/script/dom/htmliframeelement.rs @@ -5,19 +5,24 @@ use dom::bindings::codegen::BindingDeclarations::HTMLIFrameElementBinding; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast}; use dom::bindings::error::ErrorResult; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::js::{JSRef, Temporary, OptionalRootable}; use dom::document::Document; use dom::element::{HTMLIFrameElementTypeId, Element}; use dom::element::AttributeHandlers; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom::window::Window; -use servo_util::str::DOMString; - use servo_msg::constellation_msg::{PipelineId, SubpageId}; +use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed}; +use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg}; +use servo_util::namespace::Null; +use servo_util::str::DOMString; +use servo_util::url::try_parse_url; + use std::ascii::StrAsciiExt; +use url::Url; enum SandboxAllowance { AllowNothing = 0x00, @@ -50,12 +55,22 @@ pub struct IFrameSize { pub trait HTMLIFrameElementHelpers { fn is_sandboxed(&self) -> bool; + fn get_url(&self) -> Option; } impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { fn is_sandboxed(&self) -> bool { self.sandbox.is_some() } + + fn get_url(&self) -> Option { + let element: &JSRef = ElementCast::from_ref(self); + element.get_attribute(Null, "src").root().and_then(|src| { + let window = window_from_node(self).root(); + try_parse_url(src.deref().value_ref(), + Some(window.deref().page().get_url())).ok() + }) + } } impl HTMLIFrameElement { @@ -266,4 +281,35 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> { self.deref_mut().sandbox = None; } } + + fn bind_to_tree(&mut self) { + match self.super_type() { + Some(ref mut s) => s.bind_to_tree(), + _ => (), + } + + match self.get_url() { + Some(url) => { + let sandboxed = if self.is_sandboxed() { + IFrameSandboxed + } else { + IFrameUnsandboxed + }; + + // Subpage Id + let window = window_from_node(self).root(); + let page = window.deref().page(); + let subpage_id = page.get_next_subpage_id(); + + self.deref_mut().size = Some(IFrameSize { + pipeline_id: page.id, + subpage_id: subpage_id, + }); + + let ConstellationChan(ref chan) = *page.constellation_chan.deref(); + chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed)); + } + _ => () + } + } } diff --git a/servo/src/components/script/html/hubbub_html_parser.rs b/servo/src/components/script/html/hubbub_html_parser.rs index 143e58bf7b90..38fc676ce08d 100644 --- a/servo/src/components/script/html/hubbub_html_parser.rs +++ b/servo/src/components/script/html/hubbub_html_parser.rs @@ -4,14 +4,12 @@ use dom::attr::AttrMethods; use dom::bindings::codegen::InheritTypes::{NodeBase, NodeCast, TextCast, ElementCast}; -use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast; use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root}; use dom::bindings::utils::Reflectable; use dom::document::{Document, DocumentHelpers}; -use dom::element::{AttributeHandlers, HTMLLinkElementTypeId, HTMLIFrameElementTypeId}; +use dom::element::{AttributeHandlers, HTMLLinkElementTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6}; -use dom::htmliframeelement::{IFrameSize, HTMLIFrameElementHelpers}; use dom::htmlformelement::HTMLFormElement; use dom::node::{ElementNodeTypeId, NodeHelpers, NodeMethods}; use dom::types::*; @@ -19,7 +17,6 @@ use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser}; use script_task::Page; use hubbub::hubbub; -use servo_msg::constellation_msg::SubpageId; use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource}; use servo_util::namespace::Null; use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; @@ -67,7 +64,6 @@ enum JSMessage { /// Messages generated by the HTML parser upon discovery of additional resources pub enum HtmlDiscoveryMessage { HtmlDiscoveredStyle(Stylesheet), - HtmlDiscoveredIFrame((Url, SubpageId, bool)), HtmlDiscoveredScript(JSResult) } @@ -252,7 +248,6 @@ pub fn parse_html(page: &Page, resource_task: ResourceTask) -> HtmlParserResult { debug!("Hubbub: parsing {:?}", url); - let next_subpage_id: SubpageId = page.next_subpage_id.deref().get(); // Spawn a CSS parser to receive links to CSS style sheets. let (discovery_chan, discovery_port) = channel(); @@ -288,8 +283,6 @@ pub fn parse_html(page: &Page, *page.mut_url() = Some((url2.clone(), true)); } - let pipeline_id = page.id; - let mut parser = hubbub::Parser("UTF-8", false); debug!("created parser"); @@ -299,8 +292,6 @@ pub fn parse_html(page: &Page, let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone()); - let next_subpage_id = RefCell::new(next_subpage_id); - let doc_cell = RefCell::new(document); let tree_handler = hubbub::TreeHandler { @@ -352,10 +343,6 @@ pub fn parse_html(page: &Page, let href= element.get_attribute(Null, "href").root(); href.map(|a| a.deref().Value()) }; - let src_opt = { - let src_opt = element.get_attribute(Null, "src").root(); - src_opt.map(|a| a.deref().Value()) - }; // Spawn additional parsing, network loads, etc. from tag and attrs let type_id = { @@ -377,29 +364,6 @@ pub fn parse_html(page: &Page, _ => {} } } - - ElementNodeTypeId(HTMLIFrameElementTypeId) => { - let iframe_chan = discovery_chan.clone(); - let iframe_element: &mut JSRef = - HTMLIFrameElementCast::to_mut_ref(&mut *element).unwrap(); - let sandboxed = iframe_element.is_sandboxed(); - for src in src_opt.iter() { - let iframe_url = parse_url(*src, Some(url2.clone())); - - // Subpage Id - let subpage_id = *next_subpage_id.borrow(); - let SubpageId(id_num) = subpage_id; - *next_subpage_id.borrow_mut() = SubpageId(id_num + 1); - - iframe_element.deref_mut().size = Some(IFrameSize { - pipeline_id: pipeline_id, - subpage_id: subpage_id, - }); - iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, - subpage_id, - sandboxed))); - } - } _ => {} } diff --git a/servo/src/components/script/script_task.rs b/servo/src/components/script/script_task.rs index c1e01bbc3bc7..4bd981a52913 100644 --- a/servo/src/components/script/script_task.rs +++ b/servo/src/components/script/script_task.rs @@ -22,7 +22,7 @@ use dom::node; use dom::node::{Node, NodeHelpers}; use dom::window::{TimerId, Window}; use html::hubbub_html_parser::HtmlParserResult; -use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript}; +use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript}; use html::hubbub_html_parser; use layout_interface::{AddStylesheetMsg, DocumentDamage}; use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery, MouseOverQuery, MouseOverResponse}; @@ -43,8 +43,7 @@ use js::rust::with_compartment; use js; use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout}; use servo_msg::compositor_msg::{ScriptListener}; -use servo_msg::constellation_msg::{ConstellationChan, IFrameSandboxed, IFrameUnsandboxed}; -use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadCompleteMsg, LoadUrlMsg, NavigationDirection}; +use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection}; use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg}; use servo_msg::constellation_msg; use servo_net::image_cache_task::ImageCacheTask; @@ -157,6 +156,9 @@ pub struct Page { /// Associated resource task for use by DOM objects like XMLHttpRequest pub resource_task: Untraceable, + + /// A handle for communicating messages to the constellation task. + pub constellation_chan: Untraceable, } pub struct PageTree { @@ -171,6 +173,7 @@ pub struct PageTreeIterator<'a> { impl PageTree { fn new(id: PipelineId, layout_chan: LayoutChan, window_size: Size2D, resource_task: ResourceTask, + constellation_chan: ConstellationChan, js_context: Rc) -> PageTree { let js_info = JSPageInfo { dom_static: GlobalStaticData(), @@ -190,7 +193,8 @@ impl PageTree { resize_event: Untraceable::new(Cell::new(None)), fragment_node: Traceable::new(RefCell::new(None)), last_reflow_id: Traceable::new(Cell::new(0)), - resource_task: Untraceable::new(resource_task) + resource_task: Untraceable::new(resource_task), + constellation_chan: Untraceable::new(constellation_chan), }), inner: vec!(), } @@ -287,6 +291,13 @@ impl Page { self.frame.deref().borrow_mut() } + pub fn get_next_subpage_id(&self) -> SubpageId { + let subpage_id = self.next_subpage_id.deref().get(); + let SubpageId(id_num) = subpage_id; + self.next_subpage_id.deref().set(SubpageId(id_num + 1)); + subpage_id + } + /// Adds the given damage. pub fn damage(&self, level: DocumentDamageLevel) { let root = match *self.frame() { @@ -595,7 +606,9 @@ impl ScriptTask { -> Rc { let (js_runtime, js_context) = ScriptTask::new_rt_and_cx(); let page_tree = PageTree::new(id, layout_chan, window_size, - resource_task.clone(), js_context.clone()); + resource_task.clone(), + constellation_chan.clone(), + js_context.clone()); Rc::new(ScriptTask { page_tree: RefCell::new(page_tree), @@ -781,6 +794,7 @@ impl ScriptTask { let window_size = parent_page_tree.page().window_size.deref().get(); PageTree::new(new_id, layout_chan, window_size, parent_page_tree.page().resource_task.deref().clone(), + self.constellation_chan.clone(), self.js_context.borrow().get_ref().clone()) }; parent_page_tree.inner.push(new_page_tree); @@ -973,20 +987,6 @@ impl ScriptTask { let LayoutChan(ref chan) = *page.layout_chan; chan.send(AddStylesheetMsg(sheet)); } - Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, sandboxed))) => { - let SubpageId(num) = subpage_id; - page.next_subpage_id.deref().set(SubpageId(num + 1)); - let sandboxed = if sandboxed { - IFrameSandboxed - } else { - IFrameUnsandboxed - }; - let ConstellationChan(ref chan) = self.constellation_chan; - chan.send(LoadIframeUrlMsg(iframe_url, - pipeline_id, - subpage_id, - sandboxed)); - } None => break } }