зеркало из https://github.com/mozilla/gecko-dev.git
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
This commit is contained in:
Родитель
95c7e74c0a
Коммит
e839758a57
|
@ -5,19 +5,24 @@
|
||||||
use dom::bindings::codegen::BindingDeclarations::HTMLIFrameElementBinding;
|
use dom::bindings::codegen::BindingDeclarations::HTMLIFrameElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementDerived, HTMLElementCast};
|
||||||
use dom::bindings::error::ErrorResult;
|
use dom::bindings::error::ErrorResult;
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::{HTMLIFrameElementTypeId, Element};
|
use dom::element::{HTMLIFrameElementTypeId, Element};
|
||||||
use dom::element::AttributeHandlers;
|
use dom::element::AttributeHandlers;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, ElementNodeTypeId};
|
use dom::node::{Node, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use servo_util::str::DOMString;
|
|
||||||
|
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
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 std::ascii::StrAsciiExt;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
enum SandboxAllowance {
|
enum SandboxAllowance {
|
||||||
AllowNothing = 0x00,
|
AllowNothing = 0x00,
|
||||||
|
@ -50,12 +55,22 @@ pub struct IFrameSize {
|
||||||
|
|
||||||
pub trait HTMLIFrameElementHelpers {
|
pub trait HTMLIFrameElementHelpers {
|
||||||
fn is_sandboxed(&self) -> bool;
|
fn is_sandboxed(&self) -> bool;
|
||||||
|
fn get_url(&self) -> Option<Url>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
|
impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
|
||||||
fn is_sandboxed(&self) -> bool {
|
fn is_sandboxed(&self) -> bool {
|
||||||
self.sandbox.is_some()
|
self.sandbox.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_url(&self) -> Option<Url> {
|
||||||
|
let element: &JSRef<Element> = 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 {
|
impl HTMLIFrameElement {
|
||||||
|
@ -266,4 +281,35 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
|
||||||
self.deref_mut().sandbox = None;
|
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));
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,12 @@
|
||||||
|
|
||||||
use dom::attr::AttrMethods;
|
use dom::attr::AttrMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{NodeBase, NodeCast, TextCast, ElementCast};
|
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::js::{JS, JSRef, Temporary, OptionalRootable, Root};
|
||||||
use dom::bindings::utils::Reflectable;
|
use dom::bindings::utils::Reflectable;
|
||||||
use dom::document::{Document, DocumentHelpers};
|
use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{AttributeHandlers, HTMLLinkElementTypeId, HTMLIFrameElementTypeId};
|
use dom::element::{AttributeHandlers, HTMLLinkElementTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
|
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
|
||||||
use dom::htmliframeelement::{IFrameSize, HTMLIFrameElementHelpers};
|
|
||||||
use dom::htmlformelement::HTMLFormElement;
|
use dom::htmlformelement::HTMLFormElement;
|
||||||
use dom::node::{ElementNodeTypeId, NodeHelpers, NodeMethods};
|
use dom::node::{ElementNodeTypeId, NodeHelpers, NodeMethods};
|
||||||
use dom::types::*;
|
use dom::types::*;
|
||||||
|
@ -19,7 +17,6 @@ use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
||||||
use script_task::Page;
|
use script_task::Page;
|
||||||
|
|
||||||
use hubbub::hubbub;
|
use hubbub::hubbub;
|
||||||
use servo_msg::constellation_msg::SubpageId;
|
|
||||||
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource};
|
||||||
use servo_util::namespace::Null;
|
use servo_util::namespace::Null;
|
||||||
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
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
|
/// Messages generated by the HTML parser upon discovery of additional resources
|
||||||
pub enum HtmlDiscoveryMessage {
|
pub enum HtmlDiscoveryMessage {
|
||||||
HtmlDiscoveredStyle(Stylesheet),
|
HtmlDiscoveredStyle(Stylesheet),
|
||||||
HtmlDiscoveredIFrame((Url, SubpageId, bool)),
|
|
||||||
HtmlDiscoveredScript(JSResult)
|
HtmlDiscoveredScript(JSResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +248,6 @@ pub fn parse_html(page: &Page,
|
||||||
resource_task: ResourceTask)
|
resource_task: ResourceTask)
|
||||||
-> HtmlParserResult {
|
-> HtmlParserResult {
|
||||||
debug!("Hubbub: parsing {:?}", url);
|
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.
|
// Spawn a CSS parser to receive links to CSS style sheets.
|
||||||
|
|
||||||
let (discovery_chan, discovery_port) = channel();
|
let (discovery_chan, discovery_port) = channel();
|
||||||
|
@ -288,8 +283,6 @@ pub fn parse_html(page: &Page,
|
||||||
*page.mut_url() = Some((url2.clone(), true));
|
*page.mut_url() = Some((url2.clone(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pipeline_id = page.id;
|
|
||||||
|
|
||||||
let mut parser = hubbub::Parser("UTF-8", false);
|
let mut parser = hubbub::Parser("UTF-8", false);
|
||||||
debug!("created parser");
|
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 (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 doc_cell = RefCell::new(document);
|
||||||
|
|
||||||
let tree_handler = hubbub::TreeHandler {
|
let tree_handler = hubbub::TreeHandler {
|
||||||
|
@ -352,10 +343,6 @@ pub fn parse_html(page: &Page,
|
||||||
let href= element.get_attribute(Null, "href").root();
|
let href= element.get_attribute(Null, "href").root();
|
||||||
href.map(|a| a.deref().Value())
|
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
|
// Spawn additional parsing, network loads, etc. from tag and attrs
|
||||||
let type_id = {
|
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<HTMLIFrameElement> =
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use dom::node;
|
||||||
use dom::node::{Node, NodeHelpers};
|
use dom::node::{Node, NodeHelpers};
|
||||||
use dom::window::{TimerId, Window};
|
use dom::window::{TimerId, Window};
|
||||||
use html::hubbub_html_parser::HtmlParserResult;
|
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 html::hubbub_html_parser;
|
||||||
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
||||||
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery, MouseOverQuery, MouseOverResponse};
|
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery, MouseOverQuery, MouseOverResponse};
|
||||||
|
@ -43,8 +43,7 @@ use js::rust::with_compartment;
|
||||||
use js;
|
use js;
|
||||||
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout};
|
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout};
|
||||||
use servo_msg::compositor_msg::{ScriptListener};
|
use servo_msg::compositor_msg::{ScriptListener};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, IFrameSandboxed, IFrameUnsandboxed};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
|
||||||
use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
|
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
@ -157,6 +156,9 @@ pub struct Page {
|
||||||
|
|
||||||
/// Associated resource task for use by DOM objects like XMLHttpRequest
|
/// Associated resource task for use by DOM objects like XMLHttpRequest
|
||||||
pub resource_task: Untraceable<ResourceTask>,
|
pub resource_task: Untraceable<ResourceTask>,
|
||||||
|
|
||||||
|
/// A handle for communicating messages to the constellation task.
|
||||||
|
pub constellation_chan: Untraceable<ConstellationChan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PageTree {
|
pub struct PageTree {
|
||||||
|
@ -171,6 +173,7 @@ pub struct PageTreeIterator<'a> {
|
||||||
impl PageTree {
|
impl PageTree {
|
||||||
fn new(id: PipelineId, layout_chan: LayoutChan,
|
fn new(id: PipelineId, layout_chan: LayoutChan,
|
||||||
window_size: Size2D<uint>, resource_task: ResourceTask,
|
window_size: Size2D<uint>, resource_task: ResourceTask,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
js_context: Rc<Cx>) -> PageTree {
|
js_context: Rc<Cx>) -> PageTree {
|
||||||
let js_info = JSPageInfo {
|
let js_info = JSPageInfo {
|
||||||
dom_static: GlobalStaticData(),
|
dom_static: GlobalStaticData(),
|
||||||
|
@ -190,7 +193,8 @@ impl PageTree {
|
||||||
resize_event: Untraceable::new(Cell::new(None)),
|
resize_event: Untraceable::new(Cell::new(None)),
|
||||||
fragment_node: Traceable::new(RefCell::new(None)),
|
fragment_node: Traceable::new(RefCell::new(None)),
|
||||||
last_reflow_id: Traceable::new(Cell::new(0)),
|
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!(),
|
inner: vec!(),
|
||||||
}
|
}
|
||||||
|
@ -287,6 +291,13 @@ impl Page {
|
||||||
self.frame.deref().borrow_mut()
|
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.
|
/// Adds the given damage.
|
||||||
pub fn damage(&self, level: DocumentDamageLevel) {
|
pub fn damage(&self, level: DocumentDamageLevel) {
|
||||||
let root = match *self.frame() {
|
let root = match *self.frame() {
|
||||||
|
@ -595,7 +606,9 @@ impl ScriptTask {
|
||||||
-> Rc<ScriptTask> {
|
-> Rc<ScriptTask> {
|
||||||
let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
|
let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
|
||||||
let page_tree = PageTree::new(id, layout_chan, window_size,
|
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 {
|
Rc::new(ScriptTask {
|
||||||
page_tree: RefCell::new(page_tree),
|
page_tree: RefCell::new(page_tree),
|
||||||
|
|
||||||
|
@ -781,6 +794,7 @@ impl ScriptTask {
|
||||||
let window_size = parent_page_tree.page().window_size.deref().get();
|
let window_size = parent_page_tree.page().window_size.deref().get();
|
||||||
PageTree::new(new_id, layout_chan, window_size,
|
PageTree::new(new_id, layout_chan, window_size,
|
||||||
parent_page_tree.page().resource_task.deref().clone(),
|
parent_page_tree.page().resource_task.deref().clone(),
|
||||||
|
self.constellation_chan.clone(),
|
||||||
self.js_context.borrow().get_ref().clone())
|
self.js_context.borrow().get_ref().clone())
|
||||||
};
|
};
|
||||||
parent_page_tree.inner.push(new_page_tree);
|
parent_page_tree.inner.push(new_page_tree);
|
||||||
|
@ -973,20 +987,6 @@ impl ScriptTask {
|
||||||
let LayoutChan(ref chan) = *page.layout_chan;
|
let LayoutChan(ref chan) = *page.layout_chan;
|
||||||
chan.send(AddStylesheetMsg(sheet));
|
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
|
None => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче