aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/attr.rs')
-rw-r--r--components/script/dom/attr.rs233
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 }
}
}