Add an Importance enum replacing booleans to indicate !important.

This commit is contained in:
Simon Sapin 2016-08-17 19:50:43 +02:00
parent 8218b463fb
commit 24fbb26475
3 changed files with 64 additions and 48 deletions

View file

@ -10,7 +10,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::element::{Element, StylePriority}; use dom::element::Element;
use dom::node::{Node, NodeDamage, window_from_node}; use dom::node::{Node, NodeDamage, window_from_node};
use dom::window::Window; use dom::window::Window;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
@ -18,7 +18,7 @@ use std::cell::Ref;
use std::slice; use std::slice;
use string_cache::Atom; use string_cache::Atom;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::properties::{PropertyDeclaration, Shorthand}; use style::properties::{PropertyDeclaration, Shorthand, Importance};
use style::properties::{is_supported_property, parse_one_declaration, parse_style_attribute}; use style::properties::{is_supported_property, parse_one_declaration, parse_style_attribute};
use style::selector_impl::PseudoElement; use style::selector_impl::PseudoElement;
@ -160,7 +160,8 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
} }
// TODO: important is hardcoded to false because method does not implement it yet // TODO: important is hardcoded to false because method does not implement it yet
let serialized_value = shorthand.serialize_shorthand_value_to_string(Map(list.iter()), false); let serialized_value = shorthand.serialize_shorthand_value_to_string(
Map(list.iter()), Importance::Normal);
return DOMString::from(serialized_value); return DOMString::from(serialized_value);
} }
@ -222,8 +223,8 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 5 // Step 5
let priority = match &*priority { let priority = match &*priority {
"" => StylePriority::Normal, "" => Importance::Normal,
p if p.eq_ignore_ascii_case("important") => StylePriority::Important, p if p.eq_ignore_ascii_case("important") => Importance::Important,
_ => return Ok(()), _ => return Ok(()),
}; };
@ -265,8 +266,8 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 4 // Step 4
let priority = match &*priority { let priority = match &*priority {
"" => StylePriority::Normal, "" => Importance::Normal,
p if p.eq_ignore_ascii_case("important") => StylePriority::Important, p if p.eq_ignore_ascii_case("important") => Importance::Important,
_ => return Ok(()), _ => return Ok(()),
}; };

View file

@ -87,8 +87,8 @@ use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::element_state::*; use style::element_state::*;
use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes}; use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::properties::DeclaredValue;
use style::properties::longhands::{self, background_image, border_spacing, font_family, overflow_x, font_size}; use style::properties::longhands::{self, background_image, border_spacing, font_family, overflow_x, font_size};
use style::properties::{DeclaredValue, Importance};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl};
use style::sink::Push; use style::sink::Push;
@ -660,13 +660,6 @@ impl LayoutElementHelpers for LayoutJS<Element> {
} }
} }
#[derive(PartialEq, Eq, Copy, Clone, HeapSizeOf)]
pub enum StylePriority {
Important,
Normal,
}
impl Element { impl Element {
pub fn html_element_in_html_document(&self) -> bool { pub fn html_element_in_html_document(&self) -> bool {
self.namespace == ns!(html) && self.upcast::<Node>().is_in_html_doc() self.namespace == ns!(html) && self.upcast::<Node>().is_in_html_doc()
@ -780,11 +773,12 @@ impl Element {
pub fn update_inline_style(&self, pub fn update_inline_style(&self,
declarations: Vec<PropertyDeclaration>, declarations: Vec<PropertyDeclaration>,
style_priority: StylePriority) { importance: Importance) {
fn update(element: &Element, mut declarations: Vec<PropertyDeclaration>, style_priority: StylePriority) { fn update(element: &Element, mut declarations: Vec<PropertyDeclaration>,
importance: Importance) {
let mut inline_declarations = element.style_attribute().borrow_mut(); let mut inline_declarations = element.style_attribute().borrow_mut();
if let &mut Some(ref mut existing_declarations) = &mut *inline_declarations { if let &mut Some(ref mut existing_declarations) = &mut *inline_declarations {
let existing_declarations = if style_priority == StylePriority::Important { let existing_declarations = if importance.important() {
&mut existing_declarations.important &mut existing_declarations.important
} else { } else {
&mut existing_declarations.normal &mut existing_declarations.normal
@ -813,7 +807,7 @@ impl Element {
return; return;
} }
let (important, normal) = if style_priority == StylePriority::Important { let (important, normal) = if importance.important() {
(declarations, vec![]) (declarations, vec![])
} else { } else {
(vec![], declarations) (vec![], declarations)
@ -825,17 +819,17 @@ impl Element {
}); });
} }
update(self, declarations, style_priority); update(self, declarations, importance);
self.sync_property_with_attrs_style(); self.sync_property_with_attrs_style();
} }
pub fn set_inline_style_property_priority(&self, pub fn set_inline_style_property_priority(&self,
properties: &[&str], properties: &[&str],
style_priority: StylePriority) { importance: Importance) {
{ {
let mut inline_declarations = self.style_attribute().borrow_mut(); let mut inline_declarations = self.style_attribute().borrow_mut();
if let &mut Some(ref mut declarations) = &mut *inline_declarations { if let &mut Some(ref mut declarations) = &mut *inline_declarations {
let (from, to) = if style_priority == StylePriority::Important { let (from, to) = if importance == Importance::Important {
(&mut declarations.normal, &mut declarations.important) (&mut declarations.normal, &mut declarations.important)
} else { } else {
(&mut declarations.important, &mut declarations.normal) (&mut declarations.important, &mut declarations.normal)

View file

@ -14,6 +14,8 @@ use std::ascii::AsciiExt;
use std::boxed::Box as StdBox; use std::boxed::Box as StdBox;
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::iter::{Iterator, Chain, Zip, Rev, Repeat, repeat};
use std::slice;
use std::sync::Arc; use std::sync::Arc;
use app_units::Au; use app_units::Au;
@ -261,11 +263,26 @@ mod property_bit_field {
% endif % endif
% endfor % endfor
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Importance {
/// Indicates a declaration without `!important`.
Normal,
/// Indicates a declaration with `!important`.
Important,
}
impl Importance {
pub fn important(self) -> bool {
match self {
Importance::Normal => false,
Importance::Important => true,
}
}
}
use std::iter::{Iterator, Chain, Zip, Rev, Repeat, repeat};
use std::slice;
/// Overridden declarations are skipped. /// Overridden declarations are skipped.
// FIXME (https://github.com/servo/servo/issues/3426) // FIXME (https://github.com/servo/servo/issues/3426)
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -279,12 +296,12 @@ pub struct PropertyDeclarationBlock {
impl PropertyDeclarationBlock { impl PropertyDeclarationBlock {
/// Provides an iterator of all declarations, with indication of !important value /// Provides an iterator of all declarations, with indication of !important value
pub fn declarations(&self) -> Chain< pub fn declarations(&self) -> Chain<
Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<bool>>, Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<Importance>>,
Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<bool>> Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<Importance>>
> { > {
// Declarations are stored in reverse order. // Declarations are stored in reverse order.
let normal = self.normal.iter().rev().zip(repeat(false)); let normal = self.normal.iter().rev().zip(repeat(Importance::Normal));
let important = self.important.iter().rev().zip(repeat(true)); let important = self.important.iter().rev().zip(repeat(Importance::Important));
normal.chain(important) normal.chain(important)
} }
} }
@ -300,7 +317,7 @@ impl ToCss for PropertyDeclarationBlock {
let mut already_serialized = Vec::new(); let mut already_serialized = Vec::new();
// Step 3 // Step 3
for (declaration, important) in self.declarations() { for (declaration, importance) in self.declarations() {
// Step 3.1 // Step 3.1
let property = declaration.name(); let property = declaration.name();
@ -326,11 +343,11 @@ impl ToCss for PropertyDeclarationBlock {
let mut current_longhands = Vec::new(); let mut current_longhands = Vec::new();
let mut important_count = 0; let mut important_count = 0;
for &(longhand, longhand_important) in longhands.iter() { for &(longhand, longhand_importance) in longhands.iter() {
let longhand_name = longhand.name(); let longhand_name = longhand.name();
if properties.iter().any(|p| &longhand_name == *p) { if properties.iter().any(|p| &longhand_name == *p) {
current_longhands.push(longhand); current_longhands.push(longhand);
if longhand_important { if longhand_importance.important() {
important_count += 1; important_count += 1;
} }
} }
@ -396,7 +413,7 @@ impl ToCss for PropertyDeclarationBlock {
dest, dest,
&property.to_string(), &property.to_string(),
AppendableValue::Declaration(declaration), AppendableValue::Declaration(declaration),
important, importance,
&mut is_first_serialization)); &mut is_first_serialization));
// Step 3.3.8 // Step 3.3.8
@ -430,7 +447,7 @@ fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool
fn append_declaration_value<'a, W, I> fn append_declaration_value<'a, W, I>
(dest: &mut W, (dest: &mut W,
appendable_value: AppendableValue<'a, I>, appendable_value: AppendableValue<'a, I>,
is_important: bool) importance: Importance)
-> fmt::Result -> fmt::Result
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> { where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
match appendable_value { match appendable_value {
@ -445,7 +462,7 @@ fn append_declaration_value<'a, W, I>
} }
} }
if is_important { if importance.important() {
try!(write!(dest, " !important")); try!(write!(dest, " !important"));
} }
@ -455,7 +472,7 @@ fn append_declaration_value<'a, W, I>
fn append_serialization<'a, W, I>(dest: &mut W, fn append_serialization<'a, W, I>(dest: &mut W,
property_name: &str, property_name: &str,
appendable_value: AppendableValue<'a, I>, appendable_value: AppendableValue<'a, I>,
is_important: bool, importance: Importance,
is_first_serialization: &mut bool) is_first_serialization: &mut bool)
-> fmt::Result -> fmt::Result
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> { where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
@ -465,7 +482,7 @@ fn append_serialization<'a, W, I>(dest: &mut W,
// Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
// values, they no longer use the shared property name "overflow" and must be handled differently // values, they no longer use the shared property name "overflow" and must be handled differently
if shorthands::is_overflow_shorthand(&appendable_value) { if shorthands::is_overflow_shorthand(&appendable_value) {
return append_declaration_value(dest, appendable_value, is_important); return append_declaration_value(dest, appendable_value, importance);
} }
try!(write!(dest, "{}:", property_name)); try!(write!(dest, "{}:", property_name));
@ -484,7 +501,7 @@ fn append_serialization<'a, W, I>(dest: &mut W,
&AppendableValue::DeclarationsForShorthand(..) => try!(write!(dest, " ")) &AppendableValue::DeclarationsForShorthand(..) => try!(write!(dest, " "))
} }
try!(append_declaration_value(dest, appendable_value, is_important)); try!(append_declaration_value(dest, appendable_value, importance));
write!(dest, ";") write!(dest, ";")
} }
@ -514,14 +531,15 @@ struct PropertyDeclarationParser<'a, 'b: 'a> {
/// Default methods reject all at rules. /// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type AtRule = (Vec<PropertyDeclaration>, bool); type AtRule = (Vec<PropertyDeclaration>, Importance);
} }
impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
type Declaration = (Vec<PropertyDeclaration>, bool); type Declaration = (Vec<PropertyDeclaration>, Importance);
fn parse_value(&self, name: &str, input: &mut Parser) -> Result<(Vec<PropertyDeclaration>, bool), ()> { fn parse_value(&self, name: &str, input: &mut Parser)
-> Result<(Vec<PropertyDeclaration>, Importance), ()> {
let mut results = vec![]; let mut results = vec![];
try!(input.parse_until_before(Delimiter::Bang, |input| { try!(input.parse_until_before(Delimiter::Bang, |input| {
match PropertyDeclaration::parse(name, self.context, input, &mut results) { match PropertyDeclaration::parse(name, self.context, input, &mut results) {
@ -529,8 +547,11 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
_ => Err(()) _ => Err(())
} }
})); }));
let important = input.try(parse_important).is_ok(); let importance = match input.try(parse_important) {
Ok((results, important)) Ok(()) => Importance::Important,
Err(()) => Importance::Normal,
};
Ok((results, importance))
} }
} }
@ -545,8 +566,8 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok((results, important)) => { Ok((results, importance)) => {
if important { if importance.important() {
important_declarations.extend(results); important_declarations.extend(results);
} else { } else {
normal_declarations.extend(results); normal_declarations.extend(results);
@ -675,11 +696,11 @@ impl Shorthand {
} }
/// Serializes possible shorthand value to String. /// Serializes possible shorthand value to String.
pub fn serialize_shorthand_value_to_string<'a, I>(self, declarations: I, is_important: bool) -> String pub fn serialize_shorthand_value_to_string<'a, I>(self, declarations: I, importance: Importance) -> String
where I: Iterator<Item=&'a PropertyDeclaration> + Clone { where I: Iterator<Item=&'a PropertyDeclaration> + Clone {
let appendable_value = self.get_shorthand_appendable_value(declarations).unwrap(); let appendable_value = self.get_shorthand_appendable_value(declarations).unwrap();
let mut result = String::new(); let mut result = String::new();
append_declaration_value(&mut result, appendable_value, is_important).unwrap(); append_declaration_value(&mut result, appendable_value, importance).unwrap();
result result
} }
@ -700,7 +721,7 @@ impl Shorthand {
dest, dest,
property_name, property_name,
appendable_value, appendable_value,
false, Importance::Normal,
is_first_serialization is_first_serialization
).and_then(|_| Ok(true)) ).and_then(|_| Ok(true))
} }