merge from master

This commit is contained in:
rohan.prinja 2015-11-03 19:01:23 +09:00
commit 6e774ea6eb
1044 changed files with 46059 additions and 1506 deletions

View file

@ -19,12 +19,14 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId};
use dom::bindings::codegen::UnionTypes::NodeOrString;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::trace::JSTraceable;
use dom::bindings::xmlname::XMLName::InvalidXMLName;
use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
use dom::characterdata::CharacterData;
@ -40,7 +42,8 @@ use dom::htmlcollection::HTMLCollection;
use dom::htmlfieldsetelement::HTMLFieldSetElement;
use dom::htmlfontelement::HTMLFontElement;
use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use dom::htmllabelelement::HTMLLabelElement;
use dom::htmllegendelement::HTMLLegendElement;
use dom::htmloptgroupelement::HTMLOptGroupElement;
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementLayoutHelpers};
@ -62,8 +65,8 @@ use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks};
use selectors::matching::{DeclarationBlock, matches};
use selectors::parser::parse_author_origin_selector_list_from_str;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use selectors::parser::{AttrSelector, NamespaceConstraint, parse_author_origin_selector_list_from_str};
use selectors::states::*;
use smallvec::VecLike;
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
@ -77,28 +80,14 @@ use style::properties::DeclaredValue;
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
use style::values::CSSFloat;
use style::values::specified::{self, CSSColor, CSSRGBA};
use style::values::specified::{self, CSSColor, CSSRGBA, LengthOrPercentage};
use url::UrlParser;
use util::mem::HeapSizeOf;
use util::str::{DOMString, LengthOrPercentageOrAuto};
bitflags! {
#[doc = "Element Event States."]
#[derive(JSTraceable, HeapSizeOf)]
flags EventState: u8 {
#[doc = "The mouse is down on this element. \
(https://html.spec.whatwg.org/multipage/#selector-active). \
FIXME(#7333): set/unset this when appropriate"]
const IN_ACTIVE_STATE = 0x01,
#[doc = "This element has focus."]
const IN_FOCUS_STATE = 0x02,
#[doc = "The mouse is hovering over this element."]
const IN_HOVER_STATE = 0x04,
#[doc = "Content is enabled (and can be disabled)."]
const IN_ENABLED_STATE = 0x08,
#[doc = "Content is disabled."]
const IN_DISABLED_STATE = 0x10,
}
}
// TODO: Update focus state when the top-level browsing context gains or loses system focus,
// and when the element enters or leaves a browsing context container.
// https://html.spec.whatwg.org/multipage/#selector-focus
#[dom_struct]
pub struct Element {
@ -111,7 +100,7 @@ pub struct Element {
style_attribute: DOMRefCell<Option<PropertyDeclarationBlock>>,
attr_list: MutNullableHeap<JS<NamedNodeMap>>,
class_list: MutNullableHeap<JS<DOMTokenList>>,
event_state: Cell<EventState>,
state: Cell<ElementState>,
}
impl PartialEq for Element {
@ -140,11 +129,11 @@ impl Element {
pub fn new_inherited(local_name: DOMString,
namespace: Namespace, prefix: Option<DOMString>,
document: &Document) -> Element {
Element::new_inherited_with_state(EventState::empty(), local_name,
Element::new_inherited_with_state(ElementState::empty(), local_name,
namespace, prefix, document)
}
pub fn new_inherited_with_state(state: EventState, local_name: DOMString,
pub fn new_inherited_with_state(state: ElementState, local_name: DOMString,
namespace: Namespace, prefix: Option<DOMString>,
document: &Document)
-> Element {
@ -154,11 +143,11 @@ impl Element {
namespace: namespace,
prefix: prefix,
attrs: DOMRefCell::new(vec!()),
attr_list: Default::default(),
class_list: Default::default(),
id_attribute: DOMRefCell::new(None),
style_attribute: DOMRefCell::new(None),
event_state: Cell::new(state),
attr_list: Default::default(),
class_list: Default::default(),
state: Cell::new(state),
}
}
@ -188,7 +177,7 @@ pub unsafe fn get_attr_for_layout<'a>(elem: &'a Element, namespace: &Namespace,
-> Option<LayoutJS<Attr>> {
// cast to point to T in RefCell<T> directly
let attrs = elem.attrs.borrow_for_layout();
attrs.iter().find(|attr: & &JS<Attr>| {
attrs.iter().find(|attr| {
let attr = attr.to_layout();
*name == attr.local_name_atom_forever() &&
(*attr.unsafe_get()).namespace() == namespace
@ -215,7 +204,7 @@ impl RawLayoutElementHelpers for Element {
#[inline]
unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &Atom) -> Vec<&'a str> {
let attrs = self.attrs.borrow_for_layout();
(*attrs).iter().filter_map(|attr: &JS<Attr>| {
attrs.iter().filter_map(|attr| {
let attr = attr.to_layout();
if *name == attr.local_name_atom_forever() {
Some(attr.value_ref_forever())
@ -251,7 +240,7 @@ pub trait LayoutElementHelpers {
fn get_checked_state_for_layout(&self) -> bool;
fn get_indeterminate_state_for_layout(&self) -> bool;
fn get_event_state_for_layout(&self) -> EventState;
fn get_state_for_layout(&self) -> ElementState;
}
impl LayoutElementHelpers for LayoutJS<Element> {
@ -358,7 +347,8 @@ impl LayoutElementHelpers for LayoutJS<Element> {
hints.push(from_declaration(
PropertyDeclaration::FontSize(
DeclaredValue::Value(
font_size::SpecifiedValue(font_size)))))
font_size::SpecifiedValue(
LengthOrPercentage::Length(font_size))))))
}
let cellspacing = if let Some(this) = self.downcast::<HTMLTableElement>() {
@ -384,7 +374,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// a text field
match (*self.unsafe_get()).get_attr_val_for_layout(&ns!(""), &atom!("type")) {
Some("text") | Some("password") => {
match (*this.unsafe_get()).get_size_for_layout() {
match this.get_size_for_layout() {
0 => None,
s => Some(s as i32),
}
@ -584,7 +574,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// TODO option and menuitem can also have a checked state.
match self.downcast::<HTMLInputElement>() {
Some(input) => unsafe {
(*input.unsafe_get()).get_checked_state_for_layout()
input.get_checked_state_for_layout()
},
None => false,
}
@ -596,7 +586,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// TODO progress elements can also be matched with :indeterminate
match self.downcast::<HTMLInputElement>() {
Some(input) => unsafe {
(*input.unsafe_get()).get_indeterminate_state_for_layout()
input.get_indeterminate_state_for_layout()
},
None => false,
}
@ -604,9 +594,9 @@ impl LayoutElementHelpers for LayoutJS<Element> {
#[inline]
#[allow(unsafe_code)]
fn get_event_state_for_layout(&self) -> EventState {
fn get_state_for_layout(&self) -> ElementState {
unsafe {
(*self.unsafe_get()).event_state.get()
(*self.unsafe_get()).state.get()
}
}
}
@ -886,16 +876,15 @@ impl Element {
}
pub fn get_attribute(&self, namespace: &Namespace, local_name: &Atom) -> Option<Root<Attr>> {
self.attrs.borrow().iter().map(JS::root).find(|attr| {
self.attrs.borrow().iter().find(|attr| {
attr.local_name() == local_name && attr.namespace() == namespace
})
}).map(|js| Root::from_ref(&**js))
}
// https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
pub fn get_attribute_by_name(&self, name: DOMString) -> Option<Root<Attr>> {
let name = &self.parsed_name(name);
self.attrs.borrow().iter().map(JS::root)
.find(|a| a.r().name() == name)
self.attrs.borrow().iter().find(|a| a.name() == name).map(|js| Root::from_ref(&**js))
}
pub fn set_attribute_from_parser(&self,
@ -903,8 +892,8 @@ impl Element {
value: DOMString,
prefix: Option<Atom>) {
// Don't set if the attribute already exists, so we can handle add_attrs_if_missing
if self.attrs.borrow().iter().map(JS::root)
.any(|a| *a.r().local_name() == qname.local && *a.r().namespace() == qname.ns) {
if self.attrs.borrow().iter()
.any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns) {
return;
}
@ -954,7 +943,8 @@ impl Element {
find: F)
where F: Fn(&Attr)
-> bool {
let attr = self.attrs.borrow().iter().map(JS::root).find(|attr| find(&attr));
let attr = self.attrs.borrow().iter()
.find(|attr| find(&attr)).map(|js| Root::from_ref(&**js));
if let Some(attr) = attr {
attr.set_value(value, self);
} else {
@ -985,10 +975,10 @@ impl Element {
fn remove_first_matching_attribute<F>(&self, find: F) -> Option<Root<Attr>>
where F: Fn(&Attr) -> bool
{
let idx = self.attrs.borrow().iter().map(JS::root).position(|attr| find(&attr));
let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
idx.map(|idx| {
let attr = (*self.attrs.borrow())[idx].root();
let attr = Root::from_ref(&*(*self.attrs.borrow())[idx]);
self.attrs.borrow_mut().remove(idx);
attr.set_owner(None);
if attr.namespace() == &ns!("") {
@ -1017,8 +1007,8 @@ impl Element {
pub fn has_attribute(&self, local_name: &Atom) -> bool {
assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b));
self.attrs.borrow().iter().map(JS::root).any(|attr| {
attr.r().local_name() == local_name && attr.r().namespace() == &ns!("")
self.attrs.borrow().iter().any(|attr| {
attr.local_name() == local_name && attr.namespace() == &ns!("")
})
}
@ -1582,6 +1572,16 @@ impl VirtualMethods for Element {
}
}
macro_rules! state_getter {
($(
$(#[$Flag_attr: meta])*
state $css: expr => $variant: ident / $method: ident /
$flag: ident = $value: expr,
)+) => {
$( fn $method(&self) -> bool { Element::get_state(self).contains($flag) } )+
}
}
impl<'a> ::selectors::Element for Root<Element> {
fn parent_element(&self) -> Option<Root<Element>> {
self.upcast::<Node>().GetParentElement()
@ -1648,42 +1648,11 @@ impl<'a> ::selectors::Element for Root<Element> {
self.namespace()
}
fn get_hover_state(&self) -> bool {
Element::get_hover_state(self)
}
fn get_active_state(&self) -> bool {
Element::get_active_state(self)
}
fn get_focus_state(&self) -> bool {
// TODO: Also check whether the top-level browsing context has the system focus,
// and whether this element is a browsing context container.
// https://html.spec.whatwg.org/multipage/#selector-focus
Element::get_focus_state(self)
}
state_pseudo_classes!(state_getter);
fn get_id(&self) -> Option<Atom> {
self.id_attribute.borrow().clone()
}
fn get_disabled_state(&self) -> bool {
Element::get_disabled_state(self)
}
fn get_enabled_state(&self) -> bool {
Element::get_enabled_state(self)
}
fn get_checked_state(&self) -> bool {
match self.downcast::<HTMLInputElement>() {
Some(input) => input.Checked(),
None => false,
}
}
fn get_indeterminate_state(&self) -> bool {
match self.downcast::<HTMLInputElement>() {
Some(input) => input.get_indeterminate_state(),
None => false,
}
}
fn has_class(&self, name: &Atom) -> bool {
Element::has_class(&**self, name)
}
@ -1728,8 +1697,8 @@ impl<'a> ::selectors::Element for Root<Element> {
})
},
NamespaceConstraint::Any => {
self.attrs.borrow().iter().map(JS::root).any(|attr| {
attr.local_name() == local_name && test(&attr.value())
self.attrs.borrow().iter().any(|attr| {
attr.local_name() == local_name && test(&attr.value())
})
}
}
@ -1752,6 +1721,10 @@ impl Element {
let element = self.downcast::<HTMLAnchorElement>().unwrap();
Some(element as &Activatable)
},
NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
let element = self.downcast::<HTMLLabelElement>().unwrap();
Some(element as &Activatable)
},
_ => {
None
}
@ -1833,8 +1806,12 @@ impl Element {
self.set_click_in_progress(false);
}
fn set_state(&self, which: EventState, value: bool) {
let mut state = self.event_state.get();
pub fn get_state(&self) -> ElementState {
self.state.get()
}
pub fn set_state(&self, which: ElementState, value: bool) {
let mut state = self.state.get();
if state.contains(which) == value {
return
}
@ -1842,14 +1819,14 @@ impl Element {
true => state.insert(which),
false => state.remove(which),
};
self.event_state.set(state);
self.state.set(state);
let node = self.upcast::<Node>();
node.owner_doc().record_event_state_change(self, which);
node.owner_doc().record_element_state_change(self, which);
}
pub fn get_active_state(&self) -> bool {
self.event_state.get().contains(IN_ACTIVE_STATE)
self.state.get().contains(IN_ACTIVE_STATE)
}
pub fn set_active_state(&self, value: bool) {
@ -1857,7 +1834,7 @@ impl Element {
}
pub fn get_focus_state(&self) -> bool {
self.event_state.get().contains(IN_FOCUS_STATE)
self.state.get().contains(IN_FOCUS_STATE)
}
pub fn set_focus_state(&self, value: bool) {
@ -1865,7 +1842,7 @@ impl Element {
}
pub fn get_hover_state(&self) -> bool {
self.event_state.get().contains(IN_HOVER_STATE)
self.state.get().contains(IN_HOVER_STATE)
}
pub fn set_hover_state(&self, value: bool) {
@ -1873,7 +1850,7 @@ impl Element {
}
pub fn get_enabled_state(&self) -> bool {
self.event_state.get().contains(IN_ENABLED_STATE)
self.state.get().contains(IN_ENABLED_STATE)
}
pub fn set_enabled_state(&self, value: bool) {
@ -1881,7 +1858,7 @@ impl Element {
}
pub fn get_disabled_state(&self) -> bool {
self.event_state.get().contains(IN_DISABLED_STATE)
self.state.get().contains(IN_DISABLED_STATE)
}
pub fn set_disabled_state(&self, value: bool) {