script: Don't avoid all the mutation notification methods when the style attribute changes.

Styling was correct because of the explicit dirtiness, but still not fun.

Some things, like dynamic updates to with things like [style~="color"] ~ foo
selectors, were pretty broken, because we didn't take snapshots of those
attributes.
This commit is contained in:
Emilio Cobos Álvarez 2017-01-29 01:25:56 +01:00
parent cb304fd42c
commit 31ecc9b692
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 93 additions and 55 deletions

View file

@ -11,12 +11,13 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::cssrule::CSSRule;
use dom::element::Element;
use dom::node::{Node, NodeDamage, window_from_node};
use dom::node::{Node, window_from_node};
use dom::window::Window;
use parking_lot::RwLock;
use servo_url::ServoUrl;
use std::ascii::AsciiExt;
use std::sync::Arc;
use style::attr::AttrValue;
use style::parser::ParserContextExtraData;
use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
use style::properties::{parse_one_declaration, parse_style_attribute};
@ -53,16 +54,12 @@ impl CSSStyleOwner {
let mut changed = true;
match *self {
CSSStyleOwner::Element(ref el) => {
let mut attr = el.style_attribute().borrow_mut();
let (result, needs_clear) = if attr.is_some() {
let mut attr = el.style_attribute().borrow_mut().take();
let result = if attr.is_some() {
let lock = attr.as_ref().unwrap();
let mut pdb = lock.write();
let result = f(&mut pdb, &mut changed);
if changed {
el.set_style_attr(pdb.to_css_string());
el.upcast::<Node>().dirty(NodeDamage::NodeStyleDamaged);
}
(result, pdb.declarations.is_empty())
result
} else {
let mut pdb = PropertyDeclarationBlock {
important_count: 0,
@ -72,18 +69,32 @@ impl CSSStyleOwner {
// Here `changed` is somewhat silly, because we know the
// exact conditions under it changes.
if !pdb.declarations.is_empty() {
el.set_style_attr(pdb.to_css_string());
el.upcast::<Node>().dirty(NodeDamage::NodeStyleDamaged);
*attr = Some(Arc::new(RwLock::new(pdb)));
changed = !pdb.declarations.is_empty();
if changed {
attr = Some(Arc::new(RwLock::new(pdb)));
}
(result, false)
result
};
if needs_clear {
*attr = None;
if changed {
// Note that there's no need to remove the attribute here if
// the declaration block is empty[1], and if `attr` is
// `None` it means that it necessarily didn't change, so no
// need to go through all the set_attribute machinery.
//
// [1]: https://github.com/whatwg/html/issues/2306
if let Some(pdb) = attr {
let serialization = pdb.read().to_css_string();
el.set_attribute(&local_name!("style"),
AttrValue::Declaration(serialization,
pdb));
}
} else {
// Remember to put it back.
*el.style_attribute().borrow_mut() = attr;
}
result
}
CSSStyleOwner::CSSRule(ref rule, ref pdb) => {