diff options
Diffstat (limited to 'components/script/dom/attr.rs')
-rw-r--r-- | components/script/dom/attr.rs | 233 |
1 files changed, 115 insertions, 118 deletions
diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index 55f2adcfdb6..9c4b221f6f3 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -1,88 +1,92 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::cell::{DomRefCell, Ref}; +use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; +use crate::dom::bindings::str::DOMString; +use crate::dom::customelementregistry::CallbackReaction; +use crate::dom::document::Document; +use crate::dom::element::{AttributeMutation, Element}; +use crate::dom::mutationobserver::{Mutation, MutationObserver}; +use crate::dom::node::Node; +use crate::dom::virtualmethods::vtable_for; +use crate::script_thread::ScriptThread; use devtools_traits::AttrInfo; -use dom::bindings::cell::DOMRefCell; -use dom::bindings::codegen::Bindings::AttrBinding::{self, AttrMethods}; -use dom::bindings::inheritance::Castable; -use dom::bindings::js::{LayoutJS, MutNullableJS, Root, RootedReference}; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; -use dom::bindings::str::DOMString; -use dom::element::{AttributeMutation, Element}; -use dom::virtualmethods::vtable_for; -use dom::window::Window; use dom_struct::dom_struct; -use html5ever_atoms::{Prefix, LocalName, Namespace}; +use html5ever::{LocalName, Namespace, Prefix}; use servo_atoms::Atom; use std::borrow::ToOwned; -use std::cell::Ref; use std::mem; use style::attr::{AttrIdentifier, AttrValue}; +use style::values::GenericAtomIdent; // https://dom.spec.whatwg.org/#interface-attr #[dom_struct] pub struct Attr { - reflector_: Reflector, + node_: Node, identifier: AttrIdentifier, - value: DOMRefCell<AttrValue>, + value: DomRefCell<AttrValue>, /// the element that owns this attribute. - owner: MutNullableJS<Element>, + owner: MutNullableDom<Element>, } impl Attr { - fn new_inherited(local_name: LocalName, - value: AttrValue, - name: LocalName, - namespace: Namespace, - prefix: Option<Prefix>, - owner: Option<&Element>) - -> Attr { + fn new_inherited( + document: &Document, + local_name: LocalName, + value: AttrValue, + name: LocalName, + namespace: Namespace, + prefix: Option<Prefix>, + owner: Option<&Element>, + ) -> Attr { Attr { - reflector_: Reflector::new(), + node_: Node::new_inherited(document), identifier: AttrIdentifier { - local_name: local_name, - name: name, - namespace: namespace, - prefix: prefix, + local_name: GenericAtomIdent(local_name), + name: GenericAtomIdent(name), + namespace: GenericAtomIdent(namespace), + prefix: prefix.map(GenericAtomIdent), }, - value: DOMRefCell::new(value), - owner: MutNullableJS::new(owner), + value: DomRefCell::new(value), + owner: MutNullableDom::new(owner), } } - pub fn new(window: &Window, - local_name: LocalName, - value: AttrValue, - name: LocalName, - namespace: Namespace, - prefix: Option<Prefix>, - owner: Option<&Element>) - -> Root<Attr> { - reflect_dom_object(box Attr::new_inherited(local_name, - value, - name, - namespace, - prefix, - owner), - window, - AttrBinding::Wrap) + pub fn new( + document: &Document, + local_name: LocalName, + value: AttrValue, + name: LocalName, + namespace: Namespace, + prefix: Option<Prefix>, + owner: Option<&Element>, + ) -> DomRoot<Attr> { + Node::reflect_node( + Box::new(Attr::new_inherited( + document, local_name, value, name, namespace, prefix, owner, + )), + document, + ) } #[inline] pub fn name(&self) -> &LocalName { - &self.identifier.name + &self.identifier.name.0 } #[inline] pub fn namespace(&self) -> &Namespace { - &self.identifier.namespace + &self.identifier.namespace.0 } #[inline] pub fn prefix(&self) -> Option<&Prefix> { - self.identifier.prefix.as_ref() + Some(&self.identifier.prefix.as_ref()?.0) } } @@ -102,49 +106,22 @@ impl AttrMethods for Attr { // https://dom.spec.whatwg.org/#dom-attr-value fn SetValue(&self, value: DOMString) { if let Some(owner) = self.owner() { - let value = owner.parse_attribute(&self.identifier.namespace, - self.local_name(), - value); + let value = owner.parse_attribute(self.namespace(), self.local_name(), value); self.set_value(value, &owner); } else { *self.value.borrow_mut() = AttrValue::String(value.into()); } } - // https://dom.spec.whatwg.org/#dom-attr-textcontent - fn TextContent(&self) -> DOMString { - self.Value() - } - - // https://dom.spec.whatwg.org/#dom-attr-textcontent - fn SetTextContent(&self, value: DOMString) { - self.SetValue(value) - } - - // https://dom.spec.whatwg.org/#dom-attr-nodevalue - fn NodeValue(&self) -> DOMString { - self.Value() - } - - // https://dom.spec.whatwg.org/#dom-attr-nodevalue - fn SetNodeValue(&self, value: DOMString) { - self.SetValue(value) - } - // https://dom.spec.whatwg.org/#dom-attr-name fn Name(&self) -> DOMString { // FIXME(ajeffrey): convert directly from LocalName to DOMString - DOMString::from(&*self.identifier.name) - } - - // https://dom.spec.whatwg.org/#dom-attr-nodename - fn NodeName(&self) -> DOMString { - self.Name() + DOMString::from(&**self.name()) } // https://dom.spec.whatwg.org/#dom-attr-namespaceuri fn GetNamespaceURI(&self) -> Option<DOMString> { - match self.identifier.namespace { + match *self.namespace() { ns!() => None, ref url => Some(DOMString::from(&**url)), } @@ -157,7 +134,7 @@ impl AttrMethods for Attr { } // https://dom.spec.whatwg.org/#dom-attr-ownerelement - fn GetOwnerElement(&self) -> Option<Root<Element>> { + fn GetOwnerElement(&self) -> Option<DomRoot<Element>> { self.owner() } @@ -167,13 +144,34 @@ impl AttrMethods for Attr { } } - impl Attr { pub fn set_value(&self, mut value: AttrValue, owner: &Element) { - assert!(Some(owner) == self.owner().r()); + let name = self.local_name().clone(); + let namespace = self.namespace().clone(); + let old_value = DOMString::from(&**self.value()); + let new_value = DOMString::from(&*value); + let mutation = Mutation::Attribute { + name: name.clone(), + namespace: namespace.clone(), + old_value: Some(old_value.clone()), + }; + + MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation); + + if owner.get_custom_element_definition().is_some() { + let reaction = CallbackReaction::AttributeChanged( + name, + Some(old_value), + Some(new_value), + namespace, + ); + ScriptThread::enqueue_callback_reaction(owner, reaction, None); + } + + assert_eq!(Some(owner), self.owner().as_deref()); owner.will_mutate_attr(self); self.swap_value(&mut value); - if self.identifier.namespace == ns!() { + if *self.namespace() == ns!() { vtable_for(owner.upcast()) .attribute_mutated(self, AttributeMutation::Set(Some(&value))); } @@ -199,79 +197,78 @@ impl Attr { /// Sets the owner element. Should be called after the attribute is added /// or removed from its older parent. pub fn set_owner(&self, owner: Option<&Element>) { - let ns = &self.identifier.namespace; + let ns = self.namespace(); match (self.owner(), owner) { (Some(old), None) => { // Already gone from the list of attributes of old owner. - assert!(old.get_attribute(&ns, &self.identifier.local_name).r() != Some(self)) - } - (Some(old), Some(new)) => assert!(&*old == new), + assert!( + old.get_attribute(&ns, &self.identifier.local_name) + .as_deref() != + Some(self) + ) + }, + (Some(old), Some(new)) => assert_eq!(&*old, new), _ => {}, } self.owner.set(owner); } - pub fn owner(&self) -> Option<Root<Element>> { + pub fn owner(&self) -> Option<DomRoot<Element>> { self.owner.get() } pub fn summarize(&self) -> AttrInfo { AttrInfo { - namespace: (*self.identifier.namespace).to_owned(), + namespace: (**self.namespace()).to_owned(), name: String::from(self.Name()), value: String::from(self.Value()), } } + + pub fn qualified_name(&self) -> DOMString { + match self.prefix() { + Some(ref prefix) => DOMString::from(format!("{}:{}", prefix, &**self.local_name())), + None => DOMString::from(&**self.local_name()), + } + } } #[allow(unsafe_code)] -pub trait AttrHelpersForLayout { - unsafe fn value_forever(&self) -> &'static AttrValue; - unsafe fn value_ref_forever(&self) -> &'static str; - unsafe fn value_atom_forever(&self) -> Option<Atom>; - unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]>; - unsafe fn local_name_atom_forever(&self) -> LocalName; - unsafe fn value_for_layout(&self) -> &AttrValue; +pub trait AttrHelpersForLayout<'dom> { + fn value(self) -> &'dom AttrValue; + fn as_str(self) -> &'dom str; + fn as_tokens(self) -> Option<&'dom [Atom]>; + fn local_name(self) -> &'dom LocalName; + fn namespace(self) -> &'dom Namespace; } #[allow(unsafe_code)] -impl AttrHelpersForLayout for LayoutJS<Attr> { +impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> { #[inline] - unsafe fn value_forever(&self) -> &'static AttrValue { - // This transmute is used to cheat the lifetime restriction. - mem::transmute::<&AttrValue, &AttrValue>((*self.unsafe_get()).value.borrow_for_layout()) + fn value(self) -> &'dom AttrValue { + unsafe { self.unsafe_get().value.borrow_for_layout() } } #[inline] - unsafe fn value_ref_forever(&self) -> &'static str { - &**self.value_forever() - } - - #[inline] - unsafe fn value_atom_forever(&self) -> Option<Atom> { - let value = (*self.unsafe_get()).value.borrow_for_layout(); - match *value { - AttrValue::Atom(ref val) => Some(val.clone()), - _ => None, - } + fn as_str(self) -> &'dom str { + &**self.value() } #[inline] - unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]> { - // This transmute is used to cheat the lifetime restriction. - match *self.value_forever() { + fn as_tokens(self) -> Option<&'dom [Atom]> { + match *self.value() { AttrValue::TokenList(_, ref tokens) => Some(tokens), _ => None, } } #[inline] - unsafe fn local_name_atom_forever(&self) -> LocalName { - (*self.unsafe_get()).identifier.local_name.clone() + fn local_name(self) -> &'dom LocalName { + unsafe { &self.unsafe_get().identifier.local_name.0 } } #[inline] - unsafe fn value_for_layout(&self) -> &AttrValue { - (*self.unsafe_get()).value.borrow_for_layout() + fn namespace(self) -> &'dom Namespace { + unsafe { &self.unsafe_get().identifier.namespace.0 } } } |