aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorTill Schneidereit <till@tillschneidereit.net>2015-10-06 15:55:28 +0200
committerTill Schneidereit <till@tillschneidereit.net>2015-11-07 18:11:29 +0100
commit543703e3d8d7dde5efd280fb01e42061287c7002 (patch)
tree3b36ac6d5b08f842035f7f9b2eed16b94aeb0d28 /components/script
parent068e6a8e9f926fa6e8649b934ee9ffe2ef7b78de (diff)
downloadservo-543703e3d8d7dde5efd280fb01e42061287c7002.tar.gz
servo-543703e3d8d7dde5efd280fb01e42061287c7002.zip
Move Stylesheet loading and ownership from the layout task into HTML elements
Stylesheets for `HTMLLinkElement`s are now loaded by the resource task, triggered by the element in question. Stylesheets are owned by the elements they're associated with, which can be `HTMLStyleElement`, `HTMLLinkElement`, and `HTMLMetaElement` (for `<meta name="viewport">). Additionally, the quirks mode stylesheet (just as the user and user agent stylesheets a couple of commits ago), is implemented as a lazy static, loaded once per process and shared between all documents. This all has various nice consequences: - Stylesheet loading becomes a non-blocking operation. - Stylesheets are removed when the element they're associated with is removed from the document. - It'll be possible to implement the CSSOM APIs that require direct access to the stylesheets (i.e., ~ all of them). - Various subtle correctness issues are fixed. One piece of interesting follow-up work would be to move parsing of external stylesheets to the resource task, too. Right now, it happens in the link element once loading is complete, so blocks the script task. Moving it to the resource task would probably be fairly straight-forward as it doesn't require access to any external state.
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/create.rs2
-rw-r--r--components/script/dom/document.rs58
-rw-r--r--components/script/dom/htmllinkelement.rs163
-rw-r--r--components/script/dom/htmlmetaelement.rs29
-rw-r--r--components/script/dom/htmlstyleelement.rs24
-rw-r--r--components/script/dom/window.rs7
-rw-r--r--components/script/layout_interface.rs18
-rw-r--r--components/script/script_task.rs13
8 files changed, 232 insertions, 82 deletions
diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs
index 4e2b07399b1..2f1d35d3b59 100644
--- a/components/script/dom/create.rs
+++ b/components/script/dom/create.rs
@@ -174,7 +174,7 @@ pub fn create_element(name: QualName, prefix: Option<Atom>,
atom!("label") => make!(HTMLLabelElement),
atom!("legend") => make!(HTMLLegendElement),
atom!("li") => make!(HTMLLIElement),
- atom!("link") => make!(HTMLLinkElement),
+ atom!("link") => make!(HTMLLinkElement, creator),
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:listing
atom!("listing") => make!(HTMLPreElement),
atom!("main") => make!(HTMLElement),
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index b39adbc53fc..4d5fb5e2ccd 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -48,7 +48,10 @@ use dom::htmlheadelement::HTMLHeadElement;
use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::htmliframeelement::{self, HTMLIFrameElement};
use dom::htmlimageelement::HTMLImageElement;
+use dom::htmllinkelement::HTMLLinkElement;
+use dom::htmlmetaelement::HTMLMetaElement;
use dom::htmlscriptelement::HTMLScriptElement;
+use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltitleelement::HTMLTitleElement;
use dom::keyboardevent::KeyboardEvent;
use dom::location::Location;
@@ -96,8 +99,10 @@ use std::default::Default;
use std::iter::FromIterator;
use std::ptr;
use std::rc::Rc;
+use std::sync::Arc;
use std::sync::mpsc::channel;
use string_cache::{Atom, QualName};
+use style::stylesheets::Stylesheet;
use time;
use url::Url;
use util::str::{DOMString, split_html_space_chars, str_join};
@@ -135,6 +140,10 @@ pub struct Document {
scripts: MutNullableHeap<JS<HTMLCollection>>,
anchors: MutNullableHeap<JS<HTMLCollection>>,
applets: MutNullableHeap<JS<HTMLCollection>>,
+ /// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed.
+ stylesheets: DOMRefCell<Option<Vec<Arc<Stylesheet>>>>,
+ /// Whether the list of stylesheets has changed since the last reflow was triggered.
+ stylesheets_changed_since_reflow: Cell<bool>,
ready_state: Cell<DocumentReadyState>,
/// Whether the DOMContentLoaded event has already been dispatched.
domcontentloaded_dispatched: Cell<bool>,
@@ -983,6 +992,21 @@ impl Document {
count_cell.set(count_cell.get() - 1);
}
+ pub fn invalidate_stylesheets(&self) {
+ self.stylesheets_changed_since_reflow.set(true);
+ *self.stylesheets.borrow_mut() = None;
+ // Mark the document element dirty so a reflow will be performed.
+ self.get_html_element().map(|root| {
+ root.upcast::<Node>().dirty(NodeDamage::NodeStyleDamaged);
+ });
+ }
+
+ pub fn get_and_reset_stylesheets_changed_since_reflow(&self) -> bool {
+ let changed = self.stylesheets_changed_since_reflow.get();
+ self.stylesheets_changed_since_reflow.set(false);
+ changed
+ }
+
pub fn set_pending_parsing_blocking_script(&self, script: Option<&HTMLScriptElement>) {
assert!(self.get_pending_parsing_blocking_script().is_none() || script.is_none());
self.pending_parsing_blocking_script.set(script);
@@ -1100,6 +1124,13 @@ impl Document {
if parser.is_suspended() {
parser.resume();
}
+ } else if self.reflow_timeout.get().is_none() {
+ // If we don't have a parser, and the reflow timer has been reset, explicitly
+ // trigger a reflow.
+ if let LoadType::Stylesheet(_) = load {
+ self.window().reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery,
+ ReflowReason::StylesheetLoaded);
+ }
}
let loader = self.loader.borrow();
@@ -1304,6 +1335,8 @@ impl Document {
scripts: Default::default(),
anchors: Default::default(),
applets: Default::default(),
+ stylesheets: DOMRefCell::new(None),
+ stylesheets_changed_since_reflow: Cell::new(false),
ready_state: Cell::new(ready_state),
domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
possibly_focused: Default::default(),
@@ -1369,6 +1402,31 @@ impl Document {
self.GetDocumentElement().and_then(Root::downcast)
}
+ /// Returns the list of stylesheets associated with nodes in the document.
+ pub fn stylesheets(&self) -> Ref<Vec<Arc<Stylesheet>>> {
+ {
+ let mut stylesheets = self.stylesheets.borrow_mut();
+ if stylesheets.is_none() {
+ let new_stylesheets: Vec<Arc<Stylesheet>> = self.upcast::<Node>()
+ .traverse_preorder()
+ .filter_map(|node| {
+ if let Some(node) = node.downcast::<HTMLStyleElement>() {
+ node.get_stylesheet()
+ } else if let Some(node) = node.downcast::<HTMLLinkElement>() {
+ node.get_stylesheet()
+ } else if let Some(node) = node.downcast::<HTMLMetaElement>() {
+ node.get_stylesheet()
+ } else {
+ None
+ }
+ })
+ .collect();
+ *stylesheets = Some(new_stylesheets);
+ };
+ }
+ Ref::map(self.stylesheets.borrow(), |t| t.as_ref().unwrap())
+ }
+
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
pub fn appropriate_template_contents_owner_document(&self) -> Root<Document> {
self.appropriate_template_contents_owner_document.or_init(|| {
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs
index 6fd36f60074..2860c98dd5c 100644
--- a/components/script/dom/htmllinkelement.rs
+++ b/components/script/dom/htmllinkelement.rs
@@ -5,55 +5,76 @@
use cssparser::Parser as CssParser;
use document_loader::LoadType;
use dom::attr::{Attr, AttrValue};
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
-use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::js::{RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::document::Document;
use dom::domtokenlist::DOMTokenList;
-use dom::element::{AttributeMutation, Element};
-use dom::event::{Event, EventBubbles, EventCancelable};
-use dom::eventtarget::EventTarget;
+use dom::element::{AttributeMutation, Element, ElementCreator};
use dom::htmlelement::HTMLElement;
-use dom::node::{Node, window_from_node};
+use dom::node::{Node, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
+use encoding::EncodingRef;
+use encoding::all::UTF_8;
+use ipc_channel::ipc;
+use ipc_channel::router::ROUTER;
use layout_interface::{LayoutChan, Msg};
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;
-use script_traits::StylesheetLoadResponder;
+use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata};
+use network_listener::{NetworkListener, PreInvoke};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
+use std::cell::Cell;
use std::default::Default;
+use std::mem;
+use std::sync::{Arc, Mutex};
use string_cache::Atom;
-use style::media_queries::parse_media_query_list;
-use url::UrlParser;
+use style::media_queries::{MediaQueryList, parse_media_query_list};
+use style::stylesheets::{Origin, Stylesheet};
+use url::{Url, UrlParser};
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
+no_jsmanaged_fields!(Stylesheet);
+
#[dom_struct]
pub struct HTMLLinkElement {
htmlelement: HTMLElement,
rel_list: MutNullableHeap<JS<DOMTokenList>>,
+ stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
+
+ /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts
+ parser_inserted: Cell<bool>,
}
impl HTMLLinkElement {
- fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLLinkElement {
+ fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document,
+ creator: ElementCreator) -> HTMLLinkElement {
HTMLLinkElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
rel_list: Default::default(),
+ parser_inserted: Cell::new(creator == ElementCreator::ParserCreated),
+ stylesheet: DOMRefCell::new(None),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
- document: &Document) -> Root<HTMLLinkElement> {
- let element = HTMLLinkElement::new_inherited(localName, prefix, document);
+ document: &Document,
+ creator: ElementCreator) -> Root<HTMLLinkElement> {
+ let element = HTMLLinkElement::new_inherited(localName, prefix, document, creator);
Node::reflect_node(box element, document, HTMLLinkElementBinding::Wrap)
}
+
+ pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
+ self.stylesheet.borrow().clone()
+ }
}
fn get_attr(element: &Element, local_name: &Atom) -> Option<String> {
@@ -64,7 +85,7 @@ fn get_attr(element: &Element, local_name: &Atom) -> Option<String> {
})
}
-fn is_stylesheet(value: &Option<String>) -> bool {
+fn string_is_stylesheet(value: &Option<String>) -> bool {
match *value {
Some(ref value) => {
value.split(HTML_SPACE_CHARACTERS)
@@ -100,14 +121,14 @@ impl VirtualMethods for HTMLLinkElement {
let rel = get_attr(self.upcast(), &atom!(rel));
match attr.local_name() {
&atom!(href) => {
- if is_stylesheet(&rel) {
+ if string_is_stylesheet(&rel) {
self.handle_stylesheet_url(&attr.value());
} else if is_favicon(&rel) {
self.handle_favicon_url(&attr.value());
}
},
&atom!(media) => {
- if is_stylesheet(&rel) {
+ if string_is_stylesheet(&rel) {
self.handle_stylesheet_url(&attr.value());
}
},
@@ -134,7 +155,7 @@ impl VirtualMethods for HTMLLinkElement {
let href = get_attr(element, &atom!("href"));
match (rel, href) {
- (ref rel, Some(ref href)) if is_stylesheet(rel) => {
+ (ref rel, Some(ref href)) if string_is_stylesheet(rel) => {
self.handle_stylesheet_url(href);
}
(ref rel, Some(ref href)) if is_favicon(rel) => {
@@ -164,13 +185,35 @@ impl HTMLLinkElement {
let mut css_parser = CssParser::new(&mq_str);
let media = parse_media_query_list(&mut css_parser);
+ // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match.
let doc = window.Document();
- let link_element = Trusted::new(window.get_cx(), self, window.script_chan().clone());
- let load_dispatcher = StylesheetLoadDispatcher::new(link_element);
+ let script_chan = window.script_chan();
+ let elem = Trusted::new(window.get_cx(), self, script_chan.clone());
+
+ let context = Arc::new(Mutex::new(StylesheetContext {
+ elem: elem,
+ media: Some(media),
+ data: vec!(),
+ metadata: None,
+ url: url.clone(),
+ }));
+
+ let (action_sender, action_receiver) = ipc::channel().unwrap();
+ let listener = NetworkListener {
+ context: context,
+ script_chan: script_chan,
+ };
+ let response_target = AsyncResponseTarget {
+ sender: action_sender,
+ };
+ ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
+ listener.notify(message.to().unwrap());
+ });
- let pending = doc.prepare_async_load(LoadType::Stylesheet(url.clone()));
- let LayoutChan(ref layout_chan) = window.layout_chan();
- layout_chan.send(Msg::LoadStylesheet(url, media, pending, box load_dispatcher)).unwrap();
+ if self.parser_inserted.get() {
+ doc.increment_script_blocking_stylesheet_count();
+ }
+ doc.load_async(LoadType::Stylesheet(url), response_target);
}
Err(e) => debug!("Parsing url {} failed: {}", href, e)
}
@@ -190,6 +233,62 @@ impl HTMLLinkElement {
}
}
+/// The context required for asynchronously loading an external stylesheet.
+struct StylesheetContext {
+ /// The element that initiated the request.
+ elem: Trusted<HTMLLinkElement>,
+ media: Option<MediaQueryList>,
+ /// The response body received to date.
+ data: Vec<u8>,
+ /// The response metadata received to date.
+ metadata: Option<Metadata>,
+ /// The initial URL requested.
+ url: Url,
+}
+
+impl PreInvoke for StylesheetContext {}
+
+impl AsyncResponseListener for StylesheetContext {
+ fn headers_available(&mut self, metadata: Metadata) {
+ self.metadata = Some(metadata);
+ }
+
+ fn data_available(&mut self, payload: Vec<u8>) {
+ let mut payload = payload;
+ self.data.append(&mut payload);
+ }
+
+ fn response_complete(&mut self, _status: Result<(), String>) {
+ let data = mem::replace(&mut self.data, vec!());
+ let metadata = self.metadata.take().unwrap();
+ // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
+ let environment_encoding = UTF_8 as EncodingRef;
+ let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s);
+ let final_url = metadata.final_url;
+ let mut sheet = Stylesheet::from_bytes(&data, final_url, protocol_encoding_label,
+ Some(environment_encoding), Origin::Author);
+ let media = self.media.take().unwrap();
+ sheet.set_media(Some(media));
+ let sheet = Arc::new(sheet);
+
+ let elem = self.elem.root();
+ let elem = elem.r();
+ let document = document_from_node(elem);
+ let document = document.r();
+
+ let win = window_from_node(elem);
+ let LayoutChan(ref layout_chan) = win.r().layout_chan();
+ layout_chan.send(Msg::AddStylesheet(sheet.clone())).unwrap();
+
+ *elem.stylesheet.borrow_mut() = Some(sheet);
+ document.invalidate_stylesheets();
+ if elem.parser_inserted.get() {
+ document.decrement_script_blocking_stylesheet_count();
+ }
+ document.finish_load(LoadType::Stylesheet(self.url.clone()));
+ }
+}
+
impl HTMLLinkElementMethods for HTMLLinkElement {
// https://html.spec.whatwg.org/multipage/#dom-link-href
make_url_getter!(Href);
@@ -244,27 +343,3 @@ impl HTMLLinkElementMethods for HTMLLinkElement {
// https://html.spec.whatwg.org/multipage/#dom-link-target
make_setter!(SetTarget, "target");
}
-
-pub struct StylesheetLoadDispatcher {
- elem: Trusted<HTMLLinkElement>,
-}
-
-impl StylesheetLoadDispatcher {
- pub fn new(elem: Trusted<HTMLLinkElement>) -> StylesheetLoadDispatcher {
- StylesheetLoadDispatcher {
- elem: elem,
- }
- }
-}
-
-impl StylesheetLoadResponder for StylesheetLoadDispatcher {
- fn respond(self: Box<StylesheetLoadDispatcher>) {
- let elem = self.elem.root();
- let window = window_from_node(elem.r());
- let event = Event::new(GlobalRef::Window(window.r()),
- DOMString("load".to_owned()),
- EventBubbles::DoesNotBubble,
- EventCancelable::NotCancelable);
- event.fire(elem.upcast::<EventTarget>());
- }
-}
diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs
index e615a0efbf7..dd0245104cb 100644
--- a/components/script/dom/htmlmetaelement.rs
+++ b/components/script/dom/htmlmetaelement.rs
@@ -2,6 +2,7 @@
* 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::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
use dom::bindings::inheritance::Castable;
@@ -9,16 +10,18 @@ use dom::bindings::js::{Root, RootedReference};
use dom::document::Document;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
-use dom::node::{Node, window_from_node};
+use dom::node::{Node, document_from_node};
use dom::virtualmethods::VirtualMethods;
-use layout_interface::{LayoutChan, Msg};
use std::ascii::AsciiExt;
+use std::sync::Arc;
+use style::stylesheets::{CSSRule, Origin, Stylesheet};
use style::viewport::ViewportRule;
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
#[dom_struct]
pub struct HTMLMetaElement {
htmlelement: HTMLElement,
+ stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
}
impl HTMLMetaElement {
@@ -26,7 +29,8 @@ impl HTMLMetaElement {
prefix: Option<DOMString>,
document: &Document) -> HTMLMetaElement {
HTMLMetaElement {
- htmlelement: HTMLElement::new_inherited(localName, prefix, document)
+ htmlelement: HTMLElement::new_inherited(localName, prefix, document),
+ stylesheet: DOMRefCell::new(None),
}
}
@@ -38,6 +42,10 @@ impl HTMLMetaElement {
Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap)
}
+ pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
+ self.stylesheet.borrow().clone()
+ }
+
fn process_attributes(&self) {
let element = self.upcast::<Element>();
if let Some(name) = element.get_attribute(&ns!(""), &atom!("name")).r() {
@@ -45,22 +53,25 @@ impl HTMLMetaElement {
let name = name.trim_matches(HTML_SPACE_CHARACTERS);
match name {
- "viewport" => self.translate_viewport(),
+ "viewport" => self.apply_viewport(),
_ => {}
}
}
}
- fn translate_viewport(&self) {
+ fn apply_viewport(&self) {
let element = self.upcast::<Element>();
if let Some(content) = element.get_attribute(&ns!(""), &atom!("content")).r() {
let content = content.value();
if !content.is_empty() {
if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
- let win = window_from_node(self);
- let LayoutChan(ref layout_chan) = win.layout_chan();
-
- layout_chan.send(Msg::AddMetaViewport(translated_rule)).unwrap();
+ *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
+ rules: vec![CSSRule::Viewport(translated_rule)],
+ origin: Origin::Author,
+ media: None,
+ }));
+ let doc = document_from_node(self);
+ doc.invalidate_stylesheets();
}
}
}
diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs
index d1ac6dcc37b..e225ec33981 100644
--- a/components/script/dom/htmlstyleelement.rs
+++ b/components/script/dom/htmlstyleelement.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::Parser as CssParser;
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
@@ -10,9 +11,10 @@ use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
-use dom::node::{ChildrenMutation, Node, window_from_node};
+use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use layout_interface::{LayoutChan, Msg};
+use std::sync::Arc;
use style::media_queries::parse_media_query_list;
use style::stylesheets::{Origin, Stylesheet};
use util::str::DOMString;
@@ -20,6 +22,7 @@ use util::str::DOMString;
#[dom_struct]
pub struct HTMLStyleElement {
htmlelement: HTMLElement,
+ stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
}
impl HTMLStyleElement {
@@ -27,7 +30,8 @@ impl HTMLStyleElement {
prefix: Option<DOMString>,
document: &Document) -> HTMLStyleElement {
HTMLStyleElement {
- htmlelement: HTMLElement::new_inherited(localName, prefix, document)
+ htmlelement: HTMLElement::new_inherited(localName, prefix, document),
+ stylesheet: DOMRefCell::new(None),
}
}
@@ -52,13 +56,23 @@ impl HTMLStyleElement {
Some(a) => String::from(&**a.value()),
None => String::new(),
};
+
+ let data = node.GetTextContent().expect("Element.textContent must be a string");
+ let mut sheet = Stylesheet::from_str(&data, url, Origin::Author);
let mut css_parser = CssParser::new(&mq_str);
let media = parse_media_query_list(&mut css_parser);
+ sheet.set_media(Some(media));
+ let sheet = Arc::new(sheet);
- let data = node.GetTextContent().expect("Element.textContent must be a string");
- let sheet = Stylesheet::from_str(&data, url, Origin::Author);
let LayoutChan(ref layout_chan) = win.layout_chan();
- layout_chan.send(Msg::AddStylesheet(sheet, media)).unwrap();
+ layout_chan.send(Msg::AddStylesheet(sheet.clone())).unwrap();
+ *self.stylesheet.borrow_mut() = Some(sheet);
+ let doc = document_from_node(self);
+ doc.r().invalidate_stylesheets();
+ }
+
+ pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
+ self.stylesheet.borrow().clone()
}
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index e296cea77d5..e50674c222c 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -99,6 +99,7 @@ pub enum ReflowReason {
WindowResize,
DOMContentLoaded,
DocumentLoaded,
+ StylesheetLoaded,
ImageLoaded,
RequestAnimationFrame,
WebFontLoaded,
@@ -915,6 +916,9 @@ impl Window {
debug_reflow_events(&goal, &query_type, &reason);
}
+ let document = self.Document();
+ let stylesheets_changed = document.get_and_reset_stylesheets_changed_since_reflow();
+
// Send new document and relevant styles to layout.
let reflow = ScriptReflow {
reflow_info: Reflow {
@@ -922,6 +926,8 @@ impl Window {
page_clip_rect: self.page_clip_rect.get(),
},
document: self.Document().upcast::<Node>().to_trusted_node_address(),
+ document_stylesheets: document.stylesheets().clone(),
+ stylesheets_changed: stylesheets_changed,
window_size: window_size,
script_join_chan: join_chan,
query_type: query_type,
@@ -1325,6 +1331,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
ReflowReason::WindowResize => "\tWindowResize",
ReflowReason::DOMContentLoaded => "\tDOMContentLoaded",
ReflowReason::DocumentLoaded => "\tDocumentLoaded",
+ ReflowReason::StylesheetLoaded => "\tStylesheetLoaded",
ReflowReason::ImageLoaded => "\tImageLoaded",
ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame",
ReflowReason::WebFontLoaded => "\tWebFontLoaded",
diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs
index afc7adedbd3..f6d96f1f09f 100644
--- a/components/script/layout_interface.rs
+++ b/components/script/layout_interface.rs
@@ -16,32 +16,24 @@ use msg::compositor_msg::Epoch;
use msg::compositor_msg::LayerId;
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
use msg::constellation_msg::{WindowSizeData};
-use net_traits::PendingAsyncLoad;
use net_traits::image_cache_task::ImageCacheTask;
use profile_traits::mem::ReportsChan;
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
-use script_traits::{OpaqueScriptLayoutChannel, StylesheetLoadResponder, UntrustedNodeAddress};
+use script_traits::{OpaqueScriptLayoutChannel, UntrustedNodeAddress};
use selectors::parser::PseudoElement;
use std::any::Any;
+use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
use string_cache::Atom;
use style::animation::PropertyAnimation;
-use style::media_queries::MediaQueryList;
use style::stylesheets::Stylesheet;
-use style::viewport::ViewportRule;
use url::Url;
pub use dom::node::TrustedNodeAddress;
/// Asynchronous messages that script can send to layout.
pub enum Msg {
/// Adds the given stylesheet to the document.
- AddStylesheet(Stylesheet, MediaQueryList),
-
- /// Adds the given stylesheet to the document.
- LoadStylesheet(Url, MediaQueryList, PendingAsyncLoad, Box<StylesheetLoadResponder + Send>),
-
- /// Adds a @viewport rule (translated from a <META name="viewport"> element) to the document.
- AddMetaViewport(ViewportRule),
+ AddStylesheet(Arc<Stylesheet>),
/// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
SetQuirksMode,
@@ -175,6 +167,10 @@ pub struct ScriptReflow {
pub reflow_info: Reflow,
/// The document node.
pub document: TrustedNodeAddress,
+ /// The document's list of stylesheets.
+ pub document_stylesheets: Vec<Arc<Stylesheet>>,
+ /// Whether the document's stylesheets have changed since the last script reflow.
+ pub stylesheets_changed: bool,
/// The current window size.
pub window_size: WindowSizeData,
/// The channel that we send a notification to.
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index dda6faaa85b..c343dd677f6 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -20,7 +20,7 @@
use devtools;
use devtools_traits::ScriptToDevtoolsControlMsg;
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
-use document_loader::{DocumentLoader, LoadType};
+use document_loader::DocumentLoader;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::conversions::{FromJSValConvertible, StringificationBehavior};
@@ -1001,10 +1001,6 @@ impl ScriptTask {
self.handle_tick_all_animations(pipeline_id),
ConstellationControlMsg::WebFontLoaded(pipeline_id) =>
self.handle_web_font_loaded(pipeline_id),
- ConstellationControlMsg::StylesheetLoadComplete(id, url, responder) => {
- responder.respond();
- self.handle_resource_loaded(id, LoadType::Stylesheet(url));
- }
ConstellationControlMsg::GetCurrentState(sender, pipeline_id) => {
let state = self.handle_get_current_state(pipeline_id);
sender.send(state).unwrap();
@@ -1153,13 +1149,6 @@ impl ScriptTask {
panic!("Page rect message sent to nonexistent pipeline");
}
- /// Handle a request to load a page in a new child frame of an existing page.
- fn handle_resource_loaded(&self, pipeline: PipelineId, load: LoadType) {
- let page = get_page(&self.root_page(), pipeline);
- let doc = page.document();
- doc.finish_load(load);
- }
-
/// Get the current state of a given pipeline.
fn handle_get_current_state(&self, pipeline_id: PipelineId) -> ScriptState {
// Check if the main page load is still pending