diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/blob.rs | 3 | ||||
-rw-r--r-- | components/script/dom/comment.rs | 3 | ||||
-rw-r--r-- | components/script/dom/element.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 57 | ||||
-rw-r--r-- | components/script/dom/htmllinkelement.rs | 66 | ||||
-rw-r--r-- | components/script/dom/htmlstyleelement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/node.rs | 10 | ||||
-rw-r--r-- | components/script/dom/window.rs | 25 | ||||
-rw-r--r-- | components/script/html/cssparse.rs | 72 | ||||
-rw-r--r-- | components/script/html/hubbub_html_parser.rs | 220 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 3 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script/script_task.rs | 54 |
13 files changed, 247 insertions, 273 deletions
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 0bbdca9f93d..1266cce96b9 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -41,9 +41,6 @@ impl Blob { } } -pub trait BlobMethods { -} - impl Reflectable for Blob { fn reflector<'a>(&'a self) -> &'a Reflector { &self.reflector_ diff --git a/components/script/dom/comment.rs b/components/script/dom/comment.rs index dd070df87ac..5e82dae3716 100644 --- a/components/script/dom/comment.rs +++ b/components/script/dom/comment.rs @@ -46,9 +46,6 @@ impl Comment { } } -pub trait CommentMethods { -} - impl Reflectable for Comment { fn reflector<'a>(&'a self) -> &'a Reflector { self.characterdata.reflector() diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index ff7e4e1e925..953036788f4 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -806,7 +806,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { Err(()) => Err(Syntax), Ok(ref selectors) => { let root: &JSRef<Node> = NodeCast::from_ref(self); - Ok(matches(selectors, root)) + Ok(matches(selectors, root, &mut None)) } } } diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a731d0820b6..a5c83002327 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -76,36 +76,41 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { 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(); - UrlParser::new().base_url(&window.deref().page().get_url()) - .parse(src.deref().value().as_slice()).ok() + let url = src.deref().value(); + if url.as_slice().is_empty() { + None + } else { + let window = window_from_node(self).root(); + UrlParser::new().base_url(&window.deref().page().get_url()) + .parse(url.as_slice()).ok() + } }) } fn process_the_iframe_attributes(&self) { - 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().size.deref().set(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)); - } - _ => () - } + let url = match self.get_url() { + Some(url) => url.clone(), + None => Url::parse("about:blank").unwrap(), + }; + + 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().size.deref().set(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/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index d8389033bd1..3c44a9cba8b 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -2,20 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::attr::AttrHelpers; use dom::bindings::codegen::Bindings::HTMLLinkElementBinding; use dom::bindings::codegen::InheritTypes::HTMLLinkElementDerived; -use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast}; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; +use dom::bindings::js::{JSRef, Temporary, OptionalRootable}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::Document; -use dom::element::HTMLLinkElementTypeId; +use dom::element::{AttributeHandlers, Element, HTMLLinkElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; +use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; - +use layout_interface::{LayoutChan, LoadStylesheetMsg}; use servo_util::atom::Atom; -use servo_util::str::DOMString; +use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; +use servo_util::namespace::Null; + +use std::ascii::StrAsciiExt; +use url::UrlParser; #[deriving(Encodable)] #[must_root] @@ -74,6 +79,55 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { _ => () } } + + fn bind_to_tree(&self, tree_in_doc: bool) { + match self.super_type() { + Some(ref s) => s.bind_to_tree(tree_in_doc), + _ => () + } + + if tree_in_doc { + let element: &JSRef<Element> = ElementCast::from_ref(self); + + // FIXME: workaround for https://github.com/mozilla/rust/issues/13246; + // we get unrooting order failures if these are inside the match. + let rel = { + let rel = element.get_attribute(Null, "rel").root(); + rel.map(|rel| rel.deref().value().as_slice().to_string()) + }; + let href = { + let href = element.get_attribute(Null, "href").root(); + href.map(|href| href.deref().value().as_slice().to_string()) + }; + + match (rel, href) { + (Some(ref rel), Some(ref href)) => { + if rel.as_slice().split(HTML_SPACE_CHARACTERS.as_slice()) + .any(|s| s.as_slice().eq_ignore_ascii_case("stylesheet")) { + self.handle_stylesheet_url(href.as_slice()); + } + } + _ => {} + } + } + } +} + +trait PrivateHTMLLinkElementHelpers { + fn handle_stylesheet_url(&self, href: &str); +} + +impl<'a> PrivateHTMLLinkElementHelpers for JSRef<'a, HTMLLinkElement> { + fn handle_stylesheet_url(&self, href: &str) { + let window = window_from_node(self).root(); + match UrlParser::new().base_url(&window.deref().page().get_url()).parse(href) { + Ok(url) => { + let LayoutChan(ref layout_chan) = *window.deref().page().layout_chan; + layout_chan.send(LoadStylesheetMsg(url)); + } + Err(e) => debug!("Parsing url {:s} failed: {:?}", href, e) + } + } } impl Reflectable for HTMLLinkElement { diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 30aa81f15f1..d968c3bc6ee 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -13,9 +13,9 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; -use html::cssparse::parse_inline_css; use layout_interface::{AddStylesheetMsg, LayoutChan}; use servo_util::str::DOMString; +use style::Stylesheet; #[deriving(Encodable)] #[must_root] @@ -56,7 +56,7 @@ impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> { let url = win.deref().page().get_url(); let data = node.GetTextContent().expect("Element.textContent must be a string"); - let sheet = parse_inline_css(url, data); + let sheet = Stylesheet::from_str(data.as_slice(), url); let LayoutChan(ref layout_chan) = *win.deref().page().layout_chan; layout_chan.send(AddStylesheetMsg(sheet)); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b46adc488fd..9e1b73feb12 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -611,7 +611,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { Ok(ref selectors) => { let root = self.ancestors().last().unwrap_or(self.clone()); for node in root.traverse_preorder() { - if node.is_element() && matches(selectors, &node) { + if node.is_element() && matches(selectors, &node, &mut None) { let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap(); return Ok(Some(Temporary::from_rooted(elem))); } @@ -632,7 +632,9 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { // Step 3. Ok(ref selectors) => { nodes = root.traverse_preorder().filter( - |node| node.is_element() && matches(selectors, node)).collect() + // TODO(cgaebel): Is it worth it to build a bloom filter here + // (instead of passing `None`)? Probably. + |node| node.is_element() && matches(selectors, node, &mut None)).collect() } } let window = window_from_node(self).root(); @@ -1990,6 +1992,10 @@ impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> { (self as &NodeHelpers).parent_node().map(|node| *node.root()) } + fn tnode_first_child(&self) -> Option<JSRef<'a, Node>> { + (self as &NodeHelpers).first_child().map(|node| *node.root()) + } + fn prev_sibling(&self) -> Option<JSRef<'a, Node>> { (self as &NodeHelpers).prev_sibling().map(|node| *node.root()) } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d9c9cd5c6c6..75f1aaea79b 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -29,14 +29,15 @@ use servo_net::image_cache_task::ImageCacheTask; use servo_util::str::{DOMString,HTML_SPACE_CHARACTERS}; use servo_util::task::{spawn_named}; -use js::jsapi::JS_CallFunctionValue; +use js::jsapi::{JS_CallFunctionValue, JS_EvaluateUCScript}; use js::jsapi::JSContext; use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::JSVal; -use js::jsval::NullValue; +use js::jsval::{UndefinedValue, NullValue}; use js::rust::with_compartment; use url::{Url, UrlParser}; +use libc; use serialize::base64::{FromBase64, ToBase64, STANDARD}; use std::collections::hashmap::HashMap; use std::cell::{Cell, RefCell}; @@ -359,6 +360,7 @@ pub trait WindowHelpers { fn init_browser_context(&self, doc: &JSRef<Document>); fn load_url(&self, href: DOMString); fn handle_fire_timer(&self, timer_id: TimerId, cx: *mut JSContext); + fn evaluate_js_with_result(&self, code: &str) -> JSVal; } trait PrivateWindowHelpers { @@ -366,6 +368,25 @@ trait PrivateWindowHelpers { } impl<'a> WindowHelpers for JSRef<'a, Window> { + fn evaluate_js_with_result(&self, code: &str) -> JSVal { + let global = self.reflector().get_jsobject(); + let code: Vec<u16> = code.as_slice().utf16_units().collect(); + let mut rval = UndefinedValue(); + let filename = "".to_c_str(); + let cx = self.get_cx(); + + with_compartment(cx, global, || { + unsafe { + if JS_EvaluateUCScript(cx, global, code.as_ptr(), + code.len() as libc::c_uint, + filename.as_ptr(), 1, &mut rval) == 0 { + debug!("error evaluating JS string"); + } + rval + } + }) + } + fn damage_and_reflow(&self, damage: DocumentDamageLevel) { // FIXME This should probably be ReflowForQuery, not Display. All queries currently // currently rely on the display list, which means we can't destroy it by diff --git a/components/script/html/cssparse.rs b/components/script/html/cssparse.rs deleted file mode 100644 index 473b64c7d76..00000000000 --- a/components/script/html/cssparse.rs +++ /dev/null @@ -1,72 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/// Some little helpers for hooking up the HTML parser with the CSS parser. - -use std::comm::{channel, Receiver}; -use encoding::EncodingRef; -use encoding::all::UTF_8; -use style::Stylesheet; -use servo_net::resource_task::{Load, LoadData, LoadResponse, ProgressMsg, Payload, Done, ResourceTask}; -use servo_util::task::spawn_named; -use url::Url; - -/// Where a style sheet comes from. -pub enum StylesheetProvenance { - UrlProvenance(Url, ResourceTask), - InlineProvenance(Url, String), -} - -// Parses the style data and returns the stylesheet -pub fn parse_inline_css(url: Url, data: String) -> Stylesheet { - parse_css(InlineProvenance(url, data)) -} - -fn parse_css(provenance: StylesheetProvenance) -> Stylesheet { - // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding - let environment_encoding = UTF_8 as EncodingRef; - - match provenance { - UrlProvenance(url, resource_task) => { - debug!("cssparse: loading style sheet at {:s}", url.serialize()); - let (input_chan, input_port) = channel(); - resource_task.send(Load(LoadData::new(url), input_chan)); - let LoadResponse { metadata: metadata, progress_port: progress_port , ..} - = input_port.recv(); - let final_url = &metadata.final_url; - let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice()); - let iter = ProgressMsgPortIterator { progress_port: progress_port }; - Stylesheet::from_bytes_iter( - iter, final_url.clone(), - protocol_encoding_label, Some(environment_encoding)) - } - InlineProvenance(base_url, data) => { - debug!("cssparse: loading inline stylesheet {:s}", data); - Stylesheet::from_str(data.as_slice(), base_url) - } - } -} - -pub fn spawn_css_parser(provenance: StylesheetProvenance) -> Receiver<Stylesheet> { - let (result_chan, result_port) = channel(); - - spawn_named("cssparser", proc() { - result_chan.send(parse_css(provenance)); - }); - - return result_port; -} - -struct ProgressMsgPortIterator { - progress_port: Receiver<ProgressMsg> -} - -impl Iterator<Vec<u8>> for ProgressMsgPortIterator { - fn next(&mut self) -> Option<Vec<u8>> { - match self.progress_port.recv() { - Payload(data) => Some(data), - Done(..) => None - } - } -} diff --git a/components/script/html/hubbub_html_parser.rs b/components/script/html/hubbub_html_parser.rs index 89d817b9380..74dd6ca933b 100644 --- a/components/script/html/hubbub_html_parser.rs +++ b/components/script/html/hubbub_html_parser.rs @@ -10,14 +10,13 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast}; use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root}; use dom::bindings::utils::Reflectable; use dom::document::{Document, DocumentHelpers}; -use dom::element::{AttributeHandlers, HTMLLinkElementTypeId}; +use dom::element::AttributeHandlers; use dom::htmlelement::HTMLElement; use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6}; use dom::htmlformelement::HTMLFormElement; use dom::htmlscriptelement::HTMLScriptElementHelpers; -use dom::node::{ElementNodeTypeId, NodeHelpers}; +use dom::node::NodeHelpers; use dom::types::*; -use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser}; use page::Page; use encoding::all::UTF_8; @@ -29,13 +28,12 @@ use servo_net::resource_task::{Load, LoadData, Payload, Done, ResourceTask, load use servo_util::atom::Atom; use servo_util::namespace; use servo_util::namespace::{Namespace, Null}; -use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS}; +use servo_util::str::DOMString; use servo_util::task::spawn_named; use std::ascii::StrAsciiExt; use std::mem; use std::cell::RefCell; use std::comm::{channel, Sender, Receiver}; -use style::Stylesheet; use url::{Url, UrlParser}; use http::headers::HeaderEnum; use time; @@ -55,25 +53,24 @@ macro_rules! handle_element( pub struct JSFile { pub data: String, - pub url: Url + pub url: Option<Url>, } pub type JSResult = Vec<JSFile>; -enum CSSMessage { - CSSTaskNewFile(StylesheetProvenance), - CSSTaskExit +pub enum HTMLInput { + InputString(String), + InputUrl(Url), } enum JSMessage { JSTaskNewFile(Url), - JSTaskNewInlineScript(String, Url), + JSTaskNewInlineScript(String, Option<Url>), JSTaskExit } /// Messages generated by the HTML parser upon discovery of additional resources pub enum HtmlDiscoveryMessage { - HtmlDiscoveredStyle(Stylesheet), HtmlDiscoveredScript(JSResult) } @@ -95,43 +92,6 @@ unsafe fn from_hubbub_node<T: Reflectable>(n: hubbub::NodeDataPtr) -> Temporary< Temporary::new(JS::from_raw(mem::transmute(n))) } -/** -Runs a task that coordinates parsing links to css stylesheets. - -This function should be spawned in a separate task and spins waiting -for the html builder to find links to css stylesheets and sends off -tasks to parse each link. When the html process finishes, it notifies -the listener, who then collects the css rules from each task it -spawned, collates them, and sends them to the given result channel. - -# Arguments - -* `to_parent` - A channel on which to send back the full set of rules. -* `from_parent` - A port on which to receive new links. - -*/ -fn css_link_listener(to_parent: Sender<HtmlDiscoveryMessage>, - from_parent: Receiver<CSSMessage>) { - let mut result_vec = vec!(); - - loop { - match from_parent.recv_opt() { - Ok(CSSTaskNewFile(provenance)) => { - result_vec.push(spawn_css_parser(provenance)); - } - Ok(CSSTaskExit) | Err(()) => { - break; - } - } - } - - // Send the sheets back in order - // FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these - for port in result_vec.iter() { - assert!(to_parent.send_opt(HtmlDiscoveredStyle(port.recv())).is_ok()); - } -} - fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>, from_parent: Receiver<JSMessage>, resource_task: ResourceTask) { @@ -148,7 +108,7 @@ fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>, let decoded = UTF_8.decode(bytes.as_slice(), DecodeReplace).unwrap(); result_vec.push(JSFile { data: decoded.to_string(), - url: metadata.final_url, + url: Some(metadata.final_url), }); } } @@ -326,20 +286,13 @@ pub fn build_element_from_tag(tag: DOMString, ns: Namespace, document: &JSRef<Do pub fn parse_html(page: &Page, document: &JSRef<Document>, - url: Url, + input: HTMLInput, resource_task: ResourceTask) -> HtmlParserResult { - debug!("Hubbub: parsing {:?}", url); - // Spawn a CSS parser to receive links to CSS style sheets. - - let (discovery_chan, discovery_port) = channel(); - let stylesheet_chan = discovery_chan.clone(); - let (css_chan, css_msg_port) = channel(); - spawn_named("parse_html:css", proc() { - css_link_listener(stylesheet_chan, css_msg_port); - }); + debug!("Hubbub: parsing {:?}", input); // Spawn a JS parser to receive JavaScript. + let (discovery_chan, discovery_port) = channel(); let resource_task2 = resource_task.clone(); let js_result_chan = discovery_chan.clone(); let (js_chan, js_msg_port) = channel(); @@ -347,38 +300,50 @@ pub fn parse_html(page: &Page, js_script_listener(js_result_chan, js_msg_port, resource_task2.clone()); }); - // Wait for the LoadResponse so that the parser knows the final URL. - let (input_chan, input_port) = channel(); - resource_task.send(Load(LoadData::new(url.clone()), input_chan)); - let load_response = input_port.recv(); + let (base_url, load_response) = match input { + InputUrl(ref url) => { + // Wait for the LoadResponse so that the parser knows the final URL. + let (input_chan, input_port) = channel(); + resource_task.send(Load(LoadData::new(url.clone()), input_chan)); + let load_response = input_port.recv(); - debug!("Fetched page; metadata is {:?}", load_response.metadata); + debug!("Fetched page; metadata is {:?}", load_response.metadata); - load_response.metadata.headers.map(|headers| { - let header = headers.iter().find(|h| - h.header_name().as_slice().to_ascii_lower() == "last-modified".to_string() - ); + load_response.metadata.headers.as_ref().map(|headers| { + let header = headers.iter().find(|h| + h.header_name().as_slice().to_ascii_lower() == "last-modified".to_string() + ); - match header { - Some(h) => document.set_last_modified( - parse_last_modified(h.header_value().as_slice())), - None => {}, - }; - }); + match header { + Some(h) => document.set_last_modified( + parse_last_modified(h.header_value().as_slice())), + None => {}, + }; + }); - let base_url = &load_response.metadata.final_url; + let base_url = load_response.metadata.final_url.clone(); - { - // Store the final URL before we start parsing, so that DOM routines - // (e.g. HTMLImageElement::update_image) can resolve relative URLs - // correctly. - *page.mut_url() = Some((base_url.clone(), true)); - } + { + // Store the final URL before we start parsing, so that DOM routines + // (e.g. HTMLImageElement::update_image) can resolve relative URLs + // correctly. + *page.mut_url() = Some((base_url.clone(), true)); + } + + (Some(base_url), Some(load_response)) + }, + InputString(_) => { + match *page.url() { + Some((ref page_url, _)) => (Some(page_url.clone()), None), + None => (None, None), + } + }, + }; let mut parser = build_parser(unsafe { document.to_hubbub_node() }); debug!("created parser"); - let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone()); + let js_chan2 = js_chan.clone(); let doc_cell = RefCell::new(document); @@ -430,46 +395,6 @@ pub fn parse_html(page: &Page, prefix.map(|p| p.to_string())); } - //FIXME: workaround for https://github.com/mozilla/rust/issues/13246; - // we get unrooting order failures if these are inside the match. - let rel = { - let rel = element.deref().get_attribute(Null, "rel").root(); - rel.map(|a| a.deref().Value()) - }; - let href = { - let href= element.deref().get_attribute(Null, "href").root(); - href.map(|a| a.deref().Value()) - }; - - // Spawn additional parsing, network loads, etc. from tag and attrs - let type_id = { - let node: &JSRef<Node> = NodeCast::from_ref(&*element); - node.type_id() - }; - match type_id { - // Handle CSS style sheets from <link> elements - ElementNodeTypeId(HTMLLinkElementTypeId) => { - match (rel, href) { - (Some(ref rel), Some(ref href)) => { - if rel.as_slice() - .split(HTML_SPACE_CHARACTERS.as_slice()) - .any(|s| { - s.as_slice().eq_ignore_ascii_case("stylesheet") - }) { - debug!("found CSS stylesheet: {:s}", *href); - match UrlParser::new().base_url(base_url).parse(href.as_slice()) { - Ok(url) => css_chan2.send(CSSTaskNewFile( - UrlProvenance(url, resource_task.clone()))), - Err(e) => debug!("Parsing url {:s} failed: {:?}", *href, e) - }; - } - } - _ => {} - } - } - _ => {} - } - unsafe { element.deref().to_hubbub_node() } }, create_text: |data: String| { @@ -550,8 +475,14 @@ pub fn parse_html(page: &Page, match script_element.get_attribute(Null, "src").root() { Some(src) => { debug!("found script: {:s}", src.deref().Value()); - match UrlParser::new().base_url(base_url) - .parse(src.deref().value().as_slice()) { + let mut url_parser = UrlParser::new(); + match base_url { + None => (), + Some(ref base_url) => { + url_parser.base_url(base_url); + } + }; + match url_parser.parse(src.deref().value().as_slice()) { Ok(new_url) => js_chan2.send(JSTaskNewFile(new_url)), Err(e) => debug!("Parsing url {:s} failed: {:?}", src.deref().Value(), e) }; @@ -580,29 +511,36 @@ pub fn parse_html(page: &Page, parser.set_tree_handler(&mut tree_handler); debug!("set tree handler"); debug!("loaded page"); - match load_response.metadata.content_type { - Some((ref t, _)) if t.as_slice().eq_ignore_ascii_case("image") => { - let page = format!("<html><body><img src='{:s}' /></body></html>", base_url.serialize()); - parser.parse_chunk(page.into_bytes().as_slice()); + match input { + InputString(s) => { + parser.parse_chunk(s.into_bytes().as_slice()); }, - _ => loop { - match load_response.progress_port.recv() { - Payload(data) => { - debug!("received data"); - parser.parse_chunk(data.as_slice()); - } - Done(Err(err)) => { - fail!("Failed to load page URL {:s}, error: {:s}", url.serialize(), err); - } - Done(..) => { - break; + InputUrl(url) => { + let load_response = load_response.unwrap(); + match load_response.metadata.content_type { + Some((ref t, _)) if t.as_slice().eq_ignore_ascii_case("image") => { + let page = format!("<html><body><img src='{:s}' /></body></html>", base_url.get_ref().serialize()); + parser.parse_chunk(page.into_bytes().as_slice()); + }, + _ => loop { + match load_response.progress_port.recv() { + Payload(data) => { + debug!("received data"); + parser.parse_chunk(data.as_slice()); + } + Done(Err(err)) => { + fail!("Failed to load page URL {:s}, error: {:s}", url.serialize(), err); + } + Done(..) => { + break; + } + } } } - } + }, } debug!("finished parsing"); - css_chan.send(CSSTaskExit); js_chan.send(JSTaskExit); HtmlParserResult { diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 1e5e23f9c9a..0c82c61447d 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -29,6 +29,9 @@ pub enum Msg { /// Adds the given stylesheet to the document. AddStylesheetMsg(Stylesheet), + /// Adds the given stylesheet to the document. + LoadStylesheetMsg(Url), + /// Requests a reflow. ReflowMsg(Box<Reflow>), diff --git a/components/script/lib.rs b/components/script/lib.rs index 939238df1a4..9f3effaa368 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -200,7 +200,6 @@ pub mod dom { /// Parsers for HTML and CSS. pub mod html { - pub mod cssparse; pub mod hubbub_html_parser; } diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 88e2f42415a..8dc4578abb8 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -6,6 +6,7 @@ //! and layout tasks. use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, EventCast}; +use dom::bindings::conversions::{FromJSValConvertible, Empty}; use dom::bindings::global::Window; use dom::bindings::js::{JS, JSRef, RootCollection, Temporary, OptionalSettable}; use dom::bindings::js::OptionalRootable; @@ -22,10 +23,8 @@ use dom::node::{ElementNodeTypeId, Node, NodeHelpers}; use dom::window::{TimerId, Window, WindowHelpers}; use dom::worker::{Worker, TrustedWorkerAddress}; use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress}; -use html::hubbub_html_parser::HtmlParserResult; -use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript}; +use html::hubbub_html_parser::{InputString, InputUrl, HtmlParserResult, HtmlDiscoveredScript}; use html::hubbub_html_parser; -use layout_interface::AddStylesheetMsg; use layout_interface::{ScriptLayoutChan, LayoutChan, MatchSelectorsDocumentDamage}; use layout_interface::{ReflowDocumentDamage, ReflowForDisplay}; use layout_interface::ContentChangedDocumentDamage; @@ -590,7 +589,7 @@ impl ScriptTask { /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. fn load(&self, pipeline_id: PipelineId, url: Url) { - debug!("ScriptTask: loading {:?} on page {:?}", url, pipeline_id); + debug!("ScriptTask: loading {} on page {:?}", url, pipeline_id); let mut page = self.page.borrow_mut(); let page = page.find(pipeline_id).expect("ScriptTask: received a load @@ -610,6 +609,9 @@ impl ScriptTask { _ => (), } + let is_javascript = url.scheme.as_slice() == "javascript"; + let last_url = last_loaded_url.map(|(ref loaded, _)| loaded.clone()); + let cx = self.js_context.borrow(); let cx = cx.get_ref(); // Create the window and document objects. @@ -619,17 +621,39 @@ impl ScriptTask { self.control_chan.clone(), self.compositor.dup(), self.image_cache_task.clone()).root(); - let document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root(); + let doc_url = if is_javascript { + let doc_url = match last_url { + Some(url) => Some(url.clone()), + None => Url::parse("about:blank").ok(), + }; + *page.mut_url() = Some((doc_url.get_ref().clone(), true)); + doc_url + } else { + Some(url.clone()) + }; + let document = Document::new(&*window, doc_url, HTMLDocument, None).root(); + window.deref().init_browser_context(&*document); self.compositor.set_ready_state(pipeline_id, Loading); + + let parser_input = if !is_javascript { + InputUrl(url.clone()) + } else { + let evalstr = url.non_relative_scheme_data().unwrap(); + let jsval = window.evaluate_js_with_result(evalstr); + let strval = FromJSValConvertible::from_jsval(self.get_cx(), jsval, Empty); + InputString(strval.unwrap_or("".to_string())) + }; + // Parse HTML. // // Note: We can parse the next document in parallel with any previous documents. - let html_parsing_result = hubbub_html_parser::parse_html(&*page, - &*document, - url.clone(), - self.resource_task.clone()); + let html_parsing_result = + hubbub_html_parser::parse_html(&*page, + &*document, + parser_input, + self.resource_task.clone()); let HtmlParserResult { discovery_port @@ -656,15 +680,12 @@ impl ScriptTask { assert!(js_scripts.is_none()); js_scripts = Some(scripts); } - Ok(HtmlDiscoveredStyle(sheet)) => { - let LayoutChan(ref chan) = *page.layout_chan; - chan.send(AddStylesheetMsg(sheet)); - } Err(()) => break } } // Kick off the initial reflow of the page. + debug!("kicking off initial reflow of {}", url); document.deref().content_changed(); let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_string()); @@ -684,9 +705,14 @@ impl ScriptTask { // Evaluate every script in the document. for file in js_scripts.iter() { let global_obj = window.reflector().get_jsobject(); + let filename = match file.url { + None => String::new(), + Some(ref url) => url.serialize(), + }; + //FIXME: this should have some kind of error handling, or explicitly // drop an exception on the floor. - match cx.evaluate_script(global_obj, file.data.clone(), file.url.serialize(), 1) { + match cx.evaluate_script(global_obj, file.data.clone(), filename, 1) { Ok(_) => (), Err(_) => println!("evaluate_script failed") } |