aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/layout_task.rs97
-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
-rw-r--r--components/script_traits/lib.rs10
-rw-r--r--components/style/selector_matching.rs222
-rw-r--r--components/style/stylesheets.rs19
-rw-r--r--components/style_traits/viewport.rs2
-rw-r--r--tests/unit/style/stylesheets.rs1
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/cascade-import-dynamic-control.htm.ini3
15 files changed, 387 insertions, 281 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 46f889de0a3..9e0a77c8bfc 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -16,8 +16,6 @@ use context::{SharedLayoutContext, heap_size_of_local_context};
use cssparser::ToCss;
use data::LayoutDataWrapper;
use display_list_builder::ToGfxColor;
-use encoding::EncodingRef;
-use encoding::all::UTF_8;
use euclid::Matrix4;
use euclid::point::Point2D;
use euclid::rect::Rect;
@@ -42,7 +40,6 @@ use msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheResult, ImageCacheTask};
-use net_traits::{PendingAsyncLoad, load_bytes_iter};
use opaque_node::OpaqueNodeMethods;
use parallel::{self, WorkQueueData};
use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
@@ -56,7 +53,6 @@ use script::layout_interface::Animation;
use script::layout_interface::{LayoutChan, LayoutRPC, OffsetParentResponse};
use script::layout_interface::{Msg, NewLayoutTaskInfo, Reflow, ReflowGoal, ReflowQueryType};
use script::layout_interface::{ScriptLayoutChan, ScriptReflow, TrustedNodeAddress};
-use script_traits::StylesheetLoadResponder;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, OpaqueScriptLayoutChannel};
use selectors::parser::PseudoElement;
use sequential;
@@ -72,13 +68,12 @@ use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex, MutexGuard};
use string_cache::Atom;
use style::computed_values::{self, filter, mix_blend_mode};
-use style::media_queries::{Device, MediaQueryList, MediaType};
+use style::media_queries::{Device, MediaType};
use style::properties::longhands::{display, position};
use style::properties::style_structs;
use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS};
-use style::stylesheets::{CSSRule, CSSRuleIteratorExt, Origin, Stylesheet};
+use style::stylesheets::{CSSRuleIteratorExt, Stylesheet};
use style::values::AuExtensionMethods;
-use style::viewport::ViewportRule;
use url::Url;
use util::geometry::{MAX_RECT, ZERO_POINT};
use util::ipc::OptionalIpcSender;
@@ -576,20 +571,10 @@ impl LayoutTask {
LayoutTaskData>>)
-> bool {
match request {
- Msg::AddStylesheet(sheet, mq) => {
- self.handle_add_stylesheet(sheet, mq, possibly_locked_rw_data)
- }
- Msg::LoadStylesheet(url, mq, pending, link_element) => {
- self.handle_load_stylesheet(url,
- mq,
- pending,
- link_element,
- possibly_locked_rw_data)
+ Msg::AddStylesheet(style_info) => {
+ self.handle_add_stylesheet(style_info, possibly_locked_rw_data)
}
Msg::SetQuirksMode => self.handle_set_quirks_mode(possibly_locked_rw_data),
- Msg::AddMetaViewport(translated_rule) => {
- self.handle_add_meta_viewport(translated_rule, possibly_locked_rw_data)
- }
Msg::GetRPC(response_chan) => {
response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
Box<LayoutRPC + Send>).unwrap();
@@ -745,75 +730,31 @@ impl LayoutTask {
response_port.recv().unwrap()
}
- fn handle_load_stylesheet<'a>(&'a self,
- url: Url,
- mq: MediaQueryList,
- pending: PendingAsyncLoad,
- responder: Box<StylesheetLoadResponder + Send>,
- possibly_locked_rw_data:
- &mut Option<MutexGuard<'a, LayoutTaskData>>) {
- // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
- let environment_encoding = UTF_8 as EncodingRef;
-
- // TODO we don't really even need to load this if mq does not match
- let (metadata, iter) = load_bytes_iter(pending);
- let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s);
- let final_url = metadata.final_url;
-
- let sheet = Stylesheet::from_bytes_iter(iter,
- final_url,
- protocol_encoding_label,
- Some(environment_encoding),
- Origin::Author);
-
- //TODO: mark critical subresources as blocking load as well (#5974)
- self.script_chan.send(ConstellationControlMsg::StylesheetLoadComplete(self.id,
- url,
- responder)).unwrap();
-
- self.handle_add_stylesheet(sheet, mq, possibly_locked_rw_data);
- }
-
fn handle_add_stylesheet<'a>(&'a self,
- sheet: Stylesheet,
- mq: MediaQueryList,
+ stylesheet: Arc<Stylesheet>,
possibly_locked_rw_data:
&mut Option<MutexGuard<'a, LayoutTaskData>>) {
// Find all font-face rules and notify the font cache of them.
- // GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
+ // GWTODO: Need to handle unloading web fonts.
- let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
- if mq.evaluate(&rw_data.stylist.device) {
- add_font_face_rules(&sheet,
+ let rw_data = self.lock_rw_data(possibly_locked_rw_data);
+ if stylesheet.is_effective_for_device(&rw_data.stylist.device) {
+ add_font_face_rules(&*stylesheet,
&rw_data.stylist.device,
&self.font_cache_task,
&self.font_cache_sender,
&rw_data.outstanding_web_fonts);
- rw_data.stylist.add_stylesheet(sheet);
}
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
}
- fn handle_add_meta_viewport<'a>(&'a self,
- translated_rule: ViewportRule,
- possibly_locked_rw_data:
- &mut Option<MutexGuard<'a, LayoutTaskData>>)
- {
- let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
- rw_data.stylist.add_stylesheet(Stylesheet {
- rules: vec![CSSRule::Viewport(translated_rule)],
- origin: Origin::Author
- });
- LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
- }
-
- /// Sets quirks mode for the document, causing the quirks mode stylesheet to be loaded.
+ /// Sets quirks mode for the document, causing the quirks mode stylesheet to be used.
fn handle_set_quirks_mode<'a>(&'a self,
possibly_locked_rw_data:
&mut Option<MutexGuard<'a, LayoutTaskData>>) {
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
- rw_data.stylist.add_quirks_mode_stylesheet();
+ rw_data.stylist.set_quirks_mode(true);
LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data);
}
@@ -1077,7 +1018,7 @@ impl LayoutTask {
flow_ref::deref_mut(layout_root));
let root_size = {
let root_flow = flow::base(&**layout_root);
- if rw_data.stylist.get_viewport_constraints().is_some() {
+ if rw_data.stylist.viewport_constraints().is_some() {
root_flow.position.size.to_physical(root_flow.writing_mode)
} else {
root_flow.overflow.size
@@ -1153,6 +1094,9 @@ impl LayoutTask {
}
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
+ let stylesheets: Vec<&Stylesheet> = data.document_stylesheets.iter().map(|entry| &**entry)
+ .collect();
+ let stylesheets_changed = data.stylesheets_changed;
let initial_viewport = data.window_size.initial_viewport;
let old_viewport_size = rw_data.viewport_size;
@@ -1162,9 +1106,9 @@ impl LayoutTask {
// Calculate the actual viewport as per DEVICE-ADAPT § 6
let device = Device::new(MediaType::Screen, initial_viewport);
- rw_data.stylist.set_device(device);
+ rw_data.stylist.set_device(device, &stylesheets);
- let constraints = rw_data.stylist.get_viewport_constraints();
+ let constraints = rw_data.stylist.viewport_constraints().clone();
rw_data.viewport_size = match constraints {
Some(ref constraints) => {
debug!("Viewport constraints: {:?}", constraints);
@@ -1180,9 +1124,6 @@ impl LayoutTask {
let viewport_size_changed = rw_data.viewport_size != old_viewport_size;
if viewport_size_changed {
if let Some(constraints) = constraints {
- let device = Device::new(MediaType::Screen, constraints.size);
- rw_data.stylist.set_device(device);
-
// let the constellation know about the viewport constraints
let ConstellationChan(ref constellation_chan) = rw_data.constellation_chan;
constellation_chan.send(ConstellationMsg::ViewportConstrained(
@@ -1191,7 +1132,7 @@ impl LayoutTask {
}
// If the entire flow tree is invalid, then it will be reflowed anyhow.
- let needs_dirtying = rw_data.stylist.update();
+ let needs_dirtying = rw_data.stylist.update(&stylesheets, stylesheets_changed);
let needs_reflow = viewport_size_changed && !needs_dirtying;
unsafe {
if needs_dirtying {
@@ -1221,7 +1162,7 @@ impl LayoutTask {
&self.url,
data.reflow_info.goal);
- if node.is_dirty() || node.has_dirty_descendants() || rw_data.stylist.is_dirty() {
+ if node.is_dirty() || node.has_dirty_descendants() {
// Recalculate CSS styles and rebuild flows and fragments.
profile(time::ProfilerCategory::LayoutStyleRecalc,
self.profiler_metadata(),
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
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 827a729e236..f702884db01 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -41,7 +41,6 @@ use net_traits::storage_task::StorageTask;
use profile_traits::mem;
use std::any::Any;
use std::sync::mpsc::{Receiver, Sender};
-use url::Url;
use util::mem::HeapSizeOf;
/// The address of a node. Layout sends these back. They must be validated via
@@ -90,13 +89,6 @@ pub struct NewLayoutInfo {
pub layout_shutdown_chan: Sender<()>,
}
-/// `StylesheetLoadResponder` is used to notify a responder that a style sheet
-/// has loaded.
-pub trait StylesheetLoadResponder {
- /// Respond to a loaded style sheet.
- fn respond(self: Box<Self>);
-}
-
/// Used to determine if a script has any pending asynchronous activity.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ScriptState {
@@ -141,8 +133,6 @@ pub enum ConstellationControlMsg {
/// Notifies the script task that a new Web font has been loaded, and thus the page should be
/// reflowed.
WebFontLoaded(PipelineId),
- /// Notifies script that a stylesheet has finished loading.
- StylesheetLoadComplete(PipelineId, Url, Box<StylesheetLoadResponder + Send>),
/// Get the current state of the script task for a given pipeline.
GetCurrentState(Sender<ScriptState>, PipelineId),
}
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs
index 5c66a05aa1d..fe7d4621821 100644
--- a/components/style/selector_matching.rs
+++ b/components/style/selector_matching.rs
@@ -56,19 +56,37 @@ lazy_static! {
};
}
-pub struct Stylist {
- // List of stylesheets (including all media rules)
- stylesheets: Vec<Stylesheet>,
+lazy_static! {
+ pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet = {
+ match read_resource_file(&["quirks-mode.css"]) {
+ Ok(res) => {
+ Stylesheet::from_bytes(
+ &res,
+ Url::parse("chrome:///quirks-mode.css").unwrap(),
+ None,
+ None,
+ Origin::UserAgent)
+ },
+ Err(..) => {
+ error!("Stylist failed to load 'quirks-mode.css'!");
+ process::exit(1);
+ }
+ }
+ };
+}
+pub struct Stylist {
// Device that the stylist is currently evaluating against.
pub device: Device,
// Viewport constraints based on the current device.
viewport_constraints: Option<ViewportConstraints>,
- // If true, a stylesheet has been added or the device has
- // changed, and the stylist needs to be updated.
- is_dirty: bool,
+ // If true, the quirks-mode stylesheet is applied.
+ quirks_mode: bool,
+
+ // If true, the device has changed, and the stylist needs to be updated.
+ is_device_dirty: bool,
// The current selector maps, after evaluating media
// rules against the current device.
@@ -85,10 +103,10 @@ impl Stylist {
#[inline]
pub fn new(device: Device) -> Stylist {
let stylist = Stylist {
- stylesheets: vec!(),
viewport_constraints: None,
device: device,
- is_dirty: true,
+ is_device_dirty: true,
+ quirks_mode: false,
element_map: PerPseudoElementSelectorMap::new(),
before_map: PerPseudoElementSelectorMap::new(),
@@ -100,79 +118,90 @@ impl Stylist {
stylist
}
- #[inline]
- pub fn stylesheets(&self) -> &[Stylesheet] {
- &self.stylesheets
+ pub fn update(&mut self, doc_stylesheets: &[&Stylesheet],
+ stylesheets_changed: bool) -> bool {
+ if !(self.is_device_dirty || stylesheets_changed) {
+ return false;
+ }
+ self.element_map = PerPseudoElementSelectorMap::new();
+ self.before_map = PerPseudoElementSelectorMap::new();
+ self.after_map = PerPseudoElementSelectorMap::new();
+ self.rules_source_order = 0;
+ self.state_deps.clear();
+
+ for ref stylesheet in USER_OR_USER_AGENT_STYLESHEETS.iter() {
+ self.add_stylesheet(&stylesheet);
+ }
+
+ if self.quirks_mode {
+ self.add_stylesheet(&QUIRKS_MODE_STYLESHEET);
+ }
+
+ for ref stylesheet in doc_stylesheets.iter() {
+ self.add_stylesheet(stylesheet);
+ }
+
+ self.is_device_dirty = false;
+ true
}
- pub fn update(&mut self) -> bool {
- if self.is_dirty {
- self.element_map = PerPseudoElementSelectorMap::new();
- self.before_map = PerPseudoElementSelectorMap::new();
- self.after_map = PerPseudoElementSelectorMap::new();
- self.rules_source_order = 0;
- self.state_deps.clear();
-
- for stylesheet in USER_OR_USER_AGENT_STYLESHEETS.iter().chain(&self.stylesheets) {
- let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
- Origin::UserAgent => (
- &mut self.element_map.user_agent,
- &mut self.before_map.user_agent,
- &mut self.after_map.user_agent,
- ),
- Origin::Author => (
- &mut self.element_map.author,
- &mut self.before_map.author,
- &mut self.after_map.author,
- ),
- Origin::User => (
- &mut self.element_map.user,
- &mut self.before_map.user,
- &mut self.after_map.user,
- ),
- };
- let mut rules_source_order = self.rules_source_order;
-
- // Take apart the StyleRule into individual Rules and insert
- // them into the SelectorMap of that priority.
- macro_rules! append(
- ($style_rule: ident, $priority: ident) => {
- if $style_rule.declarations.$priority.len() > 0 {
- for selector in &$style_rule.selectors {
- let map = match selector.pseudo_element {
- None => &mut element_map,
- Some(PseudoElement::Before) => &mut before_map,
- Some(PseudoElement::After) => &mut after_map,
- };
- map.$priority.insert(Rule {
- selector: selector.compound_selectors.clone(),
- declarations: DeclarationBlock {
- specificity: selector.specificity,
- declarations: $style_rule.declarations.$priority.clone(),
- source_order: rules_source_order,
- },
- });
- }
- }
- };
- );
-
- for style_rule in stylesheet.effective_rules(&self.device).style() {
- append!(style_rule, normal);
- append!(style_rule, important);
- rules_source_order += 1;
- for selector in &style_rule.selectors {
- self.state_deps.note_selector(selector.compound_selectors.clone());
+ fn add_stylesheet(&mut self, stylesheet: &Stylesheet) {
+ let device = &self.device;
+ if !stylesheet.is_effective_for_device(device) {
+ return;
+ }
+ let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
+ Origin::UserAgent => (
+ &mut self.element_map.user_agent,
+ &mut self.before_map.user_agent,
+ &mut self.after_map.user_agent,
+ ),
+ Origin::Author => (
+ &mut self.element_map.author,
+ &mut self.before_map.author,
+ &mut self.after_map.author,
+ ),
+ Origin::User => (
+ &mut self.element_map.user,
+ &mut self.before_map.user,
+ &mut self.after_map.user,
+ ),
+ };
+ let mut rules_source_order = self.rules_source_order;
+
+ // Take apart the StyleRule into individual Rules and insert
+ // them into the SelectorMap of that priority.
+ macro_rules! append(
+ ($style_rule: ident, $priority: ident) => {
+ if $style_rule.declarations.$priority.len() > 0 {
+ for selector in &$style_rule.selectors {
+ let map = match selector.pseudo_element {
+ None => &mut element_map,
+ Some(PseudoElement::Before) => &mut before_map,
+ Some(PseudoElement::After) => &mut after_map,
+ };
+ map.$priority.insert(Rule {
+ selector: selector.compound_selectors.clone(),
+ declarations: DeclarationBlock {
+ specificity: selector.specificity,
+ declarations: $style_rule.declarations.$priority.clone(),
+ source_order: rules_source_order,
+ },
+ });
}
}
- self.rules_source_order = rules_source_order;
+ };
+ );
+
+ for style_rule in stylesheet.effective_rules(&self.device).style() {
+ append!(style_rule, normal);
+ append!(style_rule, important);
+ rules_source_order += 1;
+ for selector in &style_rule.selectors {
+ self.state_deps.note_selector(selector.compound_selectors.clone());
}
-
- self.is_dirty = false;
- return true;
}
-
- false
+ self.rules_source_order = rules_source_order;
}
pub fn restyle_hint_for_state_change<E>(&self, element: &E,
@@ -183,8 +212,8 @@ impl Stylist {
self.state_deps.compute_hint(element, current_state, state_change)
}
- pub fn set_device(&mut self, mut device: Device) {
- let cascaded_rule = self.stylesheets.iter()
+ pub fn set_device(&mut self, mut device: Device, stylesheets: &[&Stylesheet]) {
+ let cascaded_rule = stylesheets.iter()
.flat_map(|s| s.effective_rules(&self.device).viewport())
.cascade();
@@ -192,41 +221,20 @@ impl Stylist {
if let Some(ref constraints) = self.viewport_constraints {
device = Device::new(MediaType::Screen, constraints.size);
}
- let is_dirty = self.is_dirty || self.stylesheets.iter()
+ let is_device_dirty = self.is_device_dirty || stylesheets.iter()
.flat_map(|stylesheet| stylesheet.rules().media())
.any(|media_rule| media_rule.evaluate(&self.device) != media_rule.evaluate(&device));
self.device = device;
- self.is_dirty |= is_dirty;
+ self.is_device_dirty |= is_device_dirty;
}
- pub fn get_viewport_constraints(&self) -> Option<ViewportConstraints> {
- match self.viewport_constraints {
- Some(ref constraints) => Some(constraints.clone()),
- None => None
- }
- }
-
- pub fn add_quirks_mode_stylesheet(&mut self) {
- match read_resource_file(&["quirks-mode.css"]) {
- Ok(res) => {
- self.add_stylesheet(Stylesheet::from_bytes(
- &res,
- Url::parse("chrome:///quirks-mode.css").unwrap(),
- None,
- None,
- Origin::UserAgent));
- }
- Err(..) => {
- error!("Stylist::add_quirks_mode_stylesheet() failed at loading 'quirks-mode.css'!");
- process::exit(1);
- }
- }
+ pub fn viewport_constraints(&self) -> &Option<ViewportConstraints> {
+ &self.viewport_constraints
}
- pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
- self.stylesheets.push(stylesheet);
- self.is_dirty = true;
+ pub fn set_quirks_mode(&mut self, enabled: bool) {
+ self.quirks_mode = enabled;
}
/// Returns the applicable CSS declarations for the given element. This corresponds to
@@ -245,7 +253,7 @@ impl Stylist {
-> bool
where E: Element + TElementAttributes,
V: VecLike<DeclarationBlock> {
- assert!(!self.is_dirty);
+ assert!(!self.is_device_dirty);
assert!(style_attribute.is_none() || pseudo_element.is_none(),
"Style attributes do not apply to pseudo-elements");
@@ -312,8 +320,8 @@ impl Stylist {
shareable
}
- pub fn is_dirty(&self) -> bool {
- self.is_dirty
+ pub fn is_device_dirty(&self) -> bool {
+ self.is_device_dirty
}
}
diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs
index 0b1decedc31..00e9def4900 100644
--- a/components/style/stylesheets.rs
+++ b/components/style/stylesheets.rs
@@ -41,6 +41,8 @@ pub struct Stylesheet {
/// List of rules in the order they were found (important for
/// cascading order)
pub rules: Vec<CSSRule>,
+ /// List of media associated with the Stylesheet, if any.
+ pub media: Option<MediaQueryList>,
pub origin: Origin,
}
@@ -132,6 +134,23 @@ impl Stylesheet {
Stylesheet {
origin: origin,
rules: rules,
+ media: None,
+ }
+ }
+
+ /// Set the MediaQueryList associated with the style-sheet.
+ pub fn set_media(&mut self, media: Option<MediaQueryList>) {
+ self.media = media;
+ }
+
+ /// Returns whether the style-sheet applies for the current device depending
+ /// on the associated MediaQueryList.
+ ///
+ /// Always true if no associated MediaQueryList exists.
+ pub fn is_effective_for_device(&self, device: &Device) -> bool {
+ match self.media {
+ Some(ref media) => media.evaluate(device),
+ None => true
}
}
diff --git a/components/style_traits/viewport.rs b/components/style_traits/viewport.rs
index cead903301a..ac7c1a16be6 100644
--- a/components/style_traits/viewport.rs
+++ b/components/style_traits/viewport.rs
@@ -20,7 +20,7 @@ define_css_keyword_enum!(Orientation:
"landscape" => Landscape);
-#[derive(Clone, Debug, HeapSizeOf, PartialEq, Deserialize, Serialize)]
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct ViewportConstraints {
pub size: TypedSize2D<ViewportPx, f32>,
diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs
index 6eb9cde4402..d6a9c6d30ce 100644
--- a/tests/unit/style/stylesheets.rs
+++ b/tests/unit/style/stylesheets.rs
@@ -25,6 +25,7 @@ fn test_parse_stylesheet() {
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent);
assert_eq!(stylesheet, Stylesheet {
origin: Origin::UserAgent,
+ media: None,
rules: vec![
CSSRule::Namespace(None, ns!(HTML)),
CSSRule::Style(StyleRule {
diff --git a/tests/wpt/metadata-css/css21_dev/html4/cascade-import-dynamic-control.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/cascade-import-dynamic-control.htm.ini
deleted file mode 100644
index f0a3cbaf277..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/cascade-import-dynamic-control.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cascade-import-dynamic-control.htm]
- type: reftest
- expected: FAIL