diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index 18123e4422f..41c4807616b 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -355,6 +355,15 @@ fn collect_elements_with_id( } } +fn has_attr(element: E, local_name: &AtomIdent) -> bool +where + E: TElement, +{ + let mut found = false; + element.each_attr_name(|name| found |= name == local_name); + found +} + #[inline(always)] fn local_name_matches(element: E, local_name: &LocalName) -> bool where @@ -374,6 +383,23 @@ where element.local_name() == &**chosen_name } +fn get_attr_name(component: &Component) -> Option<&AtomIdent> { + let (name, name_lower) = match component { + Component::AttributeInNoNamespace { ref local_name, .. } => return Some(local_name), + Component::AttributeInNoNamespaceExists { + ref local_name, + ref local_name_lower, + .. + } => (local_name, local_name_lower), + Component::AttributeOther(ref attr) => (&attr.local_name, &attr.local_name_lower), + _ => return None, + }; + if name != name_lower { + return None; // TODO: Maybe optimize this? + } + Some(name) +} + fn get_id(component: &Component) -> Option<&AtomIdent> { use selectors::attr::AttrSelectorOperator; Some(match component { @@ -441,6 +467,7 @@ where enum SimpleFilter<'a> { Class(&'a AtomIdent), + Attr(&'a AtomIdent), LocalName(&'a LocalName), } @@ -473,12 +500,16 @@ where let class_and_id_case_sensitivity = matching_context.classes_and_ids_case_sensitivity(); // Let's just care about the easy cases for now. if selector.len() == 1 { - return query_selector_single_query::( + if query_selector_single_query::( root, selector.iter().next().unwrap(), results, class_and_id_case_sensitivity, - ); + ) + .is_ok() + { + return Ok(()); + } } let mut iter = selector.iter(); @@ -577,6 +608,11 @@ where return Ok(()); } + if combinator.is_none() && simple_filter.is_none() { + if let Some(attr_name) = get_attr_name(other) { + simple_filter = Some(SimpleFilter::Attr(attr_name)); + } + } }, } } @@ -621,6 +657,12 @@ where matching::matches_selector_list(selector_list, &element, matching_context) }); }, + SimpleFilter::Attr(ref local_name) => { + collect_all_elements::(root, results, |element| { + has_attr(element, local_name) && + matching::matches_selector_list(selector_list, &element, matching_context) + }); + }, } Ok(())