diff options
-rw-r--r-- | components/script/dom/htmllinkelement.rs | 21 | ||||
-rw-r--r-- | components/script/stylesheet_loader.rs | 48 |
2 files changed, 49 insertions, 20 deletions
diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 7b26fb8bbee..fd41329a9a9 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -37,6 +37,15 @@ use stylesheet_loader::{StylesheetLoader, StylesheetContextSource, StylesheetOwn unsafe_no_jsmanaged_fields!(Stylesheet); +#[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)] +pub struct RequestGenerationId(u32); + +impl RequestGenerationId { + fn increment(self) -> RequestGenerationId { + RequestGenerationId(self.0 + 1) + } +} + #[dom_struct] pub struct HTMLLinkElement { htmlelement: HTMLElement, @@ -52,6 +61,8 @@ pub struct HTMLLinkElement { pending_loads: Cell<u32>, /// Whether any of the loads have failed. any_failed_load: Cell<bool>, + /// A monotonically increasing counter that keeps track of which stylesheet to apply. + request_generation_id: Cell<RequestGenerationId>, } impl HTMLLinkElement { @@ -65,6 +76,7 @@ impl HTMLLinkElement { cssom_stylesheet: MutNullableJS::new(None), pending_loads: Cell::new(0), any_failed_load: Cell::new(false), + request_generation_id: Cell::new(RequestGenerationId(0)), } } @@ -78,12 +90,15 @@ impl HTMLLinkElement { HTMLLinkElementBinding::Wrap) } + pub fn get_request_generation_id(&self) -> RequestGenerationId { + self.request_generation_id.get() + } + pub fn set_stylesheet(&self, s: Arc<Stylesheet>) { - assert!(self.stylesheet.borrow().is_none()); + assert!(self.stylesheet.borrow().is_none()); // Useful for catching timing issues. *self.stylesheet.borrow_mut() = Some(s); } - pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> { self.stylesheet.borrow().clone() } @@ -260,6 +275,8 @@ impl HTMLLinkElement { None => "", }; + self.request_generation_id.set(self.request_generation_id.get().increment()); + // TODO: #8085 - Don't load external stylesheets if the node's mq // doesn't match. let loader = StylesheetLoader::for_element(self.upcast()); diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 8e5481df8aa..cdc93c9808b 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -10,7 +10,7 @@ use dom::document::Document; use dom::element::Element; use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; -use dom::htmllinkelement::HTMLLinkElement; +use dom::htmllinkelement::{RequestGenerationId, HTMLLinkElement}; use dom::node::{document_from_node, window_from_node}; use encoding::EncodingRef; use encoding::all::UTF_8; @@ -85,6 +85,9 @@ pub struct StylesheetContext { /// The node document for elem when the load was initiated. document: Trusted<Document>, origin_clean: bool, + /// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet. + /// This is ignored for `HTMLStyleElement` and imports. + request_generation_id: Option<RequestGenerationId>, } impl PreInvoke for StylesheetContext {} @@ -143,24 +146,30 @@ impl FetchResponseListener for StylesheetContext { let loader = StylesheetLoader::for_element(&elem); match self.source { StylesheetContextSource::LinkElement { ref mut media, .. } => { - let sheet = - Arc::new(Stylesheet::from_bytes(&data, final_url, - protocol_encoding_label, - Some(environment_encoding), - Origin::Author, - media.take().unwrap(), - Some(&loader), - win.css_error_reporter(), - ParserContextExtraData::default())); - if elem.downcast::<HTMLLinkElement>().unwrap().is_alternate() { - sheet.set_disabled(true); + let link = elem.downcast::<HTMLLinkElement>().unwrap(); + // We must first check whether the generations of the context and the element match up, + // else we risk applying the wrong stylesheet when responses come out-of-order. + let is_stylesheet_load_applicable = + self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id()); + if is_stylesheet_load_applicable { + let sheet = + Arc::new(Stylesheet::from_bytes(&data, final_url, + protocol_encoding_label, + Some(environment_encoding), + Origin::Author, + media.take().unwrap(), + Some(&loader), + win.css_error_reporter(), + ParserContextExtraData::default())); + + if link.is_alternate() { + sheet.set_disabled(true); + } + + link.set_stylesheet(sheet.clone()); + + win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap(); } - elem.downcast::<HTMLLinkElement>() - .unwrap() - .set_stylesheet(sheet.clone()); - - let win = window_from_node(&*elem); - win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap(); } StylesheetContextSource::Import(ref import) => { let import = import.read(); @@ -215,6 +224,8 @@ impl<'a> StylesheetLoader<'a> { integrity_metadata: String) { let url = source.url(); let document = document_from_node(self.elem); + let gen = self.elem.downcast::<HTMLLinkElement>() + .map(HTMLLinkElement::get_request_generation_id); let context = Arc::new(Mutex::new(StylesheetContext { elem: Trusted::new(&*self.elem), source: source, @@ -222,6 +233,7 @@ impl<'a> StylesheetLoader<'a> { data: vec![], document: Trusted::new(&*document), origin_clean: true, + request_generation_id: gen, })); let (action_sender, action_receiver) = ipc::channel().unwrap(); |