mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Move "insert a CSS rule" algorithm to style
This also changes the algorithm to match w3c/csswg-drafts#754 instead of the current cssom draft, because that makes the code simpler and matches implementation of other browsers.
This commit is contained in:
parent
c8e39dcdf6
commit
134ef33842
2 changed files with 70 additions and 62 deletions
|
@ -15,13 +15,23 @@ use dom::cssstylesheet::CSSStyleSheet;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::parser::ParserContextExtraData;
|
use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError};
|
||||||
use style::stylesheets::{CssRules, KeyframesRule, Origin};
|
|
||||||
use style::stylesheets::CssRule as StyleCssRule;
|
use style::stylesheets::CssRule as StyleCssRule;
|
||||||
|
|
||||||
no_jsmanaged_fields!(RulesSource);
|
no_jsmanaged_fields!(RulesSource);
|
||||||
no_jsmanaged_fields!(CssRules);
|
no_jsmanaged_fields!(CssRules);
|
||||||
|
|
||||||
|
impl From<RulesMutateError> for Error {
|
||||||
|
fn from(other: RulesMutateError) -> Self {
|
||||||
|
match other {
|
||||||
|
RulesMutateError::Syntax => Error::Syntax,
|
||||||
|
RulesMutateError::IndexSize => Error::IndexSize,
|
||||||
|
RulesMutateError::HierarchyRequest => Error::HierarchyRequest,
|
||||||
|
RulesMutateError::InvalidState => Error::InvalidState,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct CSSRuleList {
|
pub struct CSSRuleList {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
@ -64,21 +74,9 @@ impl CSSRuleList {
|
||||||
CSSRuleListBinding::Wrap)
|
CSSRuleListBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/cssom/#insert-a-css-rule
|
|
||||||
///
|
|
||||||
/// Should only be called for CssRules-backed rules. Use append_lazy_rule
|
/// Should only be called for CssRules-backed rules. Use append_lazy_rule
|
||||||
/// for keyframes-backed rules.
|
/// for keyframes-backed rules.
|
||||||
pub fn insert_rule(&self, rule: &str, idx: u32, nested: bool) -> Fallible<u32> {
|
pub fn insert_rule(&self, rule: &str, idx: u32, nested: bool) -> Fallible<u32> {
|
||||||
use style::stylesheets::SingleRuleParseError;
|
|
||||||
/// Insert an item into a vector, appending if it is out of bounds
|
|
||||||
fn insert<T>(vec: &mut Vec<T>, index: usize, item: T) {
|
|
||||||
if index >= vec.len() {
|
|
||||||
vec.push(item);
|
|
||||||
} else {
|
|
||||||
vec.insert(index, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let css_rules = if let RulesSource::Rules(ref rules) = self.rules {
|
let css_rules = if let RulesSource::Rules(ref rules) = self.rules {
|
||||||
rules
|
rules
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,58 +88,12 @@ impl CSSRuleList {
|
||||||
let doc = window.Document();
|
let doc = window.Document();
|
||||||
let index = idx as usize;
|
let index = idx as usize;
|
||||||
|
|
||||||
|
let new_rule = css_rules.insert_rule(rule, doc.url().clone(), index, nested)?;
|
||||||
|
|
||||||
let new_rule = {
|
|
||||||
let rules = css_rules.0.read();
|
|
||||||
let state = if nested {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(CssRules::state_at_index(&rules, index))
|
|
||||||
};
|
|
||||||
|
|
||||||
let rev_state = CssRules::state_at_index_rev(&rules, index);
|
|
||||||
|
|
||||||
// Step 1, 2
|
|
||||||
// XXXManishearth get url from correct location
|
|
||||||
// XXXManishearth should we also store the namespace map?
|
|
||||||
let parse_result = StyleCssRule::parse(&rule, Origin::Author,
|
|
||||||
doc.url().clone(),
|
|
||||||
ParserContextExtraData::default(),
|
|
||||||
state);
|
|
||||||
|
|
||||||
if let Err(SingleRuleParseError::Syntax) = parse_result {
|
|
||||||
return Err(Error::Syntax)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3, 4
|
|
||||||
if index > rules.len() {
|
|
||||||
return Err(Error::IndexSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (new_rule, new_state) = try!(parse_result.map_err(|_| Error::HierarchyRequest));
|
|
||||||
|
|
||||||
if new_state > rev_state {
|
|
||||||
// We inserted a rule too early, e.g. inserting
|
|
||||||
// a regular style rule before @namespace rules
|
|
||||||
return Err((Error::HierarchyRequest));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6
|
|
||||||
if let StyleCssRule::Namespace(..) = new_rule {
|
|
||||||
if !CssRules::only_ns_or_import(&rules) {
|
|
||||||
return Err(Error::InvalidState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_rule
|
|
||||||
};
|
|
||||||
|
|
||||||
insert(&mut css_rules.0.write(), index, new_rule.clone());
|
|
||||||
let sheet = self.sheet.get();
|
let sheet = self.sheet.get();
|
||||||
let sheet = sheet.as_ref().map(|sheet| &**sheet);
|
let sheet = sheet.as_ref().map(|sheet| &**sheet);
|
||||||
let dom_rule = CSSRule::new_specific(&window, sheet, new_rule);
|
let dom_rule = CSSRule::new_specific(&window, sheet, new_rule);
|
||||||
insert(&mut self.dom_rules.borrow_mut(),
|
self.dom_rules.borrow_mut().insert(index, MutNullableHeap::new(Some(&*dom_rule)));
|
||||||
index, MutNullableHeap::new(Some(&*dom_rule)));
|
|
||||||
Ok((idx))
|
Ok((idx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,22 @@ impl From<Vec<CssRule>> for CssRules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum RulesMutateError {
|
||||||
|
Syntax,
|
||||||
|
IndexSize,
|
||||||
|
HierarchyRequest,
|
||||||
|
InvalidState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SingleRuleParseError> for RulesMutateError {
|
||||||
|
fn from(other: SingleRuleParseError) -> Self {
|
||||||
|
match other {
|
||||||
|
SingleRuleParseError::Syntax => RulesMutateError::Syntax,
|
||||||
|
SingleRuleParseError::Hierarchy => RulesMutateError::HierarchyRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CssRules {
|
impl CssRules {
|
||||||
// used in CSSOM
|
// used in CSSOM
|
||||||
pub fn only_ns_or_import(rules: &[CssRule]) -> bool {
|
pub fn only_ns_or_import(rules: &[CssRule]) -> bool {
|
||||||
|
@ -102,6 +118,46 @@ impl CssRules {
|
||||||
State::Body
|
State::Body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/cssom/#insert-a-css-rule
|
||||||
|
pub fn insert_rule(&self, rule: &str, base_url: ServoUrl, index: usize, nested: bool)
|
||||||
|
-> Result<CssRule, RulesMutateError> {
|
||||||
|
let mut rules = self.0.write();
|
||||||
|
|
||||||
|
// Step 1, 2
|
||||||
|
if index > rules.len() {
|
||||||
|
return Err(RulesMutateError::IndexSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = if nested {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(CssRules::state_at_index(&rules, index))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 3, 4
|
||||||
|
// XXXManishearth should we also store the namespace map?
|
||||||
|
let (new_rule, new_state) = try!(CssRule::parse(&rule, Origin::Author, base_url,
|
||||||
|
ParserContextExtraData::default(), state));
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
let rev_state = CssRules::state_at_index_rev(&rules, index);
|
||||||
|
if new_state > rev_state {
|
||||||
|
// We inserted a rule too early, e.g. inserting
|
||||||
|
// a regular style rule before @namespace rules
|
||||||
|
return Err(RulesMutateError::HierarchyRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
if let CssRule::Namespace(..) = new_rule {
|
||||||
|
if !CssRules::only_ns_or_import(&rules) {
|
||||||
|
return Err(RulesMutateError::InvalidState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rules.insert(index, new_rule.clone());
|
||||||
|
Ok(new_rule)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue