diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/attr.rs | 2 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 35 | ||||
-rw-r--r-- | components/script/dom/cssstyledeclaration.rs | 41 | ||||
-rw-r--r-- | components/script/dom/document.rs | 29 | ||||
-rw-r--r-- | components/script/dom/element.rs | 96 | ||||
-rw-r--r-- | components/script/dom/htmllinkelement.rs | 2 |
6 files changed, 118 insertions, 87 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index c44cfd4367d..29c3279ad08 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -170,7 +170,7 @@ impl AttrMethods for Attr { impl Attr { pub fn set_value(&self, mut value: AttrValue, owner: &Element) { assert!(Some(owner) == self.owner().r()); - owner.will_mutate_attr(); + owner.will_mutate_attr(self); self.swap_value(&mut value); if self.identifier.namespace == ns!() { vtable_for(owner.upcast()) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 093f402fa47..b2fdbbfaf51 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5894,14 +5894,16 @@ class CGDictionary(CGThing): def impl(self): d = self.dictionary if d.parent: - initParent = ("parent: match try!(%s::%s::new(cx, val)) {\n" - " ConversionResult::Success(v) => v,\n" - " ConversionResult::Failure(error) => {\n" - " throw_type_error(cx, &error);\n" - " return Err(());\n" - " }\n" - " },\n" % (self.makeModuleName(d.parent), - self.makeClassName(d.parent))) + initParent = ("parent: {\n" + " match try!(%s::%s::new(cx, val)) {\n" + " ConversionResult::Success(v) => v,\n" + " ConversionResult::Failure(error) => {\n" + " throw_type_error(cx, &error);\n" + " return Err(());\n" + " }\n" + " }\n" + "},\n" % (self.makeModuleName(d.parent), + self.makeClassName(d.parent))) else: initParent = "" @@ -5999,7 +6001,7 @@ class CGDictionary(CGThing): def getMemberConversion(self, memberInfo, memberType): def indent(s): - return CGIndenter(CGGeneric(s), 8).define() + return CGIndenter(CGGeneric(s), 12).define() member, info = memberInfo templateBody = info.template @@ -6020,15 +6022,16 @@ class CGDictionary(CGThing): conversion = ( "{\n" - "rooted!(in(cx) let mut rval = UndefinedValue());\n" - "match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" - " true => {\n" + " rooted!(in(cx) let mut rval = UndefinedValue());\n" + " match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" + " true => {\n" "%s\n" - " },\n" - " false => {\n" + " },\n" + " false => {\n" "%s\n" - " },\n" - "}\n}") % (member.identifier.name, indent(conversion), indent(default)) + " },\n" + " }\n" + "}") % (member.identifier.name, indent(conversion), indent(default)) return CGGeneric(conversion) diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index f04bd4017ee..12bf4386433 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -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) => { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index be44ae0a91c..b2e93325236 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -129,7 +129,7 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use style::attr::AttrValue; use style::context::{QuirksMode, ReflowGoal}; -use style::restyle_hints::RestyleHint; +use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE}; use style::selector_parser::{RestyleDamage, Snapshot}; use style::str::{split_html_space_chars, str_join}; use style::stylesheets::Stylesheet; @@ -179,7 +179,7 @@ impl PendingRestyle { } } -// https://dom.spec.whatwg.org/#document +/// https://dom.spec.whatwg.org/#document #[dom_struct] pub struct Document { node: Node, @@ -2142,23 +2142,32 @@ impl Document { RefMut::map(map, |m| m.entry(JS::from_ref(el)).or_insert_with(PendingRestyle::new)) } - pub fn ensure_snapshot(&self, el: &Element) -> RefMut<Snapshot> { + pub fn element_state_will_change(&self, el: &Element) { let mut entry = self.ensure_pending_restyle(el); if entry.snapshot.is_none() { entry.snapshot = Some(Snapshot::new(el.html_element_in_html_document())); } - RefMut::map(entry, |e| e.snapshot.as_mut().unwrap()) - } - - pub fn element_state_will_change(&self, el: &Element) { - let mut snapshot = self.ensure_snapshot(el); + let mut snapshot = entry.snapshot.as_mut().unwrap(); if snapshot.state.is_none() { snapshot.state = Some(el.state()); } } - pub fn element_attr_will_change(&self, el: &Element) { - let mut snapshot = self.ensure_snapshot(el); + pub fn element_attr_will_change(&self, el: &Element, attr: &Attr) { + // FIXME(emilio): Kind of a shame we have to duplicate this. + // + // I'm getting rid of the whole hashtable soon anyway, since all it does + // right now is populate the element restyle data in layout, and we + // could in theory do it in the DOM I think. + let mut entry = self.ensure_pending_restyle(el); + if entry.snapshot.is_none() { + entry.snapshot = Some(Snapshot::new(el.html_element_in_html_document())); + } + if attr.local_name() == &local_name!("style") { + entry.hint |= RESTYLE_STYLE_ATTRIBUTE; + } + + let mut snapshot = entry.snapshot.as_mut().unwrap(); if snapshot.attrs.is_none() { let attrs = el.attrs() .iter() diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index f85baf3811e..e93becfffdd 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -105,6 +105,7 @@ use style::properties::{DeclaredValue, Importance}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute}; use style::properties::longhands::{background_image, border_spacing, font_family, font_size, overflow_x}; use style::restyle_hints::RESTYLE_SELF; +use style::rule_tree::CascadeLevel; use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser}; use style::sink::Push; use style::stylist::ApplicableDeclarationBlock; @@ -380,7 +381,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { declarations: vec![(declaration, Importance::Normal)], important_count: 0, })), - Importance::Normal) + CascadeLevel::PresHints) } let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() { @@ -824,31 +825,6 @@ impl Element { } } - // this sync method is called upon modification of the style_attribute property, - // therefore, it should not trigger subsequent mutation events - pub fn set_style_attr(&self, new_value: String) { - let mut new_style = AttrValue::String(new_value); - - if let Some(style_attr) = self.attrs.borrow().iter().find(|a| a.name() == &local_name!("style")) { - style_attr.swap_value(&mut new_style); - return; - } - - // explicitly not calling the push_new_attribute convenience method - // in order to avoid triggering mutation events - let window = window_from_node(self); - let attr = Attr::new(&window, - local_name!("style"), - new_style, - local_name!("style"), - ns!(), - None, - Some(self)); - - assert!(attr.GetOwnerElement().r() == Some(self)); - self.attrs.borrow_mut().push(JS::from_ref(&attr)); - } - pub fn serialize(&self, traversal_scope: TraversalScope) -> Fallible<DOMString> { let mut writer = vec![]; match serialize(&mut writer, @@ -962,7 +938,7 @@ impl Element { pub fn push_attribute(&self, attr: &Attr) { assert!(attr.GetOwnerElement().r() == Some(self)); - self.will_mutate_attr(); + self.will_mutate_attr(attr); self.attrs.borrow_mut().push(JS::from_ref(attr)); if attr.namespace() == &ns!() { vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None)); @@ -1088,8 +1064,8 @@ impl Element { let idx = self.attrs.borrow().iter().position(|attr| find(&attr)); idx.map(|idx| { - self.will_mutate_attr(); let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]); + self.will_mutate_attr(&attr); self.attrs.borrow_mut().remove(idx); attr.set_owner(None); if attr.namespace() == &ns!() { @@ -1227,9 +1203,9 @@ impl Element { self.set_attribute(local_name, AttrValue::UInt(value.to_string(), value)); } - pub fn will_mutate_attr(&self) { + pub fn will_mutate_attr(&self, attr: &Attr) { let node = self.upcast::<Node>(); - node.owner_doc().element_attr_will_change(self); + node.owner_doc().element_attr_will_change(self, attr); } // https://dom.spec.whatwg.org/#insert-adjacent @@ -1502,7 +1478,7 @@ impl ElementMethods for Element { } // Step 4. - self.will_mutate_attr(); + self.will_mutate_attr(attr); attr.set_owner(Some(self)); self.attrs.borrow_mut()[position] = JS::from_ref(attr); old_attr.set_owner(None); @@ -2121,18 +2097,43 @@ impl VirtualMethods for Element { match attr.local_name() { &local_name!("style") => { // Modifying the `style` attribute might change style. - *self.style_attribute.borrow_mut() = - mutation.new_value(attr).map(|value| { - let win = window_from_node(self); - Arc::new(RwLock::new(parse_style_attribute( - &value, - &doc.base_url(), - win.css_error_reporter(), - ParserContextExtraData::default()))) - }); - if node.is_in_doc() { - node.dirty(NodeDamage::NodeStyleDamaged); - } + *self.style_attribute.borrow_mut() = match mutation { + AttributeMutation::Set(..) => { + // This is the fast path we use from + // CSSStyleDeclaration. + // + // Juggle a bit to keep the borrow checker happy + // while avoiding the extra clone. + let is_declaration = match *attr.value() { + AttrValue::Declaration(..) => true, + _ => false, + }; + + let block = if is_declaration { + let mut value = AttrValue::String(String::new()); + attr.swap_value(&mut value); + let (serialization, block) = match value { + AttrValue::Declaration(s, b) => (s, b), + _ => unreachable!(), + }; + let mut value = AttrValue::String(serialization); + attr.swap_value(&mut value); + block + } else { + let win = window_from_node(self); + Arc::new(RwLock::new(parse_style_attribute( + &attr.value(), + &doc.base_url(), + win.css_error_reporter(), + ParserContextExtraData::default()))) + }; + + Some(block) + } + AttributeMutation::Removed => { + None + } + }; }, &local_name!("id") => { *self.id_attribute.borrow_mut() = @@ -2716,7 +2717,7 @@ impl Element { } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy)] pub enum AttributeMutation<'a> { /// The attribute is set, keep track of old value. /// https://dom.spec.whatwg.org/#attribute-is-set @@ -2728,6 +2729,13 @@ pub enum AttributeMutation<'a> { } impl<'a> AttributeMutation<'a> { + pub fn is_removal(&self) -> bool { + match *self { + AttributeMutation::Removed => true, + AttributeMutation::Set(..) => false, + } + } + pub fn new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>> { match *self { AttributeMutation::Set(_) => Some(attr.value()), diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 4db3949d4f9..20e560e93ad 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -166,7 +166,7 @@ impl VirtualMethods for HTMLLinkElement { fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { self.super_type().unwrap().attribute_mutated(attr, mutation); - if !self.upcast::<Node>().is_in_doc() || mutation == AttributeMutation::Removed { + if !self.upcast::<Node>().is_in_doc() || mutation.is_removal() { return; } |