Skip to content

Commit

Permalink
Merge normal and important declarations in style rules.
Browse files Browse the repository at this point in the history
Have a single Vec instead of two. Fix #3426
  • Loading branch information
SimonSapin committed Aug 21, 2016
1 parent 577d2dc commit 16bbc2f
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 221 deletions.
36 changes: 17 additions & 19 deletions components/script/dom/cssstyledeclaration.rs
Expand Up @@ -92,7 +92,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
fn Length(&self) -> u32 {
let elem = self.owner.upcast::<Element>();
let len = match *elem.style_attribute().borrow() {
Some(ref declarations) => declarations.normal.len() + declarations.important.len(),
Some(ref declarations) => declarations.declarations.len(),
None => 0,
};
len as u32
Expand All @@ -103,19 +103,15 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
let index = index as usize;
let elem = self.owner.upcast::<Element>();
let style_attribute = elem.style_attribute().borrow();
let result = style_attribute.as_ref().and_then(|declarations| {
if index > declarations.normal.len() {
declarations.important
.get(index - declarations.normal.len())
.map(|decl| format!("{:?} !important", decl))
} else {
declarations.normal
.get(index)
.map(|decl| format!("{:?}", decl))
style_attribute.as_ref().and_then(|declarations| {
declarations.declarations.get(index)
}).map(|&(ref declaration, importance)| {
let mut css = declaration.to_css_string();
if importance.important() {
css += " !important";
}
});

result.map_or(DOMString::new(), DOMString::from)
DOMString::from(css)
}).unwrap_or_else(DOMString::new)
}

// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
Expand Down Expand Up @@ -151,11 +147,11 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 2.3
// Work around closures not being Clone
#[derive(Clone)]
struct Map<'a, 'b: 'a>(slice::Iter<'a, Ref<'b, PropertyDeclaration>>);
struct Map<'a, 'b: 'a>(slice::Iter<'a, Ref<'b, (PropertyDeclaration, Importance)>>);
impl<'a, 'b> Iterator for Map<'a, 'b> {
type Item = &'a PropertyDeclaration;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|r| &**r)
self.0.next().map(|r| &r.0)
}
}

Expand All @@ -167,7 +163,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {

// Step 3 & 4
match owner.get_inline_style_declaration(&property) {
Some(declaration) => DOMString::from(declaration.value()),
Some(declaration) => DOMString::from(declaration.0.value()),
None => DOMString::new(),
}
}
Expand All @@ -188,8 +184,10 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
}
// Step 3
} else {
if self.owner.get_important_inline_style_declaration(&property).is_some() {
return DOMString::from("important");
if let Some(decl) = self.owner.get_inline_style_declaration(&property) {
if decl.1.important() {
return DOMString::from("important");
}
}
}

Expand Down Expand Up @@ -366,7 +364,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 3
let decl_block = parse_style_attribute(&value, &window.get_url(), window.css_error_reporter(),
ParserContextExtraData::default());
*element.style_attribute().borrow_mut() = if decl_block.normal.is_empty() && decl_block.important.is_empty() {
*element.style_attribute().borrow_mut() = if decl_block.declarations.is_empty() {
None // Step 2
} else {
Some(decl_block)
Expand Down
103 changes: 26 additions & 77 deletions components/script/dom/element.rs
Expand Up @@ -80,7 +80,6 @@ use std::cell::{Cell, Ref};
use std::convert::TryFrom;
use std::default::Default;
use std::fmt;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use string_cache::{Atom, Namespace, QualName};
Expand Down Expand Up @@ -329,7 +328,9 @@ impl LayoutElementHelpers for LayoutJS<Element> {
{
#[inline]
fn from_declaration(rule: PropertyDeclaration) -> DeclarationBlock {
DeclarationBlock::from_declarations(Arc::new(vec![rule]))
DeclarationBlock::from_declarations(
Arc::new(vec![(rule, Importance::Normal)]),
Importance::Normal)
}

let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
Expand Down Expand Up @@ -761,20 +762,11 @@ impl Element {
fn remove(element: &Element, property: &str) {
let mut inline_declarations = element.style_attribute.borrow_mut();
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
let index = declarations.normal
let index = declarations.declarations
.iter()
.position(|decl| decl.matches(property));
.position(|&(ref decl, _)| decl.matches(property));
if let Some(index) = index {
Arc::make_mut(&mut declarations.normal).remove(index);
return;
}

let index = declarations.important
.iter()
.position(|decl| decl.matches(property));
if let Some(index) = index {
Arc::make_mut(&mut declarations.important).remove(index);
return;
Arc::make_mut(&mut declarations.declarations).remove(index);
}
}
}
Expand All @@ -786,47 +778,29 @@ impl Element {
pub fn update_inline_style(&self,
declarations: Vec<PropertyDeclaration>,
importance: Importance) {
fn update(element: &Element, mut declarations: Vec<PropertyDeclaration>,
fn update(element: &Element, declarations: Vec<PropertyDeclaration>,
importance: Importance) {
let mut inline_declarations = element.style_attribute().borrow_mut();
if let &mut Some(ref mut existing_declarations) = &mut *inline_declarations {
let existing_declarations = if importance.important() {
&mut existing_declarations.important
} else {
&mut existing_declarations.normal
};

// Usually, the reference count will be 1 here. But transitions could make it greater
// than that.
let existing_declarations = Arc::make_mut(existing_declarations);
let existing_declarations = Arc::make_mut(&mut existing_declarations.declarations);

for mut incoming_declaration in declarations {
let mut replaced = false;
'outer: for incoming_declaration in declarations {
for existing_declaration in &mut *existing_declarations {
if existing_declaration.name() == incoming_declaration.name() {
mem::swap(existing_declaration, &mut incoming_declaration);
replaced = true;
break;
if existing_declaration.0.name() == incoming_declaration.name() {
*existing_declaration = (incoming_declaration, importance);
continue 'outer;
}
}

if !replaced {
existing_declarations.push(incoming_declaration);
}
existing_declarations.push((incoming_declaration, importance));
}

return;
}

let (important, normal) = if importance.important() {
(declarations, vec![])
} else {
(vec![], declarations)
};

*inline_declarations = Some(PropertyDeclarationBlock {
important: Arc::new(important),
normal: Arc::new(normal),
declarations: Arc::new(declarations.into_iter().map(|d| (d, importance)).collect()),
});
}

Expand All @@ -836,30 +810,18 @@ impl Element {

pub fn set_inline_style_property_priority(&self,
properties: &[&str],
importance: Importance) {
new_importance: Importance) {
{
let mut inline_declarations = self.style_attribute().borrow_mut();
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
let (from, to) = if importance == Importance::Important {
(&mut declarations.normal, &mut declarations.important)
} else {
(&mut declarations.important, &mut declarations.normal)
};

// Usually, the reference counts of `from` and `to` will be 1 here. But transitions
// could make them greater than that.
let from = Arc::make_mut(from);
let to = Arc::make_mut(to);
let mut new_from = Vec::new();
for declaration in from.drain(..) {
let name = declaration.name();
if properties.iter().any(|p| name == **p) {
to.push(declaration)
} else {
new_from.push(declaration)
}
}
mem::replace(from, new_from);
// Usually, the reference counts of `from` and `to` will be 1 here. But transitions
// could make them greater than that.
let declarations = Arc::make_mut(&mut declarations.declarations);
for &mut (ref declaration, ref mut importance) in declarations {
if properties.iter().any(|p| declaration.name() == **p) {
*importance = new_importance
}
}
}
}

Expand All @@ -868,25 +830,12 @@ impl Element {

pub fn get_inline_style_declaration(&self,
property: &Atom)
-> Option<Ref<PropertyDeclaration>> {
ref_filter_map(self.style_attribute.borrow(), |inline_declarations| {
inline_declarations.as_ref().and_then(|declarations| {
declarations.normal
.iter()
.chain(declarations.important.iter())
.find(|decl| decl.matches(&property))
})
})
}

pub fn get_important_inline_style_declaration(&self,
property: &Atom)
-> Option<Ref<PropertyDeclaration>> {
-> Option<Ref<(PropertyDeclaration, Importance)>> {
ref_filter_map(self.style_attribute.borrow(), |inline_declarations| {
inline_declarations.as_ref().and_then(|declarations| {
declarations.important
declarations.declarations
.iter()
.find(|decl| decl.matches(&property))
.find(|&&(ref decl, _)| decl.matches(&property))
})
})
}
Expand Down
5 changes: 3 additions & 2 deletions components/style/animation.rs
Expand Up @@ -15,7 +15,7 @@ use properties::longhands::animation_iteration_count::computed_value::AnimationI
use properties::longhands::animation_play_state::computed_value::AnimationPlayState;
use properties::longhands::transition_timing_function::computed_value::StartEnd;
use properties::longhands::transition_timing_function::computed_value::TransitionTimingFunction;
use properties::{self, ComputedValues};
use properties::{self, ComputedValues, Importance};
use selector_matching::DeclarationBlock;
use std::sync::Arc;
use std::sync::mpsc::Sender;
Expand Down Expand Up @@ -385,7 +385,8 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations(ref declarations) => {
let declaration_block = DeclarationBlock {
declarations: declarations.clone(),
mixed_declarations: declarations.clone(),
importance: Importance::Normal,
source_order: 0,
specificity: ::std::u32::MAX,
};
Expand Down
20 changes: 13 additions & 7 deletions components/style/keyframes.rs
Expand Up @@ -5,9 +5,9 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser};
use parser::{ParserContext, log_css_error};
use properties::PropertyDeclaration;
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
use properties::{PropertyDeclaration, Importance};
use std::sync::Arc;

/// A number from 1 to 100, indicating the percentage of the animation where
Expand Down Expand Up @@ -72,7 +72,12 @@ impl KeyframeSelector {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
pub selector: KeyframeSelector,
pub declarations: Arc<Vec<PropertyDeclaration>>,

/// `!important` is not allowed in keyframe declarations,
/// so the second value of these tuples is always `Importance::Normal`.
/// But including them enables `compute_style_for_animation_step` to create a `DeclarationBlock`
/// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`.
pub declarations: Arc<Vec<(PropertyDeclaration, Importance)>>,
}

/// A keyframes step value. This can be a synthetised keyframes animation, that
Expand All @@ -82,7 +87,8 @@ pub struct Keyframe {
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
Declarations(Arc<Vec<PropertyDeclaration>>),
/// See `Keyframe::declarations`’s docs about the presence of `Importance`.
Declarations(Arc<Vec<(PropertyDeclaration, Importance)>>),
ComputedValues,
}

Expand All @@ -108,7 +114,7 @@ impl KeyframesStep {
value: KeyframesStepValue) -> Self {
let declared_timing_function = match value {
KeyframesStepValue::Declarations(ref declarations) => {
declarations.iter().any(|prop_decl| {
declarations.iter().any(|&(ref prop_decl, _)| {
match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false,
Expand Down Expand Up @@ -148,8 +154,8 @@ fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
let mut ret = vec![];
// NB: declarations are already deduplicated, so we don't have to check for
// it here.
for declaration in keyframe.declarations.iter() {
if let Some(property) = TransitionProperty::from_declaration(&declaration) {
for &(ref declaration, _) in keyframe.declarations.iter() {
if let Some(property) = TransitionProperty::from_declaration(declaration) {
ret.push(property);
}
}
Expand Down Expand Up @@ -247,7 +253,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() {
match declaration {
Ok(d) => declarations.extend(d),
Ok(d) => declarations.extend(d.into_iter().map(|d| (d, Importance::Normal))),
Err(range) => {
let pos = range.start;
let message = format!("Unsupported keyframe property declaration: '{}'",
Expand Down
19 changes: 8 additions & 11 deletions components/style/matching.rs
Expand Up @@ -14,7 +14,7 @@ use context::{StyleContext, SharedStyleContext};
use data::PrivateStyleData;
use dom::{TElement, TNode, TRestyleDamage, UnsafeNode};
use properties::longhands::display::computed_value as display;
use properties::{ComputedValues, PropertyDeclaration, cascade};
use properties::{ComputedValues, cascade};
use selector_impl::{TheSelectorImpl, PseudoElement};
use selector_matching::{DeclarationBlock, Stylist};
use selectors::bloom::BloomFilter;
Expand Down Expand Up @@ -118,15 +118,11 @@ impl<'a> ApplicableDeclarationsCacheQuery<'a> {

impl<'a> PartialEq for ApplicableDeclarationsCacheQuery<'a> {
fn eq(&self, other: &ApplicableDeclarationsCacheQuery<'a>) -> bool {
if self.declarations.len() != other.declarations.len() {
return false
}
for (this, other) in self.declarations.iter().zip(other.declarations) {
if !arc_ptr_eq(&this.declarations, &other.declarations) {
return false
}
}
true
self.declarations.len() == other.declarations.len() &&
self.declarations.iter().zip(other.declarations).all(|(this, other)| {
arc_ptr_eq(&this.mixed_declarations, &other.mixed_declarations) &&
this.importance == other.importance
})
}
}
impl<'a> Eq for ApplicableDeclarationsCacheQuery<'a> {}
Expand All @@ -143,8 +139,9 @@ impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> {
for declaration in self.declarations {
// Each declaration contians an Arc, which is a stable
// pointer; we use that for hashing and equality.
let ptr = &*declaration.declarations as *const Vec<PropertyDeclaration>;
let ptr: *const Vec<_> = &*declaration.mixed_declarations;
ptr.hash(state);
declaration.importance.hash(state);
}
}
}
Expand Down

0 comments on commit 16bbc2f

Please sign in to comment.