Refactor the locate a namespace algorithm

This commit is contained in:
Anthony Ramine 2016-11-30 14:33:42 +01:00
parent fb206e2b10
commit 0c64bd766a
5 changed files with 60 additions and 60 deletions

View file

@ -61,6 +61,7 @@ plugins = {path = "../plugins"}
profile_traits = {path = "../profile_traits"}
rand = "0.3"
range = {path = "../range"}
ref_filter_map = "1.0.1"
ref_slice = "1.0"
regex = "0.1.43"
rustc-serialize = "0.3"

View file

@ -73,6 +73,7 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks};
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
use parking_lot::RwLock;
use ref_filter_map::ref_filter_map;
use selectors::matching::{ElementFlags, MatchingReason, matches};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
@ -722,6 +723,46 @@ impl Element {
Ref::map(self.attrs.borrow(), |attrs| &**attrs)
}
// Element branch of https://dom.spec.whatwg.org/#locate-a-namespace
pub fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
let prefix = prefix.map(String::from).map(LocalName::from);
let inclusive_ancestor_elements =
self.upcast::<Node>()
.inclusive_ancestors()
.filter_map(Root::downcast::<Self>);
// Steps 3-4.
for element in inclusive_ancestor_elements {
// Step 1.
if element.namespace() != &ns!() && element.prefix().map(|p| &**p) == prefix.as_ref().map(|p| &**p) {
return element.namespace().clone();
}
// Step 2.
let attr = ref_filter_map(self.attrs(), |attrs| {
attrs.iter().find(|attr| {
if attr.namespace() != &ns!(xmlns) {
return false;
}
match (attr.prefix(), prefix.as_ref()) {
(Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
attr.local_name() == prefix
},
(None, None) => attr.local_name() == &local_name!("xmlns"),
_ => false,
}
})
});
if let Some(attr) = attr {
return (**attr.value()).into();
}
}
ns!()
}
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>> {
&self.style_attribute
}

View file

@ -7,8 +7,6 @@
use app_units::Au;
use devtools_traits::NodeInfo;
use document_loader::DocumentLoader;
use dom::attr::Attr;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@ -60,7 +58,7 @@ use euclid::rect::Rect;
use euclid::size::Size2D;
use heapsize::{HeapSizeOf, heap_size_of};
use html5ever::tree_builder::QuirksMode;
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
use html5ever_atoms::{Prefix, Namespace, QualName};
use js::jsapi::{JSContext, JSObject, JSRuntime};
use libc::{self, c_void, uintptr_t};
use msg::constellation_msg::PipelineId;
@ -1811,68 +1809,20 @@ impl Node {
// https://dom.spec.whatwg.org/#locate-a-namespace
pub fn locate_namespace(node: &Node, prefix: Option<DOMString>) -> Namespace {
fn attr_defines_namespace(attr: &Attr,
defined_prefix: &Option<LocalName>) -> bool {
*attr.namespace() == ns!(xmlns) &&
match (attr.prefix(), defined_prefix) {
(Some(attr_prefix), &Some(ref defined_prefix)) =>
attr_prefix == &namespace_prefix!("xmlns") &&
attr.local_name() == defined_prefix,
(None, &None) => *attr.local_name() == local_name!("xmlns"),
_ => false
}
}
match node.type_id() {
NodeTypeId::Element(_) => {
let element = node.downcast::<Element>().unwrap();
// Step 1.
if *element.namespace() != ns!() && element.prefix() == prefix.as_ref() {
return element.namespace().clone()
}
// Even though this is conceptually a namespace prefix,
// in the `xmlns:foo="https://example.net/namespace" declaration
// it is a local name.
// FIXME(ajeffrey): directly convert DOMString to LocalName
let prefix_atom = prefix.as_ref().map(|s| LocalName::from(&**s));
// Step 2.
let attrs = element.attrs();
let namespace_attr = attrs.iter().find(|attr| {
attr_defines_namespace(attr, &prefix_atom)
});
// Steps 2.1-2.
if let Some(attr) = namespace_attr {
return namespace_from_domstring(Some(attr.Value()));
}
match node.GetParentElement() {
// Step 3.
None => ns!(),
// Step 4.
Some(parent) => Node::locate_namespace(parent.upcast(), prefix)
}
node.downcast::<Element>().unwrap().locate_namespace(prefix)
},
NodeTypeId::Document(_) => {
match node.downcast::<Document>().unwrap().GetDocumentElement().r() {
// Step 1.
None => ns!(),
// Step 2.
Some(document_element) => {
Node::locate_namespace(document_element.upcast(), prefix)
}
}
node.downcast::<Document>().unwrap()
.GetDocumentElement().as_ref()
.map_or(ns!(), |elem| elem.locate_namespace(prefix))
},
NodeTypeId::DocumentType => ns!(),
NodeTypeId::DocumentFragment => ns!(),
_ => match node.GetParentElement() {
// Step 1.
None => ns!(),
// Step 2.
Some(parent) => Node::locate_namespace(parent.upcast(), prefix)
}
NodeTypeId::DocumentType | NodeTypeId::DocumentFragment => ns!(),
_ => {
node.GetParentElement().as_ref()
.map_or(ns!(), |elem| elem.locate_namespace(prefix))
}
}
}
}

View file

@ -74,6 +74,7 @@ extern crate phf;
extern crate profile_traits;
extern crate rand;
extern crate range;
extern crate ref_filter_map;
extern crate ref_slice;
extern crate regex;
extern crate rustc_serialize;