auto merge of #1867 : saneyuki/servo/1828, r=pcwalton

Fix #1828
This commit is contained in:
bors-servo 2014-03-20 14:10:54 -04:00
commit 0265fb9784
6 changed files with 110 additions and 134 deletions

View file

@ -216,18 +216,17 @@ impl StyleSharingCandidate {
let mut style = Some(style); let mut style = Some(style);
let mut parent_style = Some(parent_style); let mut parent_style = Some(parent_style);
node.with_element(|element| { let element = node.as_element();
if element.style_attribute().is_some() { if element.style_attribute().is_some() {
return None return None
} }
Some(StyleSharingCandidate { Some(StyleSharingCandidate {
style: style.take_unwrap(), style: style.take_unwrap(),
parent_style: parent_style.take_unwrap(), parent_style: parent_style.take_unwrap(),
local_name: element.get_local_name().to_str(), local_name: element.get_local_name().to_str(),
class: element.get_attr(&Null, "class") class: element.get_attr(&Null, "class")
.map(|string| string.to_str()), .map(|string| string.to_str()),
})
}) })
} }
@ -401,7 +400,7 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
} }
// Check tag names, classes, etc. // Check tag names, classes, etc.
if !self.with_element(|element| candidate.can_share_style_with(element)) { if !candidate.can_share_style_with(&self.as_element()) {
return None return None
} }
@ -419,9 +418,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
stylist: &Stylist, stylist: &Stylist,
applicable_declarations: &mut ApplicableDeclarations, applicable_declarations: &mut ApplicableDeclarations,
shareable: &mut bool) { shareable: &mut bool) {
let style_attribute = self.with_element(|element| { let style_attribute = self.as_element().style_attribute().as_ref();
element.style_attribute().as_ref()
});
applicable_declarations.normal_shareable = applicable_declarations.normal_shareable =
stylist.push_applicable_declarations(self, stylist.push_applicable_declarations(self,
@ -448,9 +445,10 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
if !self.is_element() { if !self.is_element() {
return CannotShare(false) return CannotShare(false)
} }
let ok = self.with_element(|element| { let ok = {
let element = self.as_element();
element.style_attribute().is_none() && element.get_attr(&Null, "id").is_none() element.style_attribute().is_none() && element.get_attr(&Null, "id").is_none()
}); };
if !ok { if !ok {
return CannotShare(false) return CannotShare(false)
} }

View file

@ -132,12 +132,11 @@ impl ImageBoxInfo {
local_image_cache: MutexArc<LocalImageCache>) local_image_cache: MutexArc<LocalImageCache>)
-> ImageBoxInfo { -> ImageBoxInfo {
fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option<Au> { fn convert_length(node: &ThreadSafeLayoutNode, name: &str) -> Option<Au> {
node.with_element(|element| { let element = node.as_element();
element.get_attr(&namespace::Null, name).and_then(|string| { element.get_attr(&namespace::Null, name).and_then(|string| {
let n: Option<int> = FromStr::from_str(string); let n: Option<int> = FromStr::from_str(string);
n n
}).and_then(|pixels| Some(Au::from_px(pixels))) }).and_then(|pixels| Some(Au::from_px(pixels)))
})
} }
ImageBoxInfo { ImageBoxInfo {

View file

@ -851,8 +851,8 @@ trait ObjectElement {
impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> {
fn get_type_and_data(&self) -> (Option<&'static str>, Option<&'static str>) { fn get_type_and_data(&self) -> (Option<&'static str>, Option<&'static str>) {
(self.with_element(|e| { e.get_attr(&namespace::Null, "type") } ), let elem = self.as_element();
self.with_element(|e| { e.get_attr(&namespace::Null, "data") } )) (elem.get_attr(&namespace::Null, "type"), elem.get_attr(&namespace::Null, "data"))
} }
fn has_object_data(&self) -> bool { fn has_object_data(&self) -> bool {

View file

@ -34,7 +34,7 @@
//! `html_element_in_html_document_for_layout()`. //! `html_element_in_html_document_for_layout()`.
use extra::url::Url; use extra::url::Url;
use script::dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLIFrameElementDerived}; use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived};
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived}; use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived};
use script::dom::bindings::js::JS; use script::dom::bindings::js::JS;
use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId}; use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId};
@ -228,16 +228,13 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
/// If this is an element, accesses the element data. Fails if this is not an element node. /// If this is an element, accesses the element data. Fails if this is not an element node.
#[inline] #[inline]
fn with_element<R>(&self, f: |&LayoutElement<'ln>| -> R) -> R { fn as_element(&self) -> LayoutElement<'ln> {
unsafe { unsafe {
if !self.node.is_element() {
fail!("not an element!")
}
let elem: JS<Element> = self.node.transmute_copy(); let elem: JS<Element> = self.node.transmute_copy();
let element = elem.get(); let element = elem.get();
f(&LayoutElement { LayoutElement {
element: cast::transmute_region(element), element: cast::transmute_region(element),
}) }
} }
} }
@ -250,23 +247,22 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
} }
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool { fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool {
self.with_element(|element| { let element = self.as_element();
let name = unsafe { let name = unsafe {
if element.element.html_element_in_html_document_for_layout() { if element.element.html_element_in_html_document_for_layout() {
attr.lower_name.as_slice() attr.lower_name.as_slice()
} else { } else {
attr.name.as_slice() attr.name.as_slice()
}
};
match attr.namespace {
SpecificNamespace(ref ns) => {
element.get_attr(ns, name)
.map_or(false, |attr| test(attr))
},
// FIXME: https://github.com/mozilla/servo/issues/1558
AnyNamespace => false,
} }
}) };
match attr.namespace {
SpecificNamespace(ref ns) => {
element.get_attr(ns, name)
.map_or(false, |attr| test(attr))
},
// FIXME: https://github.com/mozilla/servo/issues/1558
AnyNamespace => false,
}
} }
} }
@ -433,18 +429,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
/// If this is an element, accesses the element data. Fails if this is not an element node. /// If this is an element, accesses the element data. Fails if this is not an element node.
#[inline] #[inline]
pub fn with_element<R>(&self, f: |&ThreadSafeLayoutElement| -> R) -> R { pub fn as_element(&self) -> ThreadSafeLayoutElement {
unsafe { unsafe {
if !self.node.is_element() {
fail!("not an element!")
}
let elem: JS<Element> = self.node.transmute_copy(); let elem: JS<Element> = self.node.transmute_copy();
let element = elem.unsafe_get(); let element = elem.unsafe_get();
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
// implementations. // implementations.
f(&ThreadSafeLayoutElement { ThreadSafeLayoutElement {
element: cast::transmute::<*mut Element,&mut Element>(element), element: cast::transmute::<*mut Element,&mut Element>(element),
}) }
} }
} }

View file

@ -15,10 +15,7 @@ pub trait TNode<E:TElement> : Clone {
fn next_sibling(&self) -> Option<Self>; fn next_sibling(&self) -> Option<Self>;
fn is_document(&self) -> bool; fn is_document(&self) -> bool;
fn is_element(&self) -> bool; fn is_element(&self) -> bool;
fn as_element(&self) -> E;
/// FIXME(pcwalton): This should not use the `with` pattern.
fn with_element<'a, R>(&self, f: |&E| -> R) -> R;
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool; fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
} }

View file

@ -117,44 +117,43 @@ impl SelectorMap {
// At the end, we're going to sort the rules that we added, so remember where we began. // At the end, we're going to sort the rules that we added, so remember where we began.
let init_len = matching_rules_list.len(); let init_len = matching_rules_list.len();
node.with_element(|element: &E| { let element = node.as_element();
match element.get_attr(&namespace::Null, "id") { match element.get_attr(&namespace::Null, "id") {
Some(id) => { Some(id) => {
SelectorMap::get_matching_rules_from_hash(node,
&self.id_hash,
id,
matching_rules_list,
shareable)
}
None => {}
}
match element.get_attr(&namespace::Null, "class") {
Some(ref class_attr) => {
for class in class_attr.split(SELECTOR_WHITESPACE) {
SelectorMap::get_matching_rules_from_hash(node, SelectorMap::get_matching_rules_from_hash(node,
&self.id_hash, &self.class_hash,
id, class,
matching_rules_list, matching_rules_list,
shareable) shareable);
} }
None => {}
} }
None => {}
}
match element.get_attr(&namespace::Null, "class") { // HTML elements in HTML documents must be matched case-insensitively.
Some(ref class_attr) => { // TODO(pradeep): Case-sensitivity depends on the document type.
for class in class_attr.split(SELECTOR_WHITESPACE) { SelectorMap::get_matching_rules_from_hash_ignoring_case(node,
SelectorMap::get_matching_rules_from_hash(node, &self.element_hash,
&self.class_hash, element.get_local_name(),
class, matching_rules_list,
matching_rules_list, shareable);
shareable);
}
}
None => {}
}
// HTML elements in HTML documents must be matched case-insensitively. SelectorMap::get_matching_rules(node,
// TODO(pradeep): Case-sensitivity depends on the document type. self.universal_rules,
SelectorMap::get_matching_rules_from_hash_ignoring_case(node, matching_rules_list,
&self.element_hash, shareable);
element.get_local_name(),
matching_rules_list,
shareable);
SelectorMap::get_matching_rules(node,
self.universal_rules,
matching_rules_list,
shareable);
});
// Sort only the rules we just added. // Sort only the rules we just added.
sort::quicksort(matching_rules_list.mut_slice_from(init_len)); sort::quicksort(matching_rules_list.mut_slice_from(init_len));
@ -582,36 +581,32 @@ fn matches_simple_selector<E:TElement,
// TODO: case-sensitivity depends on the document type // TODO: case-sensitivity depends on the document type
// TODO: intern element names // TODO: intern element names
LocalNameSelector(ref name) => { LocalNameSelector(ref name) => {
element.with_element(|element: &E| { let element = element.as_element();
element.get_local_name().eq_ignore_ascii_case(name.as_slice()) element.get_local_name().eq_ignore_ascii_case(name.as_slice())
})
} }
NamespaceSelector(ref namespace) => { NamespaceSelector(ref namespace) => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let element = element.as_element();
element.get_namespace() == namespace element.get_namespace() == namespace
})
} }
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
// TODO: cache and intern IDs on elements. // TODO: cache and intern IDs on elements.
IDSelector(ref id) => { IDSelector(ref id) => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let element = element.as_element();
element.get_attr(&namespace::Null, "id") element.get_attr(&namespace::Null, "id")
.map_or(false, |attr| { .map_or(false, |attr| {
attr == *id attr == *id
})
}) })
} }
// TODO: cache and intern class names on elements. // TODO: cache and intern class names on elements.
ClassSelector(ref class) => { ClassSelector(ref class) => {
element.with_element(|element: &E| { let element = element.as_element();
element.get_attr(&namespace::Null, "class") element.get_attr(&namespace::Null, "class")
.map_or(false, |attr| { .map_or(false, |attr| {
// TODO: case-sensitivity depends on the document type and quirks mode // TODO: case-sensitivity depends on the document type and quirks mode
attr.split(SELECTOR_WHITESPACE).any(|c| c == class.as_slice()) attr.split(SELECTOR_WHITESPACE).any(|c| c == class.as_slice())
})
}) })
} }
@ -663,34 +658,30 @@ fn matches_simple_selector<E:TElement,
AnyLink => { AnyLink => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let element = element.as_element();
element.get_link().is_some() element.get_link().is_some()
})
} }
Link => { Link => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let elem = element.as_element();
match element.get_link() { match elem.get_link() {
Some(url) => !url_is_visited(url), Some(url) => !url_is_visited(url),
None => false, None => false,
} }
})
} }
Visited => { Visited => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let elem = element.as_element();
match element.get_link() { match elem.get_link() {
Some(url) => url_is_visited(url), Some(url) => url_is_visited(url),
None => false, None => false,
} }
})
} }
Hover => { Hover => {
*shareable = false; *shareable = false;
element.with_element(|element: &E| { let elem = element.as_element();
element.get_hover_state() elem.get_hover_state()
})
}, },
FirstChild => { FirstChild => {
*shareable = false; *shareable = false;
@ -791,14 +782,12 @@ fn matches_generic_nth_child<'a,
if node.is_element() { if node.is_element() {
if is_of_type { if is_of_type {
element.with_element(|element: &E| { let element = element.as_element();
node.with_element(|node: &E| { let node = node.as_element();
if element.get_local_name() == node.get_local_name() && if element.get_local_name() == node.get_local_name() &&
element.get_namespace() == node.get_namespace() { element.get_namespace() == node.get_namespace() {
index += 1; index += 1;
} }
})
})
} else { } else {
index += 1; index += 1;
} }