aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/attr.rs2
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py35
-rw-r--r--components/script/dom/cssstyledeclaration.rs41
-rw-r--r--components/script/dom/document.rs29
-rw-r--r--components/script/dom/element.rs96
-rw-r--r--components/script/dom/htmllinkelement.rs2
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;
}