mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Auto merge of #25310 - pshaughn:attr_node, r=Manishearth
Attr is a Node, with consequences for many Node methods <!-- Please describe your changes on the following line: --> Attr is now a Node, as current WHATWG specs require. I think I did some unidiomatic things to make compareDocumentPosition work and it could use a look by someone more familiar with how to write concise Rust code. I also think the new cases in compareDocumentPosition lack tests; it is possible to compare the position of two attributes, or of an attribute and an element, and I don't think any tests are exercising that functionality. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #25124 <!-- Either: --> - [ ] There are tests for these changes (existing cases of Node methods are well-tested, and there is a WPT test specifically for whether Attr is Node, but I'm not sure about new Node method cases) <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
e185423fc7
9 changed files with 229 additions and 306 deletions
|
@ -5,15 +5,14 @@
|
|||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::AttrBinding::{self, AttrMethods};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
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::dom::window::Window;
|
||||
use crate::script_thread::ScriptThread;
|
||||
use devtools_traits::AttrInfo;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -27,7 +26,7 @@ use style::attr::{AttrIdentifier, AttrValue};
|
|||
// https://dom.spec.whatwg.org/#interface-attr
|
||||
#[dom_struct]
|
||||
pub struct Attr {
|
||||
reflector_: Reflector,
|
||||
node_: Node,
|
||||
identifier: AttrIdentifier,
|
||||
value: DomRefCell<AttrValue>,
|
||||
|
||||
|
@ -37,6 +36,7 @@ pub struct Attr {
|
|||
|
||||
impl Attr {
|
||||
fn new_inherited(
|
||||
document: &Document,
|
||||
local_name: LocalName,
|
||||
value: AttrValue,
|
||||
name: LocalName,
|
||||
|
@ -45,7 +45,7 @@ impl Attr {
|
|||
owner: Option<&Element>,
|
||||
) -> Attr {
|
||||
Attr {
|
||||
reflector_: Reflector::new(),
|
||||
node_: Node::new_inherited(document),
|
||||
identifier: AttrIdentifier {
|
||||
local_name: local_name,
|
||||
name: name,
|
||||
|
@ -58,7 +58,7 @@ impl Attr {
|
|||
}
|
||||
|
||||
pub fn new(
|
||||
window: &Window,
|
||||
document: &Document,
|
||||
local_name: LocalName,
|
||||
value: AttrValue,
|
||||
name: LocalName,
|
||||
|
@ -66,11 +66,11 @@ impl Attr {
|
|||
prefix: Option<Prefix>,
|
||||
owner: Option<&Element>,
|
||||
) -> DomRoot<Attr> {
|
||||
reflect_dom_object(
|
||||
Node::reflect_node(
|
||||
Box::new(Attr::new_inherited(
|
||||
local_name, value, name, namespace, prefix, owner,
|
||||
document, local_name, value, name, namespace, prefix, owner,
|
||||
)),
|
||||
window,
|
||||
document,
|
||||
AttrBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
@ -114,37 +114,12 @@ impl AttrMethods for Attr {
|
|||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-attr-namespaceuri
|
||||
fn GetNamespaceURI(&self) -> Option<DOMString> {
|
||||
match self.identifier.namespace {
|
||||
|
@ -250,6 +225,13 @@ impl Attr {
|
|||
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)]
|
||||
|
|
|
@ -3698,7 +3698,7 @@ impl DocumentMethods for Document {
|
|||
let value = AttrValue::String("".to_owned());
|
||||
|
||||
Ok(Attr::new(
|
||||
&self.window,
|
||||
&self,
|
||||
name.clone(),
|
||||
value,
|
||||
name,
|
||||
|
@ -3718,7 +3718,7 @@ impl DocumentMethods for Document {
|
|||
let value = AttrValue::String("".to_owned());
|
||||
let qualified_name = LocalName::from(qualified_name);
|
||||
Ok(Attr::new(
|
||||
&self.window,
|
||||
&self,
|
||||
local_name,
|
||||
value,
|
||||
qualified_name,
|
||||
|
|
|
@ -1336,9 +1336,8 @@ impl Element {
|
|||
namespace: Namespace,
|
||||
prefix: Option<Prefix>,
|
||||
) {
|
||||
let window = window_from_node(self);
|
||||
let attr = Attr::new(
|
||||
&window,
|
||||
&self.node.owner_doc(),
|
||||
local_name,
|
||||
value,
|
||||
name,
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
|
||||
|
||||
use crate::document_loader::DocumentLoader;
|
||||
use crate::dom::attr::Attr;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||
|
@ -1764,6 +1766,7 @@ impl Node {
|
|||
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => (),
|
||||
NodeTypeId::Document(_) => return Err(Error::HierarchyRequest),
|
||||
NodeTypeId::Attr => unreachable!(),
|
||||
}
|
||||
|
||||
// Step 6.
|
||||
|
@ -1833,6 +1836,7 @@ impl Node {
|
|||
},
|
||||
NodeTypeId::CharacterData(_) => (),
|
||||
NodeTypeId::Document(_) => unreachable!(),
|
||||
NodeTypeId::Attr => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -2118,6 +2122,19 @@ impl Node {
|
|||
);
|
||||
DomRoot::upcast::<Node>(doctype)
|
||||
},
|
||||
NodeTypeId::Attr => {
|
||||
let attr = node.downcast::<Attr>().unwrap();
|
||||
let attr = Attr::new(
|
||||
&document,
|
||||
attr.local_name().clone(),
|
||||
attr.value().clone(),
|
||||
attr.name().clone(),
|
||||
attr.namespace().clone(),
|
||||
attr.prefix().cloned(),
|
||||
None,
|
||||
);
|
||||
DomRoot::upcast::<Node>(attr)
|
||||
},
|
||||
NodeTypeId::DocumentFragment(_) => {
|
||||
let doc_fragment = DocumentFragment::new(&document);
|
||||
DomRoot::upcast::<Node>(doc_fragment)
|
||||
|
@ -2250,6 +2267,12 @@ impl Node {
|
|||
pub fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
|
||||
match node.type_id() {
|
||||
NodeTypeId::Element(_) => node.downcast::<Element>().unwrap().locate_namespace(prefix),
|
||||
NodeTypeId::Attr => node
|
||||
.downcast::<Attr>()
|
||||
.unwrap()
|
||||
.GetOwnerElement()
|
||||
.as_ref()
|
||||
.map_or(ns!(), |elem| elem.locate_namespace(prefix)),
|
||||
NodeTypeId::Document(_) => node
|
||||
.downcast::<Document>()
|
||||
.unwrap()
|
||||
|
@ -2269,6 +2292,7 @@ impl NodeMethods for Node {
|
|||
// https://dom.spec.whatwg.org/#dom-node-nodetype
|
||||
fn NodeType(&self) -> u16 {
|
||||
match self.type_id() {
|
||||
NodeTypeId::Attr => NodeConstants::ATTRIBUTE_NODE,
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
|
||||
NodeConstants::TEXT_NODE
|
||||
},
|
||||
|
@ -2289,6 +2313,7 @@ impl NodeMethods for Node {
|
|||
// https://dom.spec.whatwg.org/#dom-node-nodename
|
||||
fn NodeName(&self) -> DOMString {
|
||||
match self.type_id() {
|
||||
NodeTypeId::Attr => self.downcast::<Attr>().unwrap().qualified_name(),
|
||||
NodeTypeId::Element(..) => self.downcast::<Element>().unwrap().TagName(),
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
|
||||
DOMString::from("#text")
|
||||
|
@ -2319,11 +2344,8 @@ impl NodeMethods for Node {
|
|||
// https://dom.spec.whatwg.org/#dom-node-ownerdocument
|
||||
fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
|
||||
match self.type_id() {
|
||||
NodeTypeId::CharacterData(..) |
|
||||
NodeTypeId::Element(..) |
|
||||
NodeTypeId::DocumentType |
|
||||
NodeTypeId::DocumentFragment(_) => Some(self.owner_doc()),
|
||||
NodeTypeId::Document(_) => None,
|
||||
_ => Some(self.owner_doc()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2393,13 +2415,27 @@ impl NodeMethods for Node {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-node-nodevalue
|
||||
fn GetNodeValue(&self) -> Option<DOMString> {
|
||||
self.downcast::<CharacterData>().map(CharacterData::Data)
|
||||
match self.type_id() {
|
||||
NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
|
||||
NodeTypeId::CharacterData(_) => {
|
||||
self.downcast::<CharacterData>().map(CharacterData::Data)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-node-nodevalue
|
||||
fn SetNodeValue(&self, val: Option<DOMString>) {
|
||||
if let Some(character_data) = self.downcast::<CharacterData>() {
|
||||
character_data.SetData(val.unwrap_or_default());
|
||||
match self.type_id() {
|
||||
NodeTypeId::Attr => {
|
||||
let attr = self.downcast::<Attr>().unwrap();
|
||||
attr.SetValue(val.unwrap_or_default());
|
||||
},
|
||||
NodeTypeId::CharacterData(_) => {
|
||||
let character_data = self.downcast::<CharacterData>().unwrap();
|
||||
character_data.SetData(val.unwrap_or_default());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2411,6 +2447,7 @@ impl NodeMethods for Node {
|
|||
Node::collect_text_contents(self.traverse_preorder(ShadowIncluding::No));
|
||||
Some(content)
|
||||
},
|
||||
NodeTypeId::Attr => Some(self.downcast::<Attr>().unwrap().Value()),
|
||||
NodeTypeId::CharacterData(..) => {
|
||||
let characterdata = self.downcast::<CharacterData>().unwrap();
|
||||
Some(characterdata.Data())
|
||||
|
@ -2434,6 +2471,10 @@ impl NodeMethods for Node {
|
|||
// Step 3.
|
||||
Node::replace_all(node.as_deref(), self);
|
||||
},
|
||||
NodeTypeId::Attr => {
|
||||
let attr = self.downcast::<Attr>().unwrap();
|
||||
attr.SetValue(value);
|
||||
},
|
||||
NodeTypeId::CharacterData(..) => {
|
||||
let characterdata = self.downcast::<CharacterData>().unwrap();
|
||||
characterdata.SetData(value);
|
||||
|
@ -2532,6 +2573,7 @@ impl NodeMethods for Node {
|
|||
},
|
||||
NodeTypeId::CharacterData(..) => (),
|
||||
NodeTypeId::Document(_) => unreachable!(),
|
||||
NodeTypeId::Attr => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2588,6 +2630,7 @@ impl NodeMethods for Node {
|
|||
prev: previous_sibling.as_deref(),
|
||||
next: reference_child,
|
||||
};
|
||||
|
||||
MutationObserver::queue_a_mutation_record(&self, mutation);
|
||||
|
||||
// Step 15.
|
||||
|
@ -2676,6 +2719,13 @@ impl NodeMethods for Node {
|
|||
let other_characterdata = other.downcast::<CharacterData>().unwrap();
|
||||
*characterdata.data() == *other_characterdata.data()
|
||||
}
|
||||
fn is_equal_attr(node: &Node, other: &Node) -> bool {
|
||||
let attr = node.downcast::<Attr>().unwrap();
|
||||
let other_attr = other.downcast::<Attr>().unwrap();
|
||||
(*attr.namespace() == *other_attr.namespace()) &&
|
||||
(attr.local_name() == other_attr.local_name()) &&
|
||||
(**attr.value() == **other_attr.value())
|
||||
}
|
||||
fn is_equal_element_attrs(node: &Node, other: &Node) -> bool {
|
||||
let element = node.downcast::<Element>().unwrap();
|
||||
let other_element = other.downcast::<Element>().unwrap();
|
||||
|
@ -2688,6 +2738,7 @@ impl NodeMethods for Node {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn is_equal_node(this: &Node, node: &Node) -> bool {
|
||||
// Step 2.
|
||||
if this.NodeType() != node.NodeType() {
|
||||
|
@ -2711,6 +2762,8 @@ impl NodeMethods for Node {
|
|||
}
|
||||
// Step 4.
|
||||
NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false,
|
||||
NodeTypeId::Attr if !is_equal_attr(this, node) => return false,
|
||||
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
@ -2747,65 +2800,154 @@ impl NodeMethods for Node {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// FIXME(emilio): This will eventually need to handle attribute nodes.
|
||||
// step 2
|
||||
let mut node1 = Some(other);
|
||||
let mut node2 = Some(self);
|
||||
|
||||
let mut self_and_ancestors = self
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.collect::<SmallVec<[_; 20]>>();
|
||||
let mut other_and_ancestors = other
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.collect::<SmallVec<[_; 20]>>();
|
||||
// step 3
|
||||
let mut attr1: Option<&Attr> = None;
|
||||
let mut attr2: Option<&Attr> = None;
|
||||
|
||||
if self_and_ancestors.last() != other_and_ancestors.last() {
|
||||
let random = as_uintptr(self_and_ancestors.last().unwrap()) <
|
||||
as_uintptr(other_and_ancestors.last().unwrap());
|
||||
let random = if random {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING
|
||||
};
|
||||
|
||||
// Disconnected.
|
||||
return random +
|
||||
NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
|
||||
NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
|
||||
}
|
||||
|
||||
let mut parent = self_and_ancestors.pop().unwrap();
|
||||
other_and_ancestors.pop().unwrap();
|
||||
|
||||
let mut current_position = cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
|
||||
|
||||
while current_position > 0 {
|
||||
current_position -= 1;
|
||||
let child_1 = self_and_ancestors.pop().unwrap();
|
||||
let child_2 = other_and_ancestors.pop().unwrap();
|
||||
|
||||
if child_1 != child_2 {
|
||||
let is_before = parent.children().position(|c| c == child_1).unwrap() <
|
||||
parent.children().position(|c| c == child_2).unwrap();
|
||||
// If I am before, `other` is following, and the other way
|
||||
// around.
|
||||
return if is_before {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING
|
||||
};
|
||||
// step 4: spec says to operate on node1 here,
|
||||
// node1 is definitely Some(other) going into this step
|
||||
// The compiler doesn't know the lifetime of attr1.GetOwnerElement
|
||||
// is guaranteed by the lifetime of attr1, so we hold it explicitly
|
||||
let attr1owner;
|
||||
if let Some(ref a) = other.downcast::<Attr>() {
|
||||
attr1 = Some(a);
|
||||
attr1owner = a.GetOwnerElement();
|
||||
node1 = match attr1owner {
|
||||
Some(ref e) => Some(&e.upcast()),
|
||||
None => None,
|
||||
}
|
||||
|
||||
parent = child_1;
|
||||
}
|
||||
|
||||
// We hit the end of one of the parent chains, so one node needs to be
|
||||
// contained in the other.
|
||||
//
|
||||
// If we're the container, return that `other` is contained by us.
|
||||
return if self_and_ancestors.len() < other_and_ancestors.len() {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING +
|
||||
NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING + NodeConstants::DOCUMENT_POSITION_CONTAINS
|
||||
};
|
||||
// step 5.1: spec says to operate on node2 here,
|
||||
// node2 is definitely just Some(self) going into this step
|
||||
let attr2owner;
|
||||
if let Some(ref a) = self.downcast::<Attr>() {
|
||||
attr2 = Some(a);
|
||||
attr2owner = a.GetOwnerElement();
|
||||
node2 = match attr2owner {
|
||||
Some(ref e) => Some(&*e.upcast()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5.2
|
||||
// This substep seems lacking in test coverage.
|
||||
// We hit this when comparing two attributes that have the
|
||||
// same owner element.
|
||||
if let Some(node2) = node2 {
|
||||
if Some(node2) == node1 {
|
||||
match (attr1, attr2) {
|
||||
(Some(a1), Some(a2)) => {
|
||||
let attrs = node2.downcast::<Element>().unwrap().attrs();
|
||||
// go through the attrs in order to see if self
|
||||
// or other is first; spec is clear that we
|
||||
// want value-equality, not reference-equality
|
||||
for attr in attrs.iter() {
|
||||
if (*attr.namespace() == *a1.namespace()) &&
|
||||
(attr.local_name() == a1.local_name()) &&
|
||||
(**attr.value() == **a1.value())
|
||||
{
|
||||
return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING;
|
||||
}
|
||||
if (*attr.namespace() == *a2.namespace()) &&
|
||||
(attr.local_name() == a2.local_name()) &&
|
||||
(**attr.value() == **a2.value())
|
||||
{
|
||||
return NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC +
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING;
|
||||
}
|
||||
}
|
||||
// both attrs have node2 as their owner element, so
|
||||
// we can't have left the loop without seeing them
|
||||
unreachable!();
|
||||
},
|
||||
(_, _) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6
|
||||
match (node1, node2) {
|
||||
(None, _) => {
|
||||
// node1 is null
|
||||
return NodeConstants::DOCUMENT_POSITION_FOLLOWING +
|
||||
NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
|
||||
NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
|
||||
},
|
||||
(_, None) => {
|
||||
// node2 is null
|
||||
return NodeConstants::DOCUMENT_POSITION_PRECEDING +
|
||||
NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
|
||||
NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
|
||||
},
|
||||
(Some(node1), Some(node2)) => {
|
||||
// still step 6, testing if node1 and 2 share a root
|
||||
let mut self_and_ancestors = node2
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.collect::<SmallVec<[_; 20]>>();
|
||||
let mut other_and_ancestors = node1
|
||||
.inclusive_ancestors(ShadowIncluding::No)
|
||||
.collect::<SmallVec<[_; 20]>>();
|
||||
|
||||
if self_and_ancestors.last() != other_and_ancestors.last() {
|
||||
let random = as_uintptr(self_and_ancestors.last().unwrap()) <
|
||||
as_uintptr(other_and_ancestors.last().unwrap());
|
||||
let random = if random {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING
|
||||
};
|
||||
|
||||
// Disconnected.
|
||||
return random +
|
||||
NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
|
||||
NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
|
||||
}
|
||||
// steps 7-10
|
||||
let mut parent = self_and_ancestors.pop().unwrap();
|
||||
other_and_ancestors.pop().unwrap();
|
||||
|
||||
let mut current_position =
|
||||
cmp::min(self_and_ancestors.len(), other_and_ancestors.len());
|
||||
|
||||
while current_position > 0 {
|
||||
current_position -= 1;
|
||||
let child_1 = self_and_ancestors.pop().unwrap();
|
||||
let child_2 = other_and_ancestors.pop().unwrap();
|
||||
|
||||
if child_1 != child_2 {
|
||||
let is_before = parent.children().position(|c| c == child_1).unwrap() <
|
||||
parent.children().position(|c| c == child_2).unwrap();
|
||||
// If I am before, `other` is following, and the other way
|
||||
// around.
|
||||
return if is_before {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING
|
||||
};
|
||||
}
|
||||
|
||||
parent = child_1;
|
||||
}
|
||||
|
||||
// We hit the end of one of the parent chains, so one node needs to be
|
||||
// contained in the other.
|
||||
//
|
||||
// If we're the container, return that `other` is contained by us.
|
||||
return if self_and_ancestors.len() < other_and_ancestors.len() {
|
||||
NodeConstants::DOCUMENT_POSITION_FOLLOWING +
|
||||
NodeConstants::DOCUMENT_POSITION_CONTAINED_BY
|
||||
} else {
|
||||
NodeConstants::DOCUMENT_POSITION_PRECEDING +
|
||||
NodeConstants::DOCUMENT_POSITION_CONTAINS
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-node-contains
|
||||
|
@ -2834,6 +2976,11 @@ impl NodeMethods for Node {
|
|||
.GetDocumentElement()
|
||||
.and_then(|element| element.lookup_prefix(namespace)),
|
||||
NodeTypeId::DocumentType | NodeTypeId::DocumentFragment(_) => None,
|
||||
NodeTypeId::Attr => self
|
||||
.downcast::<Attr>()
|
||||
.unwrap()
|
||||
.GetOwnerElement()
|
||||
.and_then(|element| element.lookup_prefix(namespace)),
|
||||
_ => self
|
||||
.GetParentElement()
|
||||
.and_then(|element| element.lookup_prefix(namespace)),
|
||||
|
|
|
@ -986,6 +986,7 @@ impl RangeMethods for Range {
|
|||
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => node.GetParentElement(),
|
||||
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) |
|
||||
NodeTypeId::DocumentType => unreachable!(),
|
||||
NodeTypeId::Attr => unreachable!(),
|
||||
};
|
||||
|
||||
// Step 2.
|
||||
|
|
|
@ -253,6 +253,7 @@ impl<'a> Serialize for &'a Node {
|
|||
|
||||
NodeTypeId::Document(_) => panic!("Can't serialize Document node itself"),
|
||||
NodeTypeId::Element(_) => panic!("Element shouldn't appear here"),
|
||||
NodeTypeId::Attr => panic!("Attr shouldn't appear here"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
[Exposed=Window]
|
||||
interface Attr {
|
||||
interface Attr : Node {
|
||||
[Constant]
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
[Constant]
|
||||
|
@ -17,14 +17,8 @@ interface Attr {
|
|||
readonly attribute DOMString localName;
|
||||
[Constant]
|
||||
readonly attribute DOMString name;
|
||||
[Constant]
|
||||
readonly attribute DOMString nodeName; // historical alias of .name
|
||||
[CEReactions, Pure]
|
||||
attribute DOMString value;
|
||||
[CEReactions, Pure]
|
||||
attribute DOMString textContent; // historical alias of .value
|
||||
[CEReactions, Pure]
|
||||
attribute DOMString nodeValue; // historical alias of .value
|
||||
|
||||
[Pure]
|
||||
readonly attribute Element? ownerElement;
|
||||
|
|
|
@ -1,176 +1,3 @@
|
|||
[idlharness.window.html?include=Node]
|
||||
[Node interface: calling isSameNode(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "TEXT_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling removeChild(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling isEqualNode(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "lookupPrefix(DOMString)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "nextSibling" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "isConnected" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "isSameNode(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "nodeType" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling replaceChild(Node, Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_FOLLOWING" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling getRootNode(GetRootNodeOptions) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "cloneNode(boolean)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "ENTITY_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling contains(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "CDATA_SECTION_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling cloneNode(boolean) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "appendChild(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "parentNode" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "removeChild(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling lookupPrefix(DOMString) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "PROCESSING_INSTRUCTION_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "baseURI" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_DISCONNECTED" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "compareDocumentPosition(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "replaceChild(Node, Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_PRECEDING" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "isEqualNode(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "COMMENT_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "ATTRIBUTE_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_CONTAINS" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "childNodes" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "parentElement" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "isDefaultNamespace(DOMString)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling isDefaultNamespace(DOMString) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "ownerDocument" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling appendChild(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling insertBefore(Node, Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "ELEMENT_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_POSITION_CONTAINED_BY" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "lookupNamespaceURI(DOMString)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling lookupNamespaceURI(DOMString) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "firstChild" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "normalize()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_FRAGMENT_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "contains(Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "getRootNode(GetRootNodeOptions)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "DOCUMENT_TYPE_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "hasChildNodes()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "lastChild" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "previousSibling" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "insertBefore(Node, Node)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: calling compareDocumentPosition(Node) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "ENTITY_REFERENCE_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "NOTATION_NODE" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.window.html?exclude=Node]
|
||||
[EventTarget interface: new AbortController().signal must inherit property "addEventListener(DOMString, EventListener, [object Object\],[object Object\])" with the proper type]
|
||||
expected: FAIL
|
||||
|
@ -265,9 +92,6 @@
|
|||
[AbortController interface: attribute signal]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: document.querySelector("[id\]").attributes[0\] must inherit property "dispatchEvent(Event)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: calling attachShadow(ShadowRootInit) on element with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -292,9 +116,6 @@
|
|||
[Event interface: operation composedPath()]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: calling dispatchEvent(Event) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[AbstractRange interface: attribute endContainer]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -304,9 +125,6 @@
|
|||
[AbortController interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: document.querySelector("[id\]").attributes[0\] must inherit property "removeEventListener(DOMString, EventListener, [object Object\],[object Object\])" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[CharacterData interface: operation remove()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -409,9 +227,6 @@
|
|||
[AbortSignal interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object\],[object Object\]) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Document interface: xmlDoc must inherit property "origin" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -424,9 +239,6 @@
|
|||
[AbortSignal interface: attribute onabort]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object\],[object Object\]) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[AbortSignal interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -460,9 +272,6 @@
|
|||
[CharacterData interface: operation before([object Object\],[object Object\])]
|
||||
expected: FAIL
|
||||
|
||||
[EventTarget interface: document.querySelector("[id\]").attributes[0\] must inherit property "addEventListener(DOMString, EventListener, [object Object\],[object Object\])" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Stringification of new AbortController()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -475,9 +284,6 @@
|
|||
[Event interface: document.createEvent("Event") must inherit property "composed" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Attr interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[DocumentType interface: operation remove()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -487,9 +293,6 @@
|
|||
[Element interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[Attr interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: operation replaceWith([object Object\],[object Object\])]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[Document-importNode.html]
|
||||
[Import an Attr node with namespace/prefix correctly.]
|
||||
expected: FAIL
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue