Auto merge of #14190 - Manishearth:cssom, r=SimonSapin

Immutable CSSOM

This PR is intended to add basic support for all CSSOM interfaces, with the ability to index `document.styleSheets` and css rule lists, and serializing individual css rules. Handling individual interface methods for CSSRule subclasses can probably be done with easy/medium bugs.

Mutation safety isn't dealt with here; if the css rule list is mutated the CSSOM will be in an inconsistent state. I intend to deal with this via zero sized tokens, see https://groups.google.com/forum/#!topic/mozilla.dev.servo/AnxJoVmtMXQ .  I'll handle that when I start making the CSSOM mutable. (Getting the immutable bit landed first opens this up for easy bugs)

This doesn't really change style aside from adding an extra arc in the CSS rule list as discussed in the linked thread. So far this same design can be used by stylo as well when the time comes.

f? @SimonSapin @emilio

cc @upsuper

part of #11420
Todo:

 - [x] Stubs for rest of the CSSRule subclasses
 - [x] <s>ToCSS impls for CSSRules.</s> May make into easy bugs and stub out in this PR https://github.com/servo/servo/issues/14195
 - [x] Cache CSSStyleSheet on the relevant node

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14190)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-11-16 15:05:59 -06:00 committed by GitHub
commit afc60bee28
57 changed files with 915 additions and 209 deletions

View file

@ -0,0 +1,50 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSFontFaceRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::font_face::FontFaceRule;
#[dom_struct]
pub struct CSSFontFaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
fontfacerule: Arc<RwLock<FontFaceRule>>,
}
impl CSSFontFaceRule {
fn new_inherited(parent: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>) -> CSSFontFaceRule {
CSSFontFaceRule {
cssrule: CSSRule::new_inherited(parent),
fontfacerule: fontfacerule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> {
reflect_dom_object(box CSSFontFaceRule::new_inherited(parent, fontfacerule),
window,
CSSFontFaceRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSFontFaceRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::FONT_FACE_RULE
}
fn get_css(&self) -> DOMString {
// self.fontfacerule.read().to_css_string().into()
"".into()
}
}

View file

@ -0,0 +1,30 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::cssrule::CSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
#[dom_struct]
pub struct CSSGroupingRule {
cssrule: CSSRule,
}
impl CSSGroupingRule {
pub fn new_inherited(parent: &CSSStyleSheet) -> CSSGroupingRule {
CSSGroupingRule {
cssrule: CSSRule::new_inherited(parent),
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSGroupingRule> {
reflect_dom_object(box CSSGroupingRule::new_inherited(parent),
window,
CSSGroupingRuleBinding::Wrap)
}
}

View file

@ -0,0 +1,50 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::KeyframesRule;
#[dom_struct]
pub struct CSSKeyframesRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
keyframesrule: Arc<RwLock<KeyframesRule>>,
}
impl CSSKeyframesRule {
fn new_inherited(parent: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>) -> CSSKeyframesRule {
CSSKeyframesRule {
cssrule: CSSRule::new_inherited(parent),
keyframesrule: keyframesrule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> {
reflect_dom_object(box CSSKeyframesRule::new_inherited(parent, keyframesrule),
window,
CSSKeyframesRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSKeyframesRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::KEYFRAMES_RULE
}
fn get_css(&self) -> DOMString {
// self.keyframesrule.read().to_css_string().into()
"".into()
}
}

View file

@ -0,0 +1,51 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSMediaRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssgroupingrule::CSSGroupingRule;
use dom::cssrule::SpecificCSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::MediaRule;
#[dom_struct]
pub struct CSSMediaRule {
cssrule: CSSGroupingRule,
#[ignore_heap_size_of = "Arc"]
mediarule: Arc<RwLock<MediaRule>>,
}
impl CSSMediaRule {
fn new_inherited(parent: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>) -> CSSMediaRule {
CSSMediaRule {
cssrule: CSSGroupingRule::new_inherited(parent),
mediarule: mediarule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> {
reflect_dom_object(box CSSMediaRule::new_inherited(parent, mediarule),
window,
CSSMediaRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSMediaRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::MEDIA_RULE
}
fn get_css(&self) -> DOMString {
// self.mediarule.read().to_css_string().into()
"".into()
}
}

View file

@ -0,0 +1,50 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::NamespaceRule;
#[dom_struct]
pub struct CSSNamespaceRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
namespacerule: Arc<RwLock<NamespaceRule>>,
}
impl CSSNamespaceRule {
fn new_inherited(parent: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>) -> CSSNamespaceRule {
CSSNamespaceRule {
cssrule: CSSRule::new_inherited(parent),
namespacerule: namespacerule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> {
reflect_dom_object(box CSSNamespaceRule::new_inherited(parent, namespacerule),
window,
CSSNamespaceRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSNamespaceRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::NAMESPACE_RULE
}
fn get_css(&self) -> DOMString {
// self.namespacerule.read().to_css_string().into()
"".into()
}
}

View file

@ -0,0 +1,103 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSRuleBinding;
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssfontfacerule::CSSFontFaceRule;
use dom::csskeyframesrule::CSSKeyframesRule;
use dom::cssmediarule::CSSMediaRule;
use dom::cssnamespacerule::CSSNamespaceRule;
use dom::cssstylerule::CSSStyleRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::cssviewportrule::CSSViewportRule;
use dom::window::Window;
use style::stylesheets::CssRule as StyleCssRule;
#[dom_struct]
pub struct CSSRule {
reflector_: Reflector,
parent: MutNullableHeap<JS<CSSStyleSheet>>,
}
impl CSSRule {
#[allow(unrooted_must_root)]
pub fn new_inherited(parent: &CSSStyleSheet) -> CSSRule {
CSSRule {
reflector_: Reflector::new(),
parent: MutNullableHeap::new(Some(parent)),
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSRule> {
reflect_dom_object(box CSSRule::new_inherited(parent),
window,
CSSRuleBinding::Wrap)
}
pub fn as_specific(&self) -> &SpecificCSSRule {
if let Some(rule) = self.downcast::<CSSStyleRule>() {
rule as &SpecificCSSRule
} else if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
rule as &SpecificCSSRule
} else if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
rule as &SpecificCSSRule
} else if let Some(rule) = self.downcast::<CSSMediaRule>() {
rule as &SpecificCSSRule
} else if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
rule as &SpecificCSSRule
} else if let Some(rule) = self.downcast::<CSSViewportRule>() {
rule as &SpecificCSSRule
} else {
unreachable!()
}
}
// Given a StyleCssRule, create a new instance of a derived class of
// CSSRule based on which rule it is
pub fn new_specific(window: &Window, parent: &CSSStyleSheet,
rule: StyleCssRule) -> Root<CSSRule> {
// be sure to update the match in as_specific when this is updated
match rule {
StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent, s)),
StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent, s)),
StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent, s)),
StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent, s)),
StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent, s)),
StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent, s)),
}
}
}
impl CSSRuleMethods for CSSRule {
// https://drafts.csswg.org/cssom/#dom-cssrule-type
fn Type(&self) -> u16 {
self.as_specific().ty()
}
// https://drafts.csswg.org/cssom/#dom-cssrule-parentstylesheet
fn GetParentStyleSheet(&self) -> Option<Root<CSSStyleSheet>> {
self.parent.get()
}
// https://drafts.csswg.org/cssom/#dom-cssrule-csstext
fn CssText(&self) -> DOMString {
self.as_specific().get_css()
}
// https://drafts.csswg.org/cssom/#dom-cssrule-csstext
fn SetCssText(&self, _: DOMString) {
// do nothing
}
}
pub trait SpecificCSSRule {
fn ty(&self) -> u16;
fn get_css(&self) -> DOMString;
}

View file

@ -0,0 +1,67 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSRuleListBinding;
use dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::cssrule::CSSRule;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use style::stylesheets::CssRules;
no_jsmanaged_fields!(CssRules);
#[dom_struct]
pub struct CSSRuleList {
reflector_: Reflector,
sheet: JS<CSSStyleSheet>,
#[ignore_heap_size_of = "Arc"]
rules: CssRules,
dom_rules: Vec<MutNullableHeap<JS<CSSRule>>>
}
impl CSSRuleList {
#[allow(unrooted_must_root)]
pub fn new_inherited(sheet: &CSSStyleSheet, rules: CssRules) -> CSSRuleList {
let dom_rules = rules.0.read().iter().map(|_| MutNullableHeap::new(None)).collect();
CSSRuleList {
reflector_: Reflector::new(),
sheet: JS::from_ref(sheet),
rules: rules,
dom_rules: dom_rules,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, sheet: &CSSStyleSheet, rules: CssRules) -> Root<CSSRuleList> {
reflect_dom_object(box CSSRuleList::new_inherited(sheet, rules),
window,
CSSRuleListBinding::Wrap)
}
}
impl CSSRuleListMethods for CSSRuleList {
// https://drafts.csswg.org/cssom/#ref-for-dom-cssrulelist-item-1
fn Item(&self, idx: u32) -> Option<Root<CSSRule>> {
self.dom_rules.get(idx as usize).map(|rule| {
rule.or_init(|| {
CSSRule::new_specific(self.global().as_window(),
&self.sheet,
self.rules.0.read()[idx as usize].clone())
})
})
}
// https://drafts.csswg.org/cssom/#dom-cssrulelist-length
fn Length(&self) -> u32 {
self.dom_rules.len() as u32
}
// check-tidy: no specs after this line
fn IndexedGetter(&self, index: u32) -> Option<Root<CSSRule>> {
self.Item(index)
}
}

View file

@ -0,0 +1,50 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSStyleRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::stylesheets::StyleRule;
use style_traits::ToCss;
#[dom_struct]
pub struct CSSStyleRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
stylerule: Arc<RwLock<StyleRule>>,
}
impl CSSStyleRule {
fn new_inherited(parent: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>) -> CSSStyleRule {
CSSStyleRule {
cssrule: CSSRule::new_inherited(parent),
stylerule: stylerule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> {
reflect_dom_object(box CSSStyleRule::new_inherited(parent, stylerule),
window,
CSSStyleRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSStyleRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::STYLE_RULE
}
fn get_css(&self) -> DOMString {
self.stylerule.read().to_css_string().into()
}
}

View file

@ -0,0 +1,51 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSStyleSheetBinding;
use dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods;
use dom::bindings::js::{JS, Root, MutNullableHeap};
use dom::bindings::reflector::{reflect_dom_object, Reflectable};
use dom::bindings::str::DOMString;
use dom::cssrulelist::CSSRuleList;
use dom::stylesheet::StyleSheet;
use dom::window::Window;
use std::sync::Arc;
use style::stylesheets::Stylesheet as StyleStyleSheet;
#[dom_struct]
pub struct CSSStyleSheet {
stylesheet: StyleSheet,
rulelist: MutNullableHeap<JS<CSSRuleList>>,
#[ignore_heap_size_of = "Arc"]
style_stylesheet: Arc<StyleStyleSheet>,
}
impl CSSStyleSheet {
fn new_inherited(type_: DOMString, href: Option<DOMString>,
title: Option<DOMString>, stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
CSSStyleSheet {
stylesheet: StyleSheet::new_inherited(type_, href, title),
rulelist: MutNullableHeap::new(None),
style_stylesheet: stylesheet,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, type_: DOMString,
href: Option<DOMString>,
title: Option<DOMString>,
stylesheet: Arc<StyleStyleSheet>) -> Root<CSSStyleSheet> {
reflect_dom_object(box CSSStyleSheet::new_inherited(type_, href, title, stylesheet),
window,
CSSStyleSheetBinding::Wrap)
}
}
impl CSSStyleSheetMethods for CSSStyleSheet {
// https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules
fn CssRules(&self) -> Root<CSSRuleList> {
self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), self, self.style_stylesheet.rules.clone()))
}
}

View file

@ -0,0 +1,50 @@
/* 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/. */
use dom::bindings::codegen::Bindings::CSSViewportRuleBinding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window;
use parking_lot::RwLock;
use std::sync::Arc;
use style::viewport::ViewportRule;
#[dom_struct]
pub struct CSSViewportRule {
cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"]
viewportrule: Arc<RwLock<ViewportRule>>,
}
impl CSSViewportRule {
fn new_inherited(parent: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
CSSViewportRule {
cssrule: CSSRule::new_inherited(parent),
viewportrule: viewportrule,
}
}
#[allow(unrooted_must_root)]
pub fn new(window: &Window, parent: &CSSStyleSheet,
viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> {
reflect_dom_object(box CSSViewportRule::new_inherited(parent, viewportrule),
window,
CSSViewportRuleBinding::Wrap)
}
}
impl SpecificCSSRule for CSSViewportRule {
fn ty(&self) -> u16 {
use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
CSSRuleConstants::VIEWPORT_RULE
}
fn get_css(&self) -> DOMString {
// self.viewportrule.read().to_css_string().into()
"".into()
}
}

View file

@ -59,10 +59,7 @@ use dom::htmlheadelement::HTMLHeadElement;
use dom::htmlhtmlelement::HTMLHtmlElement; use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::htmliframeelement::HTMLIFrameElement; use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlimageelement::HTMLImageElement; use dom::htmlimageelement::HTMLImageElement;
use dom::htmllinkelement::HTMLLinkElement;
use dom::htmlmetaelement::HTMLMetaElement;
use dom::htmlscriptelement::HTMLScriptElement; use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltitleelement::HTMLTitleElement; use dom::htmltitleelement::HTMLTitleElement;
use dom::keyboardevent::KeyboardEvent; use dom::keyboardevent::KeyboardEvent;
use dom::location::Location; use dom::location::Location;
@ -152,10 +149,10 @@ enum ParserBlockedByScript {
#[derive(JSTraceable, HeapSizeOf)] #[derive(JSTraceable, HeapSizeOf)]
#[must_root] #[must_root]
struct StylesheetInDocument { pub struct StylesheetInDocument {
node: JS<Node>, pub node: JS<Node>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
stylesheet: Arc<Stylesheet>, pub stylesheet: Arc<Stylesheet>,
} }
// https://dom.spec.whatwg.org/#document // https://dom.spec.whatwg.org/#document
@ -189,6 +186,7 @@ pub struct Document {
stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>, stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>,
/// Whether the list of stylesheets has changed since the last reflow was triggered. /// Whether the list of stylesheets has changed since the last reflow was triggered.
stylesheets_changed_since_reflow: Cell<bool>, stylesheets_changed_since_reflow: Cell<bool>,
stylesheet_list: MutNullableHeap<JS<StyleSheetList>>,
ready_state: Cell<DocumentReadyState>, ready_state: Cell<DocumentReadyState>,
/// Whether the DOMContentLoaded event has already been dispatched. /// Whether the DOMContentLoaded event has already been dispatched.
domcontentloaded_dispatched: Cell<bool>, domcontentloaded_dispatched: Cell<bool>,
@ -1811,6 +1809,7 @@ impl Document {
applets: Default::default(), applets: Default::default(),
stylesheets: DOMRefCell::new(None), stylesheets: DOMRefCell::new(None),
stylesheets_changed_since_reflow: Cell::new(false), stylesheets_changed_since_reflow: Cell::new(false),
stylesheet_list: MutNullableHeap::new(None),
ready_state: Cell::new(ready_state), ready_state: Cell::new(ready_state),
domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched), domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
possibly_focused: Default::default(), possibly_focused: Default::default(),
@ -1910,35 +1909,37 @@ impl Document {
self.GetDocumentElement().and_then(Root::downcast) self.GetDocumentElement().and_then(Root::downcast)
} }
/// Returns the list of stylesheets associated with nodes in the document. // Ensure that the stylesheets vector is populated
pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> { fn ensure_stylesheets(&self) {
{
let mut stylesheets = self.stylesheets.borrow_mut(); let mut stylesheets = self.stylesheets.borrow_mut();
if stylesheets.is_none() { if stylesheets.is_none() {
*stylesheets = Some(self.upcast::<Node>() *stylesheets = Some(self.upcast::<Node>()
.traverse_preorder() .traverse_preorder()
.filter_map(|node| { .filter_map(|node| {
if let Some(node) = node.downcast::<HTMLStyleElement>() {
node.get_stylesheet() node.get_stylesheet()
} else if let Some(node) = node.downcast::<HTMLLinkElement>() { .map(|stylesheet| StylesheetInDocument {
node.get_stylesheet()
} else if let Some(node) = node.downcast::<HTMLMetaElement>() {
node.get_stylesheet()
} else {
None
}.map(|stylesheet| StylesheetInDocument {
node: JS::from_ref(&*node), node: JS::from_ref(&*node),
stylesheet: stylesheet stylesheet: stylesheet,
}) })
}) })
.collect()); .collect());
}; };
} }
/// Returns the list of stylesheets associated with nodes in the document.
pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> {
self.ensure_stylesheets();
self.stylesheets.borrow().as_ref().unwrap().iter() self.stylesheets.borrow().as_ref().unwrap().iter()
.map(|s| s.stylesheet.clone()) .map(|s| s.stylesheet.clone())
.collect() .collect()
} }
pub fn with_style_sheets_in_document<F, T>(&self, mut f: F) -> T
where F: FnMut(&[StylesheetInDocument]) -> T {
self.ensure_stylesheets();
f(&self.stylesheets.borrow().as_ref().unwrap())
}
/// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document /// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
pub fn appropriate_template_contents_owner_document(&self) -> Root<Document> { pub fn appropriate_template_contents_owner_document(&self) -> Root<Document> {
self.appropriate_template_contents_owner_document.or_init(|| { self.appropriate_template_contents_owner_document.or_init(|| {
@ -2038,7 +2039,7 @@ impl Element {
impl DocumentMethods for Document { impl DocumentMethods for Document {
// https://drafts.csswg.org/cssom/#dom-document-stylesheets // https://drafts.csswg.org/cssom/#dom-document-stylesheets
fn StyleSheets(&self) -> Root<StyleSheetList> { fn StyleSheets(&self) -> Root<StyleSheetList> {
StyleSheetList::new(&self.window, JS::from_ref(&self)) self.stylesheet_list.or_init(|| StyleSheetList::new(&self.window, JS::from_ref(&self)))
} }
// https://dom.spec.whatwg.org/#dom-document-implementation // https://dom.spec.whatwg.org/#dom-document-implementation

View file

@ -14,6 +14,7 @@ use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::cssstylesheet::CSSStyleSheet;
use dom::document::Document; use dom::document::Document;
use dom::domtokenlist::DOMTokenList; use dom::domtokenlist::DOMTokenList;
use dom::element::{AttributeMutation, Element, ElementCreator}; use dom::element::{AttributeMutation, Element, ElementCreator};
@ -56,6 +57,7 @@ pub struct HTMLLinkElement {
rel_list: MutNullableHeap<JS<DOMTokenList>>, rel_list: MutNullableHeap<JS<DOMTokenList>>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>, stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
/// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts
parser_inserted: Cell<bool>, parser_inserted: Cell<bool>,
@ -69,6 +71,7 @@ impl HTMLLinkElement {
rel_list: Default::default(), rel_list: Default::default(),
parser_inserted: Cell::new(creator == ElementCreator::ParserCreated), parser_inserted: Cell::new(creator == ElementCreator::ParserCreated),
stylesheet: DOMRefCell::new(None), stylesheet: DOMRefCell::new(None),
cssom_stylesheet: MutNullableHeap::new(None),
} }
} }
@ -85,6 +88,18 @@ impl HTMLLinkElement {
pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> { pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
self.stylesheet.borrow().clone() self.stylesheet.borrow().clone()
} }
pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
self.get_stylesheet().map(|sheet| {
self.cssom_stylesheet.or_init(|| {
CSSStyleSheet::new(&window_from_node(self),
"text/css".into(),
None, // todo handle location
None, // todo handle title
sheet)
})
})
}
} }
fn get_attr(element: &Element, local_name: &LocalName) -> Option<String> { fn get_attr(element: &Element, local_name: &LocalName) -> Option<String> {

View file

@ -8,13 +8,14 @@ use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods; use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::cssstylesheet::CSSStyleSheet;
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element}; use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::htmlheadelement::HTMLHeadElement; use dom::htmlheadelement::HTMLHeadElement;
use dom::node::{Node, UnbindContext, document_from_node}; use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use html5ever_atoms::LocalName; use html5ever_atoms::LocalName;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -30,6 +31,7 @@ pub struct HTMLMetaElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>, stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
} }
impl HTMLMetaElement { impl HTMLMetaElement {
@ -39,6 +41,7 @@ impl HTMLMetaElement {
HTMLMetaElement { HTMLMetaElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document), htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
stylesheet: DOMRefCell::new(None), stylesheet: DOMRefCell::new(None),
cssom_stylesheet: MutNullableHeap::new(None),
} }
} }
@ -55,6 +58,18 @@ impl HTMLMetaElement {
self.stylesheet.borrow().clone() self.stylesheet.borrow().clone()
} }
pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
self.get_stylesheet().map(|sheet| {
self.cssom_stylesheet.or_init(|| {
CSSStyleSheet::new(&window_from_node(self),
"text/css".into(),
None, // todo handle location
None, // todo handle title
sheet)
})
})
}
fn process_attributes(&self) { fn process_attributes(&self) {
let element = self.upcast::<Element>(); let element = self.upcast::<Element>();
if let Some(name) = element.get_attribute(&ns!(), &local_name!("name")).r() { if let Some(name) = element.get_attribute(&ns!(), &local_name!("name")).r() {
@ -81,7 +96,7 @@ impl HTMLMetaElement {
if !content.is_empty() { if !content.is_empty() {
if let Some(translated_rule) = ViewportRule::from_meta(&**content) { if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
*self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet { *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))], rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))].into(),
origin: Origin::Author, origin: Origin::Author,
media: Default::default(), media: Default::default(),
// Viewport constraints are always recomputed on resize; they don't need to // Viewport constraints are always recomputed on resize; they don't need to

View file

@ -7,8 +7,9 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLStyleElementBinding; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::cssstylesheet::CSSStyleSheet;
use dom::document::Document; use dom::document::Document;
use dom::element::Element; use dom::element::Element;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
@ -26,6 +27,7 @@ pub struct HTMLStyleElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>, stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
} }
impl HTMLStyleElement { impl HTMLStyleElement {
@ -35,6 +37,7 @@ impl HTMLStyleElement {
HTMLStyleElement { HTMLStyleElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document), htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
stylesheet: DOMRefCell::new(None), stylesheet: DOMRefCell::new(None),
cssom_stylesheet: MutNullableHeap::new(None),
} }
} }
@ -77,6 +80,18 @@ impl HTMLStyleElement {
pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> { pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
self.stylesheet.borrow().clone() self.stylesheet.borrow().clone()
} }
pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
self.get_stylesheet().map(|sheet| {
self.cssom_stylesheet.or_init(|| {
CSSStyleSheet::new(&window_from_node(self),
"text/css".into(),
None, // todo handle location
None, // todo handle title
sheet)
})
})
}
} }
impl VirtualMethods for HTMLStyleElement { impl VirtualMethods for HTMLStyleElement {

View file

@ -242,7 +242,17 @@ pub mod comment;
pub mod console; pub mod console;
pub mod crypto; pub mod crypto;
pub mod css; pub mod css;
pub mod cssfontfacerule;
pub mod cssgroupingrule;
pub mod csskeyframesrule;
pub mod cssmediarule;
pub mod cssnamespacerule;
pub mod cssrule;
pub mod cssrulelist;
pub mod cssstyledeclaration; pub mod cssstyledeclaration;
pub mod cssstylerule;
pub mod cssstylesheet;
pub mod cssviewportrule;
pub mod customevent; pub mod customevent;
pub mod dedicatedworkerglobalscope; pub mod dedicatedworkerglobalscope;
pub mod document; pub mod document;

View file

@ -30,6 +30,7 @@ use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::{DOMString, USVString}; use dom::bindings::str::{DOMString, USVString};
use dom::bindings::xmlname::namespace_from_domstring; use dom::bindings::xmlname::namespace_from_domstring;
use dom::characterdata::{CharacterData, LayoutCharacterDataHelpers}; use dom::characterdata::{CharacterData, LayoutCharacterDataHelpers};
use dom::cssstylesheet::CSSStyleSheet;
use dom::document::{Document, DocumentSource, IsHTMLDocument}; use dom::document::{Document, DocumentSource, IsHTMLDocument};
use dom::documentfragment::DocumentFragment; use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType; use dom::documenttype::DocumentType;
@ -43,6 +44,9 @@ use dom::htmlelement::HTMLElement;
use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods}; use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use dom::htmllinkelement::HTMLLinkElement;
use dom::htmlmetaelement::HTMLMetaElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers}; use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
use dom::nodelist::NodeList; use dom::nodelist::NodeList;
use dom::processinginstruction::ProcessingInstruction; use dom::processinginstruction::ProcessingInstruction;
@ -76,8 +80,10 @@ use std::default::Default;
use std::iter; use std::iter;
use std::mem; use std::mem;
use std::ops::Range; use std::ops::Range;
use std::sync::Arc;
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::selector_impl::ServoSelectorImpl; use style::selector_impl::ServoSelectorImpl;
use style::stylesheets::Stylesheet;
use style::thread_state; use style::thread_state;
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
@ -901,6 +907,30 @@ impl Node {
element.upcast::<Node>().remove_self(); element.upcast::<Node>().remove_self();
Ok(()) Ok(())
} }
pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
if let Some(node) = self.downcast::<HTMLStyleElement>() {
node.get_stylesheet()
} else if let Some(node) = self.downcast::<HTMLLinkElement>() {
node.get_stylesheet()
} else if let Some(node) = self.downcast::<HTMLMetaElement>() {
node.get_stylesheet()
} else {
None
}
}
pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
if let Some(node) = self.downcast::<HTMLStyleElement>() {
node.get_cssom_stylesheet()
} else if let Some(node) = self.downcast::<HTMLLinkElement>() {
node.get_cssom_stylesheet()
} else if let Some(node) = self.downcast::<HTMLMetaElement>() {
node.get_cssom_stylesheet()
} else {
None
}
}
} }

View file

@ -20,7 +20,7 @@ pub struct StyleSheet {
impl StyleSheet { impl StyleSheet {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn new_inherited(type_: DOMString, href: Option<DOMString>, title: Option<DOMString>) -> StyleSheet { pub fn new_inherited(type_: DOMString, href: Option<DOMString>, title: Option<DOMString>) -> StyleSheet {
StyleSheet { StyleSheet {
reflector_: Reflector::new(), reflector_: Reflector::new(),
type_: type_, type_: type_,

View file

@ -35,13 +35,18 @@ impl StyleSheetList {
impl StyleSheetListMethods for StyleSheetList { impl StyleSheetListMethods for StyleSheetList {
// https://drafts.csswg.org/cssom/#dom-stylesheetlist-length // https://drafts.csswg.org/cssom/#dom-stylesheetlist-length
fn Length(&self) -> u32 { fn Length(&self) -> u32 {
self.document.stylesheets().len() as u32 self.document.with_style_sheets_in_document(|s| s.len() as u32)
} }
// https://drafts.csswg.org/cssom/#dom-stylesheetlist-item // https://drafts.csswg.org/cssom/#dom-stylesheetlist-item
fn Item(&self, _index: u32) -> Option<Root<StyleSheet>> { fn Item(&self, index: u32) -> Option<Root<StyleSheet>> {
None // XXXManishearth this doesn't handle the origin clean flag
//TODO Create a new StyleSheet object and return it // and is a cors vulnerability
self.document.with_style_sheets_in_document(|sheets| {
sheets.get(index as usize)
.and_then(|sheet| sheet.node.get_cssom_stylesheet())
.map(Root::upcast)
})
} }
// check-tidy: no specs after this line // check-tidy: no specs after this line

View file

@ -6,7 +6,7 @@
* http://dev.w3.org/csswg/cssom/#the-css-interface * http://dev.w3.org/csswg/cssom/#the-css-interface
*/ */
[Abstract, Exposed=(Window,Worker)] [Abstract, Exposed=Window]
interface CSS { interface CSS {
[Throws] [Throws]
static DOMString escape(DOMString ident); static DOMString escape(DOMString ident);

View file

@ -0,0 +1,17 @@
/* 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/. */
// https://drafts.csswg.org/css-fonts/#cssfontfacerule
[Exposed=Window]
interface CSSFontFaceRule : CSSRule {
// attribute DOMString family;
// attribute DOMString src;
// attribute DOMString style;
// attribute DOMString weight;
// attribute DOMString stretch;
// attribute DOMString unicodeRange;
// attribute DOMString variant;
// attribute DOMString featureSettings;
};

View file

@ -0,0 +1,12 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
[Exposed=Window]
interface CSSGroupingRule : CSSRule {
// [SameObject] readonly attribute CSSRuleList cssRules;
// unsigned long insertRule(DOMString rule, unsigned long index);
// void deleteRule(unsigned long index);
};

View file

@ -0,0 +1,14 @@
/* 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/. */
// https://drafts.csswg.org/css-animations/#interface-csskeyframesrule
[Exposed=Window]
interface CSSKeyframesRule : CSSRule {
// attribute DOMString name;
// readonly attribute CSSRuleList cssRules;
// void appendRule(DOMString rule);
// void deleteRule(DOMString select);
// CSSKeyframeRule? findRule(DOMString select);
};

View file

@ -0,0 +1,9 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssmediarule-interface
[Exposed=Window]
interface CSSMediaRule : CSSGroupingRule {
// [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
};

View file

@ -0,0 +1,10 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
[Exposed=Window]
interface CSSNamespaceRule : CSSRule {
// readonly attribute DOMString namespaceURI;
// readonly attribute DOMString prefix;
};

View file

@ -0,0 +1,33 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssrule-interface
[Exposed=Window]
interface CSSRule {
const unsigned short STYLE_RULE = 1;
const unsigned short CHARSET_RULE = 2; // historical
const unsigned short IMPORT_RULE = 3;
const unsigned short MEDIA_RULE = 4;
const unsigned short FONT_FACE_RULE = 5;
const unsigned short PAGE_RULE = 6;
const unsigned short MARGIN_RULE = 9;
const unsigned short NAMESPACE_RULE = 10;
readonly attribute unsigned short type;
attribute DOMString cssText;
// readonly attribute CSSRule? parentRule;
readonly attribute CSSStyleSheet? parentStyleSheet;
};
// https://drafts.csswg.org/css-animations/#interface-cssrule-idl
partial interface CSSRule {
const unsigned short KEYFRAMES_RULE = 7;
const unsigned short KEYFRAME_RULE = 8;
};
// https://drafts.csswg.org/css-device-adapt/#css-rule-interface
partial interface CSSRule {
const unsigned short VIEWPORT_RULE = 15;
};

View file

@ -0,0 +1,11 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#cssrulelist
// [LegacyArrayClass]
[Exposed=Window]
interface CSSRuleList {
getter CSSRule? item(unsigned long index);
readonly attribute unsigned long length;
};

View file

@ -8,7 +8,7 @@
* Copyright © 2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. * Copyright © 2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
*/ */
[Exposed=(Window,Worker)] [Exposed=(Window, Worker)]
interface CSSStyleDeclaration { interface CSSStyleDeclaration {
[SetterThrows] [SetterThrows]
attribute DOMString cssText; attribute DOMString cssText;

View file

@ -0,0 +1,10 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssstylerule-interface
[Exposed=Window]
interface CSSStyleRule : CSSRule {
// attribute DOMString selectorText;
// [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
};

View file

@ -0,0 +1,12 @@
/* 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/. */
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
[Exposed=Window]
interface CSSStyleSheet : StyleSheet {
// readonly attribute CSSRule? ownerRule;
[SameObject] readonly attribute CSSRuleList cssRules;
// unsigned long insertRule(DOMString rule, unsigned long index);
// void deleteRule(unsigned long index);
};

View file

@ -0,0 +1,9 @@
/* 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/. */
// https://drafts.csswg.org/css-device-adapt/#css-viewport-rule-interface
[Exposed=Window]
interface CSSViewportRule : CSSRule {
// readonly attribute CSSStyleDeclaration style;
};

View file

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://drafts.csswg.org/cssom/#the-stylesheet-interface // https://drafts.csswg.org/cssom/#the-stylesheet-interface
[Exposed=(Window,Worker)] [Exposed=Window]
interface StyleSheet { interface StyleSheet {
readonly attribute DOMString type_; readonly attribute DOMString type_;
readonly attribute DOMString? href; readonly attribute DOMString? href;

View file

@ -4,7 +4,7 @@
// https://drafts.csswg.org/cssom/#the-stylesheetlist-interface // https://drafts.csswg.org/cssom/#the-stylesheetlist-interface
// [ArrayClass] // [ArrayClass]
[Exposed=(Window,Worker)] [Exposed=Window]
interface StyleSheetList { interface StyleSheetList {
getter StyleSheet? item(unsigned long index); getter StyleSheet? item(unsigned long index);
readonly attribute unsigned long length; readonly attribute unsigned long length;

View file

@ -388,7 +388,7 @@ impl Stylist {
false false
} }
self.is_device_dirty |= stylesheets.iter().any(|stylesheet| { self.is_device_dirty |= stylesheets.iter().any(|stylesheet| {
mq_eval_changed(&stylesheet.rules, &self.device, &device) mq_eval_changed(&stylesheet.rules.0.read(), &self.device, &device)
}); });
self.device = device; self.device = device;

View file

@ -7,6 +7,7 @@
use {Atom, Prefix, Namespace}; use {Atom, Prefix, Namespace};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
use cssparser::{AtRuleType, RuleListParser, Token}; use cssparser::{AtRuleType, RuleListParser, Token};
use cssparser::ToCss as ParserToCss;
use encoding::EncodingRef; use encoding::EncodingRef;
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use font_face::{FontFaceRule, parse_font_face_block}; use font_face::{FontFaceRule, parse_font_face_block};
@ -18,7 +19,9 @@ use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
use selector_impl::TheSelectorImpl; use selector_impl::TheSelectorImpl;
use selectors::parser::{Selector, parse_selector_list}; use selectors::parser::{Selector, parse_selector_list};
use std::cell::Cell; use std::cell::Cell;
use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use style_traits::ToCss;
use url::Url; use url::Url;
use viewport::ViewportRule; use viewport::ViewportRule;
@ -39,12 +42,20 @@ pub enum Origin {
User, User,
} }
#[derive(Debug, Clone)]
pub struct CssRules(pub Arc<RwLock<Vec<CssRule>>>);
impl From<Vec<CssRule>> for CssRules {
fn from(other: Vec<CssRule>) -> Self {
CssRules(Arc::new(RwLock::new(other)))
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Stylesheet { pub struct Stylesheet {
/// List of rules in the order they were found (important for /// List of rules in the order they were found (important for
/// cascading order) /// cascading order)
pub rules: Vec<CssRule>, pub rules: CssRules,
/// List of media associated with the Stylesheet. /// List of media associated with the Stylesheet.
pub media: MediaList, pub media: MediaList,
pub origin: Origin, pub origin: Origin,
@ -59,7 +70,7 @@ pub struct UserAgentStylesheets {
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum CssRule { pub enum CssRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM // No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013 // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
@ -89,7 +100,8 @@ impl CssRule {
CssRule::Media(ref lock) => { CssRule::Media(ref lock) => {
let media_rule = lock.read(); let media_rule = lock.read();
let mq = media_rule.media_queries.read(); let mq = media_rule.media_queries.read();
f(&media_rule.rules, Some(&mq)) let rules = media_rule.rules.0.read();
f(&rules, Some(&mq))
} }
} }
} }
@ -112,7 +124,7 @@ pub struct KeyframesRule {
#[derive(Debug)] #[derive(Debug)]
pub struct MediaRule { pub struct MediaRule {
pub media_queries: Arc<RwLock<MediaList>>, pub media_queries: Arc<RwLock<MediaList>>,
pub rules: Vec<CssRule>, pub rules: CssRules,
} }
#[derive(Debug)] #[derive(Debug)]
@ -121,6 +133,41 @@ pub struct StyleRule {
pub block: Arc<RwLock<PropertyDeclarationBlock>>, pub block: Arc<RwLock<PropertyDeclarationBlock>>,
} }
impl StyleRule {
/// Serialize the group of selectors for this rule.
///
/// https://drafts.csswg.org/cssom/#serialize-a-group-of-selectors
pub fn selectors_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let mut iter = self.selectors.iter();
try!(iter.next().unwrap().to_css(dest));
for selector in iter {
try!(write!(dest, ", "));
try!(selector.to_css(dest));
}
Ok(())
}
}
impl ToCss for StyleRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
// Step 1
try!(self.selectors_to_css(dest));
// Step 2
try!(dest.write_str(" { "));
// Step 3
let declaration_block = self.block.read();
try!(declaration_block.to_css(dest));
// Step 4
if declaration_block.declarations.len() > 0 {
try!(write!(dest, " "));
}
// Step 5
try!(dest.write_str("}"));
Ok(())
}
}
impl Stylesheet { impl Stylesheet {
pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>( pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>(
@ -180,7 +227,7 @@ impl Stylesheet {
Stylesheet { Stylesheet {
origin: origin, origin: origin,
rules: rules, rules: rules.into(),
media: Default::default(), media: Default::default(),
dirty_on_viewport_size_change: dirty_on_viewport_size_change:
input.seen_viewport_percentages(), input.seen_viewport_percentages(),
@ -208,7 +255,7 @@ impl Stylesheet {
/// examined. /// examined.
#[inline] #[inline]
pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) { pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) {
effective_rules(&self.rules, device, &mut f); effective_rules(&self.rules.0.read(), device, &mut f);
} }
} }
@ -251,7 +298,7 @@ rule_filter! {
effective_keyframes_rules(Keyframes => KeyframesRule), effective_keyframes_rules(Keyframes => KeyframesRule),
} }
fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CssRule> { fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> CssRules {
let mut iter = RuleListParser::new_for_nested_rule(input, let mut iter = RuleListParser::new_for_nested_rule(input,
NestedRuleParser { context: context }); NestedRuleParser { context: context });
let mut rules = Vec::new(); let mut rules = Vec::new();
@ -265,7 +312,7 @@ fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CssRul
} }
} }
} }
rules rules.into()
} }

View file

@ -255,7 +255,7 @@ pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorr
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool { pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool {
!Stylesheet::as_arc(&raw_sheet).rules.is_empty() !Stylesheet::as_arc(&raw_sheet).rules.0.read().is_empty()
} }
#[no_mangle] #[no_mangle]

View file

@ -63,7 +63,7 @@ WEBIDL_STANDARDS = [
"//dvcs.w3.org/hg", "//dvcs.w3.org/hg",
"//dom.spec.whatwg.org", "//dom.spec.whatwg.org",
"//domparsing.spec.whatwg.org", "//domparsing.spec.whatwg.org",
"//drafts.csswg.org/cssom", "//drafts.csswg.org",
"//drafts.fxtf.org", "//drafts.fxtf.org",
"//encoding.spec.whatwg.org", "//encoding.spec.whatwg.org",
"//fetch.spec.whatwg.org", "//fetch.spec.whatwg.org",

View file

@ -29,7 +29,7 @@ fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaList, &str) {
let stylesheet = Stylesheet::from_str(css, url, Origin::Author, Box::new(CSSErrorReporterTest), let stylesheet = Stylesheet::from_str(css, url, Origin::Author, Box::new(CSSErrorReporterTest),
ParserContextExtraData::default()); ParserContextExtraData::default());
let mut rule_count = 0; let mut rule_count = 0;
media_queries(&stylesheet.rules, &mut |mq| { media_queries(&stylesheet.rules.0.read(), &mut |mq| {
rule_count += 1; rule_count += 1;
callback(mq, css); callback(mq, css);
}); });

View file

@ -256,7 +256,7 @@ fn test_parse_stylesheet() {
] ]
}))) })))
], ].into(),
}; };
assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected)); assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected));

View file

@ -1,2 +1,3 @@
[test_pref_reset.html] [test_pref_reset.html]
type: testharness
prefs: [@Reset] prefs: [@Reset]

View file

@ -1,3 +1,4 @@
[test_pref_set.html] [test_pref_set.html]
type: testharness
prefs: ["browser.display.foreground_color:#00FF00", prefs: ["browser.display.foreground_color:#00FF00",
"browser.display.background_color:#000000"] "browser.display.background_color:#000000"]

View file

@ -1,2 +1,3 @@
[testharness_1.html] [testharness_1.html]
type: testharness
disabled: @False disabled: @False

View file

@ -1,4 +1,5 @@
tags: [file-tag] tags: [file-tag]
[testharness_0.html] [testharness_0.html]
type: testharness
tags: [test-tag] tags: [test-tag]

View file

@ -1,2 +1,3 @@
[testharness_0.html] [testharness_0.html]
type: testharness
tags: [test-1-tag] tags: [test-1-tag]

View file

@ -1,4 +1,5 @@
tags: [file-tag] tags: [file-tag]
[testharness_2.html] [testharness_2.html]
type: testharness
tags: [test-2-tag, @Reset] tags: [test-2-tag, @Reset]

View file

@ -2,6 +2,7 @@
type: testharness type: testharness
[changing transition-property / values] [changing transition-property / values]
expected: FAIL expected: FAIL
[changing transition-duration / values] [changing transition-duration / values]
expected: FAIL expected: FAIL

View file

@ -1,2 +1,3 @@
[color-applies-to-014.htm] [color-applies-to-014.htm]
disabled: https://github.com/servo/servo/pull/13870#issuecomment-255507790 type: reftest
disabled: https://github.com/servo/servo/pull/13870

View file

@ -1,3 +1,8 @@
[index-003.htm] [index-003.htm]
type: testharness type: testharness
expected: ERROR [@import rule is expected to be @import url("main.css")]
expected: FAIL
[page rule is expected to be @page :first]
expected: FAIL

View file

@ -117,24 +117,9 @@
[StyleSheet interface: attribute disabled] [StyleSheet interface: attribute disabled]
expected: FAIL expected: FAIL
[CSSStyleSheet interface: existence and properties of interface object]
expected: FAIL
[CSSStyleSheet interface object length]
expected: FAIL
[CSSStyleSheet interface: existence and properties of interface prototype object]
expected: FAIL
[CSSStyleSheet interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSStyleSheet interface: attribute ownerRule] [CSSStyleSheet interface: attribute ownerRule]
expected: FAIL expected: FAIL
[CSSStyleSheet interface: attribute cssRules]
expected: FAIL
[CSSStyleSheet interface: operation insertRule(DOMString,unsigned long)] [CSSStyleSheet interface: operation insertRule(DOMString,unsigned long)]
expected: FAIL expected: FAIL
@ -189,24 +174,9 @@
[StyleSheetList interface: existence and properties of interface prototype object] [StyleSheetList interface: existence and properties of interface prototype object]
expected: FAIL expected: FAIL
[CSSRuleList interface: existence and properties of interface object]
expected: FAIL
[CSSRuleList interface object length]
expected: FAIL
[CSSRuleList interface: existence and properties of interface prototype object] [CSSRuleList interface: existence and properties of interface prototype object]
expected: FAIL expected: FAIL
[CSSRuleList interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSRuleList interface: operation item(unsigned long)]
expected: FAIL
[CSSRuleList interface: attribute length]
expected: FAIL
[CSSRuleList must be primary interface of style_element.sheet.cssRules] [CSSRuleList must be primary interface of style_element.sheet.cssRules]
expected: FAIL expected: FAIL
@ -222,90 +192,9 @@
[CSSRuleList interface: style_element.sheet.cssRules must inherit property "length" with the proper type (1)] [CSSRuleList interface: style_element.sheet.cssRules must inherit property "length" with the proper type (1)]
expected: FAIL expected: FAIL
[CSSRule interface: existence and properties of interface object]
expected: FAIL
[CSSRule interface object length]
expected: FAIL
[CSSRule interface: existence and properties of interface prototype object]
expected: FAIL
[CSSRule interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSRule interface: constant STYLE_RULE on interface object]
expected: FAIL
[CSSRule interface: constant STYLE_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant CHARSET_RULE on interface object]
expected: FAIL
[CSSRule interface: constant CHARSET_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant IMPORT_RULE on interface object]
expected: FAIL
[CSSRule interface: constant IMPORT_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant MEDIA_RULE on interface object]
expected: FAIL
[CSSRule interface: constant MEDIA_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant FONT_FACE_RULE on interface object]
expected: FAIL
[CSSRule interface: constant FONT_FACE_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant PAGE_RULE on interface object]
expected: FAIL
[CSSRule interface: constant PAGE_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant MARGIN_RULE on interface object]
expected: FAIL
[CSSRule interface: constant MARGIN_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: constant NAMESPACE_RULE on interface object]
expected: FAIL
[CSSRule interface: constant NAMESPACE_RULE on interface prototype object]
expected: FAIL
[CSSRule interface: attribute type]
expected: FAIL
[CSSRule interface: attribute cssText]
expected: FAIL
[CSSRule interface: attribute parentRule] [CSSRule interface: attribute parentRule]
expected: FAIL expected: FAIL
[CSSRule interface: attribute parentStyleSheet]
expected: FAIL
[CSSStyleRule interface: existence and properties of interface object]
expected: FAIL
[CSSStyleRule interface object length]
expected: FAIL
[CSSStyleRule interface: existence and properties of interface prototype object]
expected: FAIL
[CSSStyleRule interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSStyleRule interface: attribute selectorText] [CSSStyleRule interface: attribute selectorText]
expected: FAIL expected: FAIL
@ -381,18 +270,6 @@
[CSSImportRule interface: attribute styleSheet] [CSSImportRule interface: attribute styleSheet]
expected: FAIL expected: FAIL
[CSSGroupingRule interface: existence and properties of interface object]
expected: FAIL
[CSSGroupingRule interface object length]
expected: FAIL
[CSSGroupingRule interface: existence and properties of interface prototype object]
expected: FAIL
[CSSGroupingRule interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSGroupingRule interface: attribute cssRules] [CSSGroupingRule interface: attribute cssRules]
expected: FAIL expected: FAIL
@ -402,18 +279,6 @@
[CSSGroupingRule interface: operation deleteRule(unsigned long)] [CSSGroupingRule interface: operation deleteRule(unsigned long)]
expected: FAIL expected: FAIL
[CSSMediaRule interface: existence and properties of interface object]
expected: FAIL
[CSSMediaRule interface object length]
expected: FAIL
[CSSMediaRule interface: existence and properties of interface prototype object]
expected: FAIL
[CSSMediaRule interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSMediaRule interface: attribute media] [CSSMediaRule interface: attribute media]
expected: FAIL expected: FAIL
@ -453,18 +318,6 @@
[CSSMarginRule interface: attribute style] [CSSMarginRule interface: attribute style]
expected: FAIL expected: FAIL
[CSSNamespaceRule interface: existence and properties of interface object]
expected: FAIL
[CSSNamespaceRule interface object length]
expected: FAIL
[CSSNamespaceRule interface: existence and properties of interface prototype object]
expected: FAIL
[CSSNamespaceRule interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[CSSNamespaceRule interface: attribute namespaceURI] [CSSNamespaceRule interface: attribute namespaceURI]
expected: FAIL expected: FAIL

View file

@ -17,3 +17,4 @@
[test skewY()] [test skewY()]
expected: FAIL expected: FAIL

View file

@ -1,6 +1,5 @@
[DOMMatrix-001.xht] [DOMMatrix-001.xht]
type: testharness type: testharness
[testConstructor1] [testConstructor1]
expected: FAIL expected: FAIL

View file

@ -17,3 +17,4 @@
[test skewY()] [test skewY()]
expected: FAIL expected: FAIL

View file

@ -1,6 +1,5 @@
[DOMMatrix-001.xht] [DOMMatrix-001.xht]
type: testharness type: testharness
[testConstructor1] [testConstructor1]
expected: FAIL expected: FAIL

View file

@ -17,3 +17,4 @@
[test skewY()] [test skewY()]
expected: FAIL expected: FAIL

View file

@ -1,2 +1,3 @@
[basic-transition.html] [basic-transition.html]
type: reftest
disabled: https://github.com/servo/servo/issues/13865 disabled: https://github.com/servo/servo/issues/13865

View file

@ -0,0 +1,4 @@
[inline_block_opacity_change.html]
type: reftest
expected: PASS
disabled: https://github.com/servo/servo/issues/13360

View file

@ -20,7 +20,17 @@ test_interfaces([
"CharacterData", "CharacterData",
"CloseEvent", "CloseEvent",
"CSS", "CSS",
"CSSFontFaceRule",
"CSSGroupingRule",
"CSSKeyframesRule",
"CSSMediaRule",
"CSSNamespaceRule",
"CSSRule",
"CSSRuleList",
"CSSStyleDeclaration", "CSSStyleDeclaration",
"CSSStyleRule",
"CSSStyleSheet",
"CSSViewportRule",
"DOMMatrix", "DOMMatrix",
"DOMMatrixReadOnly", "DOMMatrixReadOnly",
"DOMPoint", "DOMPoint",

View file

@ -10,7 +10,6 @@ test_interfaces([
"BeforeUnloadEvent", "BeforeUnloadEvent",
"Blob", "Blob",
"CloseEvent", "CloseEvent",
"CSS",
"CSSStyleDeclaration", "CSSStyleDeclaration",
"DOMPoint", "DOMPoint",
"DOMPointReadOnly", "DOMPointReadOnly",
@ -50,8 +49,6 @@ test_interfaces([
"Screen", "Screen",
"Storage", "Storage",
"StorageEvent", "StorageEvent",
"StyleSheet",
"StyleSheetList",
"TextDecoder", "TextDecoder",
"TextEncoder", "TextEncoder",
"URL", "URL",