1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! Element nodes.
6 
7 use devtools_traits::AttrInfo;
8 use dom::activation::Activatable;
9 use dom::attr::{Attr, AttrHelpersForLayout};
10 use dom::bindings::cell::DomRefCell;
11 use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
12 use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
13 use dom::bindings::codegen::Bindings::ElementBinding;
14 use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
15 use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
16 use dom::bindings::codegen::Bindings::FunctionBinding::Function;
17 use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
18 use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
19 use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
20 use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
21 use dom::bindings::codegen::UnionTypes::NodeOrString;
22 use dom::bindings::conversions::DerivedFrom;
23 use dom::bindings::error::{Error, ErrorResult, Fallible};
24 use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
25 use dom::bindings::refcounted::{Trusted, TrustedPromise};
26 use dom::bindings::reflector::DomObject;
27 use dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, RootedReference};
28 use dom::bindings::str::DOMString;
29 use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
30 use dom::bindings::xmlname::XMLName::InvalidXMLName;
31 use dom::characterdata::CharacterData;
32 use dom::create::create_element;
33 use dom::customelementregistry::{CallbackReaction, CustomElementDefinition, CustomElementReaction};
34 use dom::document::{Document, LayoutDocumentHelpers};
35 use dom::documentfragment::DocumentFragment;
36 use dom::domrect::DOMRect;
37 use dom::domtokenlist::DOMTokenList;
38 use dom::event::Event;
39 use dom::eventtarget::EventTarget;
40 use dom::htmlanchorelement::HTMLAnchorElement;
41 use dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers};
42 use dom::htmlbuttonelement::HTMLButtonElement;
43 use dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
44 use dom::htmlcollection::HTMLCollection;
45 use dom::htmlelement::HTMLElement;
46 use dom::htmlfieldsetelement::HTMLFieldSetElement;
47 use dom::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers};
48 use dom::htmlformelement::FormControlElementHelpers;
49 use dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers};
50 use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
51 use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
52 use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
53 use dom::htmllabelelement::HTMLLabelElement;
54 use dom::htmllegendelement::HTMLLegendElement;
55 use dom::htmllinkelement::HTMLLinkElement;
56 use dom::htmlobjectelement::HTMLObjectElement;
57 use dom::htmloptgroupelement::HTMLOptGroupElement;
58 use dom::htmlselectelement::HTMLSelectElement;
59 use dom::htmlstyleelement::HTMLStyleElement;
60 use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementLayoutHelpers};
61 use dom::htmltableelement::{HTMLTableElement, HTMLTableElementLayoutHelpers};
62 use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementLayoutHelpers};
63 use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers};
64 use dom::htmltemplateelement::HTMLTemplateElement;
65 use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
66 use dom::mutationobserver::{Mutation, MutationObserver};
67 use dom::namednodemap::NamedNodeMap;
68 use dom::node::{ChildrenMutation, LayoutNodeHelpers, Node};
69 use dom::node::{NodeDamage, NodeFlags, UnbindContext};
70 use dom::node::{document_from_node, window_from_node};
71 use dom::nodelist::NodeList;
72 use dom::promise::Promise;
73 use dom::servoparser::ServoParser;
74 use dom::text::Text;
75 use dom::validation::Validatable;
76 use dom::virtualmethods::{VirtualMethods, vtable_for};
77 use dom::window::ReflowReason;
78 use dom_struct::dom_struct;
79 use html5ever::{Prefix, LocalName, Namespace, QualName};
80 use html5ever::serialize;
81 use html5ever::serialize::SerializeOpts;
82 use html5ever::serialize::TraversalScope;
83 use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
84 use js::jsapi::Heap;
85 use js::jsval::JSVal;
86 use net_traits::request::CorsSettings;
87 use ref_filter_map::ref_filter_map;
88 use script_layout_interface::message::ReflowGoal;
89 use script_thread::ScriptThread;
90 use selectors::Element as SelectorsElement;
91 use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
92 use selectors::matching::{ElementSelectorFlags, MatchingContext};
93 use selectors::sink::Push;
94 use servo_arc::Arc;
95 use servo_atoms::Atom;
96 use std::borrow::Cow;
97 use std::cell::{Cell, Ref};
98 use std::default::Default;
99 use std::fmt;
100 use std::mem;
101 use std::rc::Rc;
102 use std::str::FromStr;
103 use style::CaseSensitivityExt;
104 use style::applicable_declarations::ApplicableDeclarationBlock;
105 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
106 use style::context::QuirksMode;
107 use style::dom_apis;
108 use style::element_state::ElementState;
109 use style::invalidation::element::restyle_hints::RestyleHint;
110 use style::properties::{ComputedValues, Importance, PropertyDeclaration};
111 use style::properties::{PropertyDeclarationBlock, parse_style_attribute};
112 use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size};
113 use style::properties::longhands::{overflow_x, overflow_y};
114 use style::rule_tree::CascadeLevel;
115 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
116 use style::selector_parser::extended_filtering;
117 use style::shared_lock::{SharedRwLock, Locked};
118 use style::thread_state;
119 use style::values::{CSSFloat, Either};
120 use style::values::{specified, computed};
121 use stylesheet_loader::StylesheetOwner;
122 use task::TaskOnce;
123 use xml5ever::serialize as xmlSerialize;
124 use xml5ever::serialize::SerializeOpts as XmlSerializeOpts;
125 use xml5ever::serialize::TraversalScope as XmlTraversalScope;
126 use xml5ever::serialize::TraversalScope::ChildrenOnly as XmlChildrenOnly;
127 use xml5ever::serialize::TraversalScope::IncludeNode as XmlIncludeNode;
128 
129 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
130 // and when the element enters or leaves a browsing context container.
131 // https://html.spec.whatwg.org/multipage/#selector-focus
132 
133 #[dom_struct]
134 pub struct Element {
135     node: Node,
136     local_name: LocalName,
137     tag_name: TagName,
138     namespace: Namespace,
139     prefix: DomRefCell<Option<Prefix>>,
140     attrs: DomRefCell<Vec<Dom<Attr>>>,
141     id_attribute: DomRefCell<Option<Atom>>,
142     is: DomRefCell<Option<LocalName>>,
143     #[ignore_malloc_size_of = "Arc"]
144     style_attribute: DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
145     attr_list: MutNullableDom<NamedNodeMap>,
146     class_list: MutNullableDom<DOMTokenList>,
147     state: Cell<ElementState>,
148     /// These flags are set by the style system to indicate the that certain
149     /// operations may require restyling this element or its descendants. The
150     /// flags are not atomic, so the style system takes care of only set them
151     /// when it has exclusive access to the element.
152     #[ignore_malloc_size_of = "bitflags defined in rust-selectors"]
153     selector_flags: Cell<ElementSelectorFlags>,
154     /// <https://html.spec.whatwg.org/multipage/#custom-element-reaction-queue>
155     custom_element_reaction_queue: DomRefCell<Vec<CustomElementReaction>>,
156     /// <https://dom.spec.whatwg.org/#concept-element-custom-element-definition>
157     #[ignore_malloc_size_of = "Rc"]
158     custom_element_definition: DomRefCell<Option<Rc<CustomElementDefinition>>>,
159     /// <https://dom.spec.whatwg.org/#concept-element-custom-element-state>
160     custom_element_state: Cell<CustomElementState>,
161 }
162 
163 impl fmt::Debug for Element {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result164     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165         write!(f, "<{}", self.local_name)?;
166         if let Some(ref id) = *self.id_attribute.borrow() {
167             write!(f, " id={}", id)?;
168         }
169         write!(f, ">")
170     }
171 }
172 
173 impl fmt::Debug for DomRoot<Element> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result174     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175         (**self).fmt(f)
176     }
177 }
178 
179 #[derive(MallocSizeOf, PartialEq)]
180 pub enum ElementCreator {
181     ParserCreated(u64),
182     ScriptCreated,
183 }
184 
185 pub enum CustomElementCreationMode {
186     Synchronous,
187     Asynchronous,
188 }
189 
190 /// <https://dom.spec.whatwg.org/#concept-element-custom-element-state>
191 #[derive(Clone, Copy, Eq, JSTraceable, MallocSizeOf, PartialEq)]
192 pub enum CustomElementState {
193     Undefined,
194     Failed,
195     Uncustomized,
196     Custom,
197 }
198 
199 impl ElementCreator {
is_parser_created(&self) -> bool200     pub fn is_parser_created(&self) -> bool {
201         match *self {
202             ElementCreator::ParserCreated(_) => true,
203             ElementCreator::ScriptCreated => false,
204         }
205     }
return_line_number(&self) -> u64206     pub fn return_line_number(&self) -> u64 {
207         match *self {
208             ElementCreator::ParserCreated(l) => l,
209             ElementCreator::ScriptCreated => 1,
210         }
211     }
212 }
213 
214 pub enum AdjacentPosition {
215     BeforeBegin,
216     AfterEnd,
217     AfterBegin,
218     BeforeEnd,
219 }
220 
221 impl FromStr for AdjacentPosition {
222     type Err = Error;
223 
from_str(position: &str) -> Result<Self, Self::Err>224     fn from_str(position: &str) -> Result<Self, Self::Err> {
225         match_ignore_ascii_case! { &*position,
226             "beforebegin" => Ok(AdjacentPosition::BeforeBegin),
227             "afterbegin"  => Ok(AdjacentPosition::AfterBegin),
228             "beforeend"   => Ok(AdjacentPosition::BeforeEnd),
229             "afterend"    => Ok(AdjacentPosition::AfterEnd),
230             _             => Err(Error::Syntax)
231         }
232     }
233 }
234 
235 //
236 // Element methods
237 //
238 impl Element {
create(name: QualName, is: Option<LocalName>, document: &Document, creator: ElementCreator, mode: CustomElementCreationMode) -> DomRoot<Element>239     pub fn create(name: QualName,
240                   is: Option<LocalName>,
241                   document: &Document,
242                   creator: ElementCreator,
243                   mode: CustomElementCreationMode)
244                   -> DomRoot<Element> {
245         create_element(name, is, document, creator, mode)
246     }
247 
new_inherited(local_name: LocalName, namespace: Namespace, prefix: Option<Prefix>, document: &Document) -> Element248     pub fn new_inherited(local_name: LocalName,
249                          namespace: Namespace, prefix: Option<Prefix>,
250                          document: &Document) -> Element {
251         Element::new_inherited_with_state(ElementState::empty(), local_name,
252                                           namespace, prefix, document)
253     }
254 
new_inherited_with_state(state: ElementState, local_name: LocalName, namespace: Namespace, prefix: Option<Prefix>, document: &Document) -> Element255     pub fn new_inherited_with_state(state: ElementState, local_name: LocalName,
256                                     namespace: Namespace, prefix: Option<Prefix>,
257                                     document: &Document)
258                                     -> Element {
259         Element {
260             node: Node::new_inherited(document),
261             local_name: local_name,
262             tag_name: TagName::new(),
263             namespace: namespace,
264             prefix: DomRefCell::new(prefix),
265             attrs: DomRefCell::new(vec![]),
266             id_attribute: DomRefCell::new(None),
267             is: DomRefCell::new(None),
268             style_attribute: DomRefCell::new(None),
269             attr_list: Default::default(),
270             class_list: Default::default(),
271             state: Cell::new(state),
272             selector_flags: Cell::new(ElementSelectorFlags::empty()),
273             custom_element_reaction_queue: Default::default(),
274             custom_element_definition: Default::default(),
275             custom_element_state: Cell::new(CustomElementState::Uncustomized),
276         }
277     }
278 
new(local_name: LocalName, namespace: Namespace, prefix: Option<Prefix>, document: &Document) -> DomRoot<Element>279     pub fn new(local_name: LocalName,
280                namespace: Namespace,
281                prefix: Option<Prefix>,
282                document: &Document) -> DomRoot<Element> {
283         Node::reflect_node(
284             Box::new(Element::new_inherited(local_name, namespace, prefix, document)),
285             document,
286             ElementBinding::Wrap)
287     }
288 
restyle(&self, damage: NodeDamage)289     pub fn restyle(&self, damage: NodeDamage) {
290         let doc = self.node.owner_doc();
291         let mut restyle = doc.ensure_pending_restyle(self);
292 
293         // FIXME(bholley): I think we should probably only do this for
294         // NodeStyleDamaged, but I'm preserving existing behavior.
295         restyle.hint.insert(RestyleHint::RESTYLE_SELF);
296 
297         if damage == NodeDamage::OtherNodeDamage {
298             restyle.damage = RestyleDamage::rebuild_and_reflow();
299         }
300     }
301 
set_is(&self, is: LocalName)302     pub fn set_is(&self, is: LocalName) {
303         *self.is.borrow_mut() = Some(is);
304     }
305 
get_is(&self) -> Option<LocalName>306     pub fn get_is(&self) -> Option<LocalName> {
307         self.is.borrow().clone()
308     }
309 
set_custom_element_state(&self, state: CustomElementState)310     pub fn set_custom_element_state(&self, state: CustomElementState) {
311         self.custom_element_state.set(state);
312     }
313 
get_custom_element_state(&self) -> CustomElementState314     pub fn get_custom_element_state(&self) -> CustomElementState {
315         self.custom_element_state.get()
316     }
317 
set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>)318     pub fn set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>) {
319         *self.custom_element_definition.borrow_mut() = Some(definition);
320     }
321 
get_custom_element_definition(&self) -> Option<Rc<CustomElementDefinition>>322     pub fn get_custom_element_definition(&self) -> Option<Rc<CustomElementDefinition>> {
323         (*self.custom_element_definition.borrow()).clone()
324     }
325 
push_callback_reaction(&self, function: Rc<Function>, args: Box<[Heap<JSVal>]>)326     pub fn push_callback_reaction(&self, function: Rc<Function>, args: Box<[Heap<JSVal>]>) {
327         self.custom_element_reaction_queue.borrow_mut().push(CustomElementReaction::Callback(function, args));
328     }
329 
push_upgrade_reaction(&self, definition: Rc<CustomElementDefinition>)330     pub fn push_upgrade_reaction(&self, definition: Rc<CustomElementDefinition>) {
331         self.custom_element_reaction_queue.borrow_mut().push(CustomElementReaction::Upgrade(definition));
332     }
333 
clear_reaction_queue(&self)334     pub fn clear_reaction_queue(&self) {
335         self.custom_element_reaction_queue.borrow_mut().clear();
336     }
337 
invoke_reactions(&self)338     pub fn invoke_reactions(&self) {
339         // TODO: This is not spec compliant, as this will allow some reactions to be processed
340         // after clear_reaction_queue has been called.
341         rooted_vec!(let mut reactions);
342         while !self.custom_element_reaction_queue.borrow().is_empty() {
343             mem::swap(&mut *reactions, &mut *self.custom_element_reaction_queue.borrow_mut());
344             for reaction in reactions.iter() {
345                 reaction.invoke(self);
346             }
347             reactions.clear();
348         }
349     }
350 
351     /// style will be `None` for elements in a `display: none` subtree. otherwise, the element has a
352     /// layout box iff it doesn't have `display: none`.
style(&self) -> Option<Arc<ComputedValues>>353     pub fn style(&self) -> Option<Arc<ComputedValues>> {
354         window_from_node(self).style_query(
355             self.upcast::<Node>().to_trusted_node_address()
356         )
357     }
358 
359     // https://drafts.csswg.org/cssom-view/#css-layout-box
has_css_layout_box(&self) -> bool360     pub fn has_css_layout_box(&self) -> bool {
361         self.style()
362             .map_or(false, |s| !s.get_box().clone_display().is_none())
363     }
364 
365     // https://drafts.csswg.org/cssom-view/#potentially-scrollable
potentially_scrollable(&self) -> bool366     fn potentially_scrollable(&self) -> bool {
367         self.has_css_layout_box() && !self.has_any_visible_overflow()
368     }
369 
370     // https://drafts.csswg.org/cssom-view/#scrolling-box
has_scrolling_box(&self) -> bool371     fn has_scrolling_box(&self) -> bool {
372         // TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet)
373         //       self.has_scrolling_mechanism()
374         self.has_any_hidden_overflow()
375     }
376 
has_overflow(&self) -> bool377     fn has_overflow(&self) -> bool {
378         self.ScrollHeight() > self.ClientHeight() ||
379         self.ScrollWidth() > self.ClientWidth()
380     }
381 
382     // TODO: Once #19183 is closed (overflow-x/y types moved out of mako), then we could implement
383     //       a more generic `fn has_some_overflow(&self, overflow: Overflow)` rather than have
384     //       these two `has_any_{visible,hidden}_overflow` methods which are very structurally
385     //       similar.
386 
387     /// Computed value of overflow-x or overflow-y is "visible"
has_any_visible_overflow(&self) -> bool388     fn has_any_visible_overflow(&self) -> bool {
389         self.style().map_or(false, |s| {
390             let box_ = s.get_box();
391 
392             box_.clone_overflow_x() == overflow_x::computed_value::T::Visible ||
393                 box_.clone_overflow_y() == overflow_y::computed_value::T::Visible
394         })
395     }
396 
397     /// Computed value of overflow-x or overflow-y is "hidden"
has_any_hidden_overflow(&self) -> bool398     fn has_any_hidden_overflow(&self) -> bool {
399         self.style().map_or(false, |s| {
400             let box_ = s.get_box();
401 
402             box_.clone_overflow_x() == overflow_x::computed_value::T::Hidden ||
403                 box_.clone_overflow_y() == overflow_y::computed_value::T::Hidden
404         })
405     }
406 }
407 
408 #[allow(unsafe_code)]
409 pub trait RawLayoutElementHelpers {
get_attr_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a AttrValue>410     unsafe fn get_attr_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
411                                       -> Option<&'a AttrValue>;
get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str>412     unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
413                                       -> Option<&'a str>;
get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue>414     unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue>;
415 }
416 
417 #[inline]
418 #[allow(unsafe_code)]
get_attr_for_layout<'a>(elem: &'a Element, namespace: &Namespace, name: &LocalName) -> Option<LayoutDom<Attr>>419 pub unsafe fn get_attr_for_layout<'a>(elem: &'a Element, namespace: &Namespace, name: &LocalName)
420                                       -> Option<LayoutDom<Attr>> {
421     // cast to point to T in RefCell<T> directly
422     let attrs = elem.attrs.borrow_for_layout();
423     attrs.iter().find(|attr| {
424         let attr = attr.to_layout();
425         *name == attr.local_name_atom_forever() &&
426         (*attr.unsafe_get()).namespace() == namespace
427     }).map(|attr| attr.to_layout())
428 }
429 
430 #[allow(unsafe_code)]
431 impl RawLayoutElementHelpers for Element {
432     #[inline]
get_attr_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a AttrValue>433     unsafe fn get_attr_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
434                                       -> Option<&'a AttrValue> {
435         get_attr_for_layout(self, namespace, name).map(|attr| {
436             attr.value_forever()
437         })
438     }
439 
440     #[inline]
get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str>441     unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
442                                           -> Option<&'a str> {
443         get_attr_for_layout(self, namespace, name).map(|attr| {
444             attr.value_ref_forever()
445         })
446     }
447 
448     #[inline]
get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue>449     unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue> {
450         let attrs = self.attrs.borrow_for_layout();
451         attrs.iter().filter_map(|attr| {
452             let attr = attr.to_layout();
453             if *name == attr.local_name_atom_forever() {
454               Some(attr.value_forever())
455             } else {
456               None
457             }
458         }).collect()
459     }
460 }
461 
462 pub trait LayoutElementHelpers {
463     #[allow(unsafe_code)]
has_class_for_layout(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool464     unsafe fn has_class_for_layout(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool;
465     #[allow(unsafe_code)]
get_classes_for_layout(&self) -> Option<&'static [Atom]>466     unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>;
467 
468     #[allow(unsafe_code)]
synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V) where V: Push<ApplicableDeclarationBlock>469     unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
470         where V: Push<ApplicableDeclarationBlock>;
471     #[allow(unsafe_code)]
get_colspan(self) -> u32472     unsafe fn get_colspan(self) -> u32;
473     #[allow(unsafe_code)]
get_rowspan(self) -> u32474     unsafe fn get_rowspan(self) -> u32;
475     #[allow(unsafe_code)]
is_html_element(&self) -> bool476     unsafe fn is_html_element(&self) -> bool;
id_attribute(&self) -> *const Option<Atom>477     fn id_attribute(&self) -> *const Option<Atom>;
style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>478     fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
local_name(&self) -> &LocalName479     fn local_name(&self) -> &LocalName;
namespace(&self) -> &Namespace480     fn namespace(&self) -> &Namespace;
get_lang_for_layout(&self) -> String481     fn get_lang_for_layout(&self) -> String;
get_checked_state_for_layout(&self) -> bool482     fn get_checked_state_for_layout(&self) -> bool;
get_indeterminate_state_for_layout(&self) -> bool483     fn get_indeterminate_state_for_layout(&self) -> bool;
get_state_for_layout(&self) -> ElementState484     fn get_state_for_layout(&self) -> ElementState;
insert_selector_flags(&self, flags: ElementSelectorFlags)485     fn insert_selector_flags(&self, flags: ElementSelectorFlags);
has_selector_flags(&self, flags: ElementSelectorFlags) -> bool486     fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
487 }
488 
489 impl LayoutElementHelpers for LayoutDom<Element> {
490     #[allow(unsafe_code)]
491     #[inline]
has_class_for_layout(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool492     unsafe fn has_class_for_layout(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
493         get_attr_for_layout(&*self.unsafe_get(), &ns!(), &local_name!("class")).map_or(false, |attr| {
494             attr.value_tokens_forever().unwrap().iter().any(|atom| case_sensitivity.eq_atom(atom, name))
495         })
496     }
497 
498     #[allow(unsafe_code)]
499     #[inline]
get_classes_for_layout(&self) -> Option<&'static [Atom]>500     unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]> {
501         get_attr_for_layout(&*self.unsafe_get(), &ns!(), &local_name!("class"))
502             .map(|attr| attr.value_tokens_forever().unwrap())
503     }
504 
505     #[allow(unsafe_code)]
synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V) where V: Push<ApplicableDeclarationBlock>506     unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
507         where V: Push<ApplicableDeclarationBlock>
508     {
509         // FIXME(emilio): Just a single PDB should be enough.
510         #[inline]
511         fn from_declaration(shared_lock: &SharedRwLock, declaration: PropertyDeclaration)
512                             -> ApplicableDeclarationBlock {
513             ApplicableDeclarationBlock::from_declarations(
514                 Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
515                     declaration, Importance::Normal
516                 ))),
517                 CascadeLevel::PresHints)
518         }
519 
520         let document = self.upcast::<Node>().owner_doc_for_layout();
521         let shared_lock = document.style_shared_lock();
522 
523         let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
524             this.get_background_color()
525         } else if let Some(this) = self.downcast::<HTMLTableElement>() {
526             this.get_background_color()
527         } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
528             this.get_background_color()
529         } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
530             this.get_background_color()
531         } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
532             this.get_background_color()
533         } else {
534             None
535         };
536 
537         if let Some(color) = bgcolor {
538             hints.push(from_declaration(
539                 shared_lock,
540                 PropertyDeclaration::BackgroundColor(color.into())
541             ));
542         }
543 
544         let background = if let Some(this) = self.downcast::<HTMLBodyElement>() {
545             this.get_background()
546         } else {
547             None
548         };
549 
550         if let Some(url) = background {
551             hints.push(from_declaration(
552                 shared_lock,
553                 PropertyDeclaration::BackgroundImage(
554                     background_image::SpecifiedValue(vec![
555                         Either::Second(specified::Image::for_cascade(url.into()))
556                     ]))));
557         }
558 
559         let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
560             this.get_color()
561         } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
562             // https://html.spec.whatwg.org/multipage/#the-page:the-body-element-20
563             this.get_color()
564         } else if let Some(this) = self.downcast::<HTMLHRElement>() {
565             // https://html.spec.whatwg.org/multipage/#the-hr-element-2:presentational-hints-5
566             this.get_color()
567         } else {
568             None
569         };
570 
571         if let Some(color) = color {
572             hints.push(from_declaration(
573                 shared_lock,
574                 PropertyDeclaration::Color(
575                     longhands::color::SpecifiedValue(color.into())
576                 )
577             ));
578         }
579 
580         let font_family = if let Some(this) = self.downcast::<HTMLFontElement>() {
581             this.get_face()
582         } else {
583             None
584         };
585 
586         if let Some(font_family) = font_family {
587             hints.push(from_declaration(
588                 shared_lock,
589                 PropertyDeclaration::FontFamily(
590                     font_family::SpecifiedValue::Values(
591                         computed::font::FontFamilyList::new(Box::new([
592                             computed::font::SingleFontFamily::from_atom(
593                                 font_family)]))))));
594         }
595 
596         let font_size = self.downcast::<HTMLFontElement>().and_then(|this| this.get_size());
597 
598         if let Some(font_size) = font_size {
599             hints.push(from_declaration(
600                 shared_lock,
601                 PropertyDeclaration::FontSize(
602                     font_size::SpecifiedValue::from_html_size(font_size as u8)
603                 )
604             ))
605         }
606 
607         let cellspacing = if let Some(this) = self.downcast::<HTMLTableElement>() {
608             this.get_cellspacing()
609         } else {
610             None
611         };
612 
613         if let Some(cellspacing) = cellspacing {
614             let width_value = specified::Length::from_px(cellspacing as f32);
615             hints.push(from_declaration(
616                 shared_lock,
617                 PropertyDeclaration::BorderSpacing(
618                     Box::new(border_spacing::SpecifiedValue::new(
619                         width_value.clone().into(),
620                         width_value.into()
621                     ))
622                 )
623             ));
624         }
625 
626 
627         let size = if let Some(this) = self.downcast::<HTMLInputElement>() {
628             // FIXME(pcwalton): More use of atoms, please!
629             match (*self.unsafe_get()).get_attr_val_for_layout(&ns!(), &local_name!("type")) {
630                 // Not text entry widget
631                 Some("hidden") | Some("date") | Some("month") | Some("week") |
632                 Some("time") | Some("datetime-local") | Some("number") | Some("range") |
633                 Some("color") | Some("checkbox") | Some("radio") | Some("file") |
634                 Some("submit") | Some("image") | Some("reset") | Some("button") => {
635                     None
636                 },
637                 // Others
638                 _ => {
639                     match this.size_for_layout() {
640                         0 => None,
641                         s => Some(s as i32),
642                     }
643                 },
644             }
645         } else {
646             None
647         };
648 
649         if let Some(size) = size {
650             let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size));
651             hints.push(from_declaration(
652                 shared_lock,
653                 PropertyDeclaration::Width(
654                     specified::LengthOrPercentageOrAuto::Length(value))));
655         }
656 
657         let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
658             this.get_width()
659         } else if let Some(this) = self.downcast::<HTMLImageElement>() {
660             this.get_width()
661         } else if let Some(this) = self.downcast::<HTMLTableElement>() {
662             this.get_width()
663         } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
664             this.get_width()
665         } else if let Some(this) = self.downcast::<HTMLHRElement>() {
666             // https://html.spec.whatwg.org/multipage/#the-hr-element-2:attr-hr-width
667             this.get_width()
668         } else if let Some(this) = self.downcast::<HTMLCanvasElement>() {
669             this.get_width()
670         } else {
671             LengthOrPercentageOrAuto::Auto
672         };
673 
674         // FIXME(emilio): Use from_computed value here and below.
675         match width {
676             LengthOrPercentageOrAuto::Auto => {}
677             LengthOrPercentageOrAuto::Percentage(percentage) => {
678                 let width_value =
679                     specified::LengthOrPercentageOrAuto::Percentage(computed::Percentage(percentage));
680                 hints.push(from_declaration(
681                     shared_lock,
682                     PropertyDeclaration::Width(width_value)));
683             }
684             LengthOrPercentageOrAuto::Length(length) => {
685                 let width_value = specified::LengthOrPercentageOrAuto::Length(
686                     specified::NoCalcLength::Absolute(specified::AbsoluteLength::Px(length.to_f32_px())));
687                 hints.push(from_declaration(
688                     shared_lock,
689                     PropertyDeclaration::Width(width_value)));
690             }
691         }
692 
693 
694         let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
695             this.get_height()
696         } else if let Some(this) = self.downcast::<HTMLImageElement>() {
697             this.get_height()
698         } else if let Some(this) = self.downcast::<HTMLCanvasElement>() {
699             this.get_height()
700         } else {
701             LengthOrPercentageOrAuto::Auto
702         };
703 
704         match height {
705             LengthOrPercentageOrAuto::Auto => {}
706             LengthOrPercentageOrAuto::Percentage(percentage) => {
707                 let height_value =
708                     specified::LengthOrPercentageOrAuto::Percentage(computed::Percentage(percentage));
709                 hints.push(from_declaration(
710                     shared_lock,
711                     PropertyDeclaration::Height(height_value)));
712             }
713             LengthOrPercentageOrAuto::Length(length) => {
714                 let height_value = specified::LengthOrPercentageOrAuto::Length(
715                     specified::NoCalcLength::Absolute(specified::AbsoluteLength::Px(length.to_f32_px())));
716                 hints.push(from_declaration(
717                     shared_lock,
718                     PropertyDeclaration::Height(height_value)));
719             }
720         }
721 
722 
723         let cols = if let Some(this) = self.downcast::<HTMLTextAreaElement>() {
724             match this.get_cols() {
725                 0 => None,
726                 c => Some(c as i32),
727             }
728         } else {
729             None
730         };
731 
732         if let Some(cols) = cols {
733             // TODO(mttr) ServoCharacterWidth uses the size math for <input type="text">, but
734             // the math for <textarea> is a little different since we need to take
735             // scrollbar size into consideration (but we don't have a scrollbar yet!)
736             //
737             // https://html.spec.whatwg.org/multipage/#textarea-effective-width
738             let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols));
739             hints.push(from_declaration(
740                 shared_lock,
741                 PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value))));
742         }
743 
744         let rows = if let Some(this) = self.downcast::<HTMLTextAreaElement>() {
745             match this.get_rows() {
746                 0 => None,
747                 r => Some(r as i32),
748             }
749         } else {
750             None
751         };
752 
753         if let Some(rows) = rows {
754             // TODO(mttr) This should take scrollbar size into consideration.
755             //
756             // https://html.spec.whatwg.org/multipage/#textarea-effective-height
757             let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat));
758             hints.push(from_declaration(
759                 shared_lock,
760                 PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value))));
761         }
762 
763 
764         let border = if let Some(this) = self.downcast::<HTMLTableElement>() {
765             this.get_border()
766         } else {
767             None
768         };
769 
770         if let Some(border) = border {
771             let width_value = specified::BorderSideWidth::Length(specified::Length::from_px(border as f32));
772             hints.push(from_declaration(
773                 shared_lock,
774                 PropertyDeclaration::BorderTopWidth(width_value.clone())));
775             hints.push(from_declaration(
776                 shared_lock,
777                 PropertyDeclaration::BorderLeftWidth(width_value.clone())));
778             hints.push(from_declaration(
779                 shared_lock,
780                 PropertyDeclaration::BorderBottomWidth(width_value.clone())));
781             hints.push(from_declaration(
782                 shared_lock,
783                 PropertyDeclaration::BorderRightWidth(width_value)));
784         }
785     }
786 
787     #[allow(unsafe_code)]
get_colspan(self) -> u32788     unsafe fn get_colspan(self) -> u32 {
789         if let Some(this) = self.downcast::<HTMLTableCellElement>() {
790             this.get_colspan().unwrap_or(1)
791         } else {
792             // Don't panic since `display` can cause this to be called on arbitrary
793             // elements.
794             1
795         }
796     }
797 
798     #[allow(unsafe_code)]
get_rowspan(self) -> u32799     unsafe fn get_rowspan(self) -> u32 {
800         if let Some(this) = self.downcast::<HTMLTableCellElement>() {
801             this.get_rowspan().unwrap_or(1)
802         } else {
803             // Don't panic since `display` can cause this to be called on arbitrary
804             // elements.
805             1
806         }
807     }
808 
809     #[inline]
810     #[allow(unsafe_code)]
is_html_element(&self) -> bool811     unsafe fn is_html_element(&self) -> bool {
812         (*self.unsafe_get()).namespace == ns!(html)
813     }
814 
815     #[allow(unsafe_code)]
id_attribute(&self) -> *const Option<Atom>816     fn id_attribute(&self) -> *const Option<Atom> {
817         unsafe {
818             (*self.unsafe_get()).id_attribute.borrow_for_layout()
819         }
820     }
821 
822     #[allow(unsafe_code)]
style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>823     fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
824         unsafe {
825             (*self.unsafe_get()).style_attribute.borrow_for_layout()
826         }
827     }
828 
829     #[allow(unsafe_code)]
local_name(&self) -> &LocalName830     fn local_name(&self) -> &LocalName {
831         unsafe {
832             &(*self.unsafe_get()).local_name
833         }
834     }
835 
836     #[allow(unsafe_code)]
namespace(&self) -> &Namespace837     fn namespace(&self) -> &Namespace {
838         unsafe {
839             &(*self.unsafe_get()).namespace
840         }
841     }
842 
843     #[allow(unsafe_code)]
get_lang_for_layout(&self) -> String844     fn get_lang_for_layout(&self) -> String {
845         unsafe {
846             let mut current_node = Some(self.upcast::<Node>());
847             while let Some(node) = current_node {
848                 current_node = node.parent_node_ref();
849                 match node.downcast::<Element>().map(|el| el.unsafe_get()) {
850                     Some(elem) => {
851                         if let Some(attr) = (*elem).get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
852                             return attr.to_owned();
853                         }
854                         if let Some(attr) = (*elem).get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
855                             return attr.to_owned();
856                         }
857                     }
858                     None => continue
859                 }
860             }
861             // TODO: Check meta tags for a pragma-set default language
862             // TODO: Check HTTP Content-Language header
863             String::new()
864         }
865     }
866 
867     #[inline]
868     #[allow(unsafe_code)]
get_checked_state_for_layout(&self) -> bool869     fn get_checked_state_for_layout(&self) -> bool {
870         // TODO option and menuitem can also have a checked state.
871         match self.downcast::<HTMLInputElement>() {
872             Some(input) => unsafe {
873                 input.checked_state_for_layout()
874             },
875             None => false,
876         }
877     }
878 
879     #[inline]
880     #[allow(unsafe_code)]
get_indeterminate_state_for_layout(&self) -> bool881     fn get_indeterminate_state_for_layout(&self) -> bool {
882         // TODO progress elements can also be matched with :indeterminate
883         match self.downcast::<HTMLInputElement>() {
884             Some(input) => unsafe {
885                 input.indeterminate_state_for_layout()
886             },
887             None => false,
888         }
889     }
890 
891     #[inline]
892     #[allow(unsafe_code)]
get_state_for_layout(&self) -> ElementState893     fn get_state_for_layout(&self) -> ElementState {
894         unsafe {
895             (*self.unsafe_get()).state.get()
896         }
897     }
898 
899     #[inline]
900     #[allow(unsafe_code)]
insert_selector_flags(&self, flags: ElementSelectorFlags)901     fn insert_selector_flags(&self, flags: ElementSelectorFlags) {
902         debug_assert!(thread_state::get().is_layout());
903         unsafe {
904             let f = &(*self.unsafe_get()).selector_flags;
905             f.set(f.get() | flags);
906         }
907     }
908 
909     #[inline]
910     #[allow(unsafe_code)]
has_selector_flags(&self, flags: ElementSelectorFlags) -> bool911     fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool {
912         unsafe {
913             (*self.unsafe_get()).selector_flags.get().contains(flags)
914         }
915     }
916 }
917 
918 impl Element {
is_html_element(&self) -> bool919     pub fn is_html_element(&self) -> bool {
920         self.namespace == ns!(html)
921     }
922 
html_element_in_html_document(&self) -> bool923     pub fn html_element_in_html_document(&self) -> bool {
924         self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
925     }
926 
local_name(&self) -> &LocalName927     pub fn local_name(&self) -> &LocalName {
928         &self.local_name
929     }
930 
parsed_name(&self, mut name: DOMString) -> LocalName931     pub fn parsed_name(&self, mut name: DOMString) -> LocalName {
932         if self.html_element_in_html_document() {
933             name.make_ascii_lowercase();
934         }
935         LocalName::from(name)
936     }
937 
namespace(&self) -> &Namespace938     pub fn namespace(&self) -> &Namespace {
939         &self.namespace
940     }
941 
prefix(&self) -> Ref<Option<Prefix>>942     pub fn prefix(&self) -> Ref<Option<Prefix>> {
943         self.prefix.borrow()
944     }
945 
set_prefix(&self, prefix: Option<Prefix>)946     pub fn set_prefix(&self, prefix: Option<Prefix>) {
947         *self.prefix.borrow_mut() = prefix;
948     }
949 
attrs(&self) -> Ref<[Dom<Attr>]>950     pub fn attrs(&self) -> Ref<[Dom<Attr>]> {
951         Ref::map(self.attrs.borrow(), |attrs| &**attrs)
952     }
953 
954     // Element branch of https://dom.spec.whatwg.org/#locate-a-namespace
locate_namespace(&self, prefix: Option<DOMString>) -> Namespace955     pub fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
956         let prefix = prefix.map(String::from).map(LocalName::from);
957 
958         let inclusive_ancestor_elements =
959             self.upcast::<Node>()
960                 .inclusive_ancestors()
961                 .filter_map(DomRoot::downcast::<Self>);
962 
963         // Steps 3-4.
964         for element in inclusive_ancestor_elements {
965             // Step 1.
966             if element.namespace() != &ns!() &&
967                 element.prefix().as_ref().map(|p| &**p) == prefix.as_ref().map(|p| &**p)
968             {
969                 return element.namespace().clone();
970             }
971 
972             // Step 2.
973             let attr = ref_filter_map(self.attrs(), |attrs| {
974                 attrs.iter().find(|attr| {
975                     if attr.namespace() != &ns!(xmlns) {
976                         return false;
977                     }
978                     match (attr.prefix(), prefix.as_ref()) {
979                         (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
980                             attr.local_name() == prefix
981                         },
982                         (None, None) => attr.local_name() == &local_name!("xmlns"),
983                         _ => false,
984                     }
985                 })
986             });
987 
988             if let Some(attr) = attr {
989                 return (**attr.value()).into();
990             }
991         }
992 
993         ns!()
994     }
995 
style_attribute(&self) -> &DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>996     pub fn style_attribute(&self) -> &DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
997         &self.style_attribute
998     }
999 
summarize(&self) -> Vec<AttrInfo>1000     pub fn summarize(&self) -> Vec<AttrInfo> {
1001         self.attrs.borrow().iter()
1002                            .map(|attr| attr.summarize())
1003                            .collect()
1004     }
1005 
is_void(&self) -> bool1006     pub fn is_void(&self) -> bool {
1007         if self.namespace != ns!(html) {
1008             return false
1009         }
1010         match self.local_name {
1011             /* List of void elements from
1012             https://html.spec.whatwg.org/multipage/#html-fragment-serialisation-algorithm */
1013 
1014             local_name!("area") | local_name!("base") | local_name!("basefont") |
1015             local_name!("bgsound") | local_name!("br") |
1016             local_name!("col") |  local_name!("embed") | local_name!("frame") |
1017             local_name!("hr") | local_name!("img") |
1018             local_name!("input") | local_name!("keygen") | local_name!("link") |
1019             local_name!("menuitem") | local_name!("meta") |
1020             local_name!("param") | local_name!("source") | local_name!("track") |
1021             local_name!("wbr") => true,
1022             _ => false
1023         }
1024     }
1025 
serialize(&self, traversal_scope: TraversalScope) -> Fallible<DOMString>1026     pub fn serialize(&self, traversal_scope: TraversalScope) -> Fallible<DOMString> {
1027         let mut writer = vec![];
1028         match serialize(&mut writer,
1029                         &self.upcast::<Node>(),
1030                         SerializeOpts {
1031                             traversal_scope: traversal_scope,
1032                             ..Default::default()
1033                         }) {
1034             // FIXME(ajeffrey): Directly convert UTF8 to DOMString
1035             Ok(()) => Ok(DOMString::from(String::from_utf8(writer).unwrap())),
1036             Err(_) => panic!("Cannot serialize element"),
1037         }
1038     }
1039 
xmlSerialize(&self, traversal_scope: XmlTraversalScope) -> Fallible<DOMString>1040     pub fn xmlSerialize(&self, traversal_scope: XmlTraversalScope) -> Fallible<DOMString> {
1041         let mut writer = vec![];
1042         match xmlSerialize::serialize(&mut writer,
1043                         &self.upcast::<Node>(),
1044                         XmlSerializeOpts {
1045                             traversal_scope: traversal_scope,
1046                             ..Default::default()
1047                         }) {
1048             Ok(()) => Ok(DOMString::from(String::from_utf8(writer).unwrap())),
1049             Err(_) => panic!("Cannot serialize element"),
1050         }
1051     }
1052 
root_element(&self) -> DomRoot<Element>1053     pub fn root_element(&self) -> DomRoot<Element> {
1054         if self.node.is_in_doc() {
1055             self.upcast::<Node>()
1056                 .owner_doc()
1057                 .GetDocumentElement()
1058                 .unwrap()
1059         } else {
1060             self.upcast::<Node>()
1061                 .inclusive_ancestors()
1062                 .filter_map(DomRoot::downcast)
1063                 .last()
1064                 .expect("We know inclusive_ancestors will return `self` which is an element")
1065         }
1066     }
1067 
1068     // https://dom.spec.whatwg.org/#locate-a-namespace-prefix
lookup_prefix(&self, namespace: Namespace) -> Option<DOMString>1069     pub fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1070         for node in self.upcast::<Node>().inclusive_ancestors() {
1071             let element = node.downcast::<Element>()?;
1072             // Step 1.
1073             if *element.namespace() == namespace {
1074                 if let Some(prefix) = element.GetPrefix() {
1075                     return Some(prefix);
1076                 }
1077             }
1078 
1079             // Step 2.
1080             for attr in element.attrs.borrow().iter() {
1081                 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1082                    **attr.value() == *namespace {
1083                     return Some(attr.LocalName());
1084                 }
1085             }
1086         }
1087         None
1088     }
1089 
is_focusable_area(&self) -> bool1090     pub fn is_focusable_area(&self) -> bool {
1091         if self.is_actually_disabled() {
1092             return false;
1093         }
1094         // TODO: Check whether the element is being rendered (i.e. not hidden).
1095         let node = self.upcast::<Node>();
1096         if node.get_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE) {
1097             return true;
1098         }
1099         // https://html.spec.whatwg.org/multipage/#specially-focusable
1100         match node.type_id() {
1101             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) |
1102             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) |
1103             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) |
1104             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
1105                 true
1106             }
1107             _ => false,
1108         }
1109     }
1110 
is_actually_disabled(&self) -> bool1111     pub fn is_actually_disabled(&self) -> bool {
1112         let node = self.upcast::<Node>();
1113         match node.type_id() {
1114             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) |
1115             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) |
1116             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) |
1117             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) |
1118             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => {
1119                 self.disabled_state()
1120             }
1121             // TODO:
1122             // an optgroup element that has a disabled attribute
1123             // a menuitem element that has a disabled attribute
1124             // a fieldset element that is a disabled fieldset
1125             _ => false,
1126         }
1127     }
1128 
push_new_attribute(&self, local_name: LocalName, value: AttrValue, name: LocalName, namespace: Namespace, prefix: Option<Prefix>)1129     pub fn push_new_attribute(&self,
1130                               local_name: LocalName,
1131                               value: AttrValue,
1132                               name: LocalName,
1133                               namespace: Namespace,
1134                               prefix: Option<Prefix>) {
1135         let window = window_from_node(self);
1136         let attr = Attr::new(&window,
1137                              local_name,
1138                              value,
1139                              name,
1140                              namespace,
1141                              prefix,
1142                              Some(self));
1143         self.push_attribute(&attr);
1144     }
1145 
push_attribute(&self, attr: &Attr)1146     pub fn push_attribute(&self, attr: &Attr) {
1147         let name = attr.local_name().clone();
1148         let namespace = attr.namespace().clone();
1149         let value = DOMString::from(&**attr.value());
1150         let mutation = Mutation::Attribute {
1151             name: name.clone(),
1152             namespace: namespace.clone(),
1153             old_value: value.clone(),
1154         };
1155 
1156         MutationObserver::queue_a_mutation_record(&self.node, mutation);
1157 
1158         if self.get_custom_element_definition().is_some() {
1159             let reaction = CallbackReaction::AttributeChanged(name, None, Some(value), namespace);
1160             ScriptThread::enqueue_callback_reaction(self, reaction, None);
1161         }
1162 
1163         assert!(attr.GetOwnerElement().r() == Some(self));
1164         self.will_mutate_attr(attr);
1165         self.attrs.borrow_mut().push(Dom::from_ref(attr));
1166         if attr.namespace() == &ns!() {
1167             vtable_for(self.upcast()).attribute_mutated(attr, AttributeMutation::Set(None));
1168         }
1169     }
1170 
get_attribute(&self, namespace: &Namespace, local_name: &LocalName) -> Option<DomRoot<Attr>>1171     pub fn get_attribute(&self, namespace: &Namespace, local_name: &LocalName) -> Option<DomRoot<Attr>> {
1172         self.attrs
1173             .borrow()
1174             .iter()
1175             .find(|attr| attr.local_name() == local_name && attr.namespace() == namespace)
1176             .map(|js| DomRoot::from_ref(&**js))
1177     }
1178 
1179     // https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>>1180     pub fn get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>> {
1181         let name = &self.parsed_name(name);
1182         self.attrs.borrow().iter().find(|a| a.name() == name).map(|js| DomRoot::from_ref(&**js))
1183     }
1184 
set_attribute_from_parser(&self, qname: QualName, value: DOMString, prefix: Option<Prefix>)1185     pub fn set_attribute_from_parser(&self,
1186                                      qname: QualName,
1187                                      value: DOMString,
1188                                      prefix: Option<Prefix>) {
1189         // Don't set if the attribute already exists, so we can handle add_attrs_if_missing
1190         if self.attrs
1191                .borrow()
1192                .iter()
1193                .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns) {
1194             return;
1195         }
1196 
1197         let name = match prefix {
1198             None => qname.local.clone(),
1199             Some(ref prefix) => {
1200                 let name = format!("{}:{}", &**prefix, &*qname.local);
1201                 LocalName::from(name)
1202             },
1203         };
1204         let value = self.parse_attribute(&qname.ns, &qname.local, value);
1205         self.push_new_attribute(qname.local, value, name, qname.ns, prefix);
1206     }
1207 
set_attribute(&self, name: &LocalName, value: AttrValue)1208     pub fn set_attribute(&self, name: &LocalName, value: AttrValue) {
1209         assert!(name == &name.to_ascii_lowercase());
1210         assert!(!name.contains(":"));
1211 
1212         self.set_first_matching_attribute(name.clone(),
1213                                           value,
1214                                           name.clone(),
1215                                           ns!(),
1216                                           None,
1217                                           |attr| attr.local_name() == name);
1218     }
1219 
1220     // https://html.spec.whatwg.org/multipage/#attr-data-*
set_custom_attribute(&self, name: DOMString, value: DOMString) -> ErrorResult1221     pub fn set_custom_attribute(&self, name: DOMString, value: DOMString) -> ErrorResult {
1222         // Step 1.
1223         if let InvalidXMLName = xml_name_type(&name) {
1224             return Err(Error::InvalidCharacter);
1225         }
1226 
1227         // Steps 2-5.
1228         let name = LocalName::from(name);
1229         let value = self.parse_attribute(&ns!(), &name, value);
1230         self.set_first_matching_attribute(name.clone(),
1231                                           value,
1232                                           name.clone(),
1233                                           ns!(),
1234                                           None,
1235                                           |attr| {
1236                                               *attr.name() == name && *attr.namespace() == ns!()
1237                                           });
1238         Ok(())
1239     }
1240 
set_first_matching_attribute<F>(&self, local_name: LocalName, value: AttrValue, name: LocalName, namespace: Namespace, prefix: Option<Prefix>, find: F) where F: Fn(&Attr) -> bool1241     fn set_first_matching_attribute<F>(&self,
1242                                        local_name: LocalName,
1243                                        value: AttrValue,
1244                                        name: LocalName,
1245                                        namespace: Namespace,
1246                                        prefix: Option<Prefix>,
1247                                        find: F)
1248         where F: Fn(&Attr) -> bool
1249     {
1250         let attr = self.attrs
1251                        .borrow()
1252                        .iter()
1253                        .find(|attr| find(&attr))
1254                        .map(|js| DomRoot::from_ref(&**js));
1255         if let Some(attr) = attr {
1256             attr.set_value(value, self);
1257         } else {
1258             self.push_new_attribute(local_name, value, name, namespace, prefix);
1259         };
1260     }
1261 
parse_attribute(&self, namespace: &Namespace, local_name: &LocalName, value: DOMString) -> AttrValue1262     pub fn parse_attribute(&self,
1263                            namespace: &Namespace,
1264                            local_name: &LocalName,
1265                            value: DOMString)
1266                            -> AttrValue {
1267         if *namespace == ns!() {
1268             vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
1269         } else {
1270             AttrValue::String(value.into())
1271         }
1272     }
1273 
remove_attribute(&self, namespace: &Namespace, local_name: &LocalName) -> Option<DomRoot<Attr>>1274     pub fn remove_attribute(&self, namespace: &Namespace, local_name: &LocalName) -> Option<DomRoot<Attr>> {
1275         self.remove_first_matching_attribute(|attr| {
1276             attr.namespace() == namespace && attr.local_name() == local_name
1277         })
1278     }
1279 
remove_attribute_by_name(&self, name: &LocalName) -> Option<DomRoot<Attr>>1280     pub fn remove_attribute_by_name(&self, name: &LocalName) -> Option<DomRoot<Attr>> {
1281         self.remove_first_matching_attribute(|attr| attr.name() == name)
1282     }
1283 
remove_first_matching_attribute<F>(&self, find: F) -> Option<DomRoot<Attr>> where F: Fn(&Attr) -> bool1284     fn remove_first_matching_attribute<F>(&self, find: F) -> Option<DomRoot<Attr>>
1285         where F: Fn(&Attr) -> bool {
1286         let idx = self.attrs.borrow().iter().position(|attr| find(&attr));
1287         idx.map(|idx| {
1288             let attr = DomRoot::from_ref(&*(*self.attrs.borrow())[idx]);
1289             self.will_mutate_attr(&attr);
1290 
1291             let name = attr.local_name().clone();
1292             let namespace = attr.namespace().clone();
1293             let old_value = DOMString::from(&**attr.value());
1294             let mutation = Mutation::Attribute {
1295                 name: name.clone(),
1296                 namespace: namespace.clone(),
1297                 old_value: old_value.clone(),
1298             };
1299 
1300             MutationObserver::queue_a_mutation_record(&self.node, mutation);
1301 
1302             let reaction = CallbackReaction::AttributeChanged(name, Some(old_value), None, namespace);
1303             ScriptThread::enqueue_callback_reaction(self, reaction, None);
1304 
1305             self.attrs.borrow_mut().remove(idx);
1306             attr.set_owner(None);
1307             if attr.namespace() == &ns!() {
1308                 vtable_for(self.upcast()).attribute_mutated(&attr, AttributeMutation::Removed);
1309             }
1310             attr
1311         })
1312     }
1313 
has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool1314     pub fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
1315         self.get_attribute(&ns!(), &local_name!("class")).map_or(false, |attr| {
1316             attr.value().as_tokens().iter().any(|atom| case_sensitivity.eq_atom(name, atom))
1317         })
1318     }
1319 
set_atomic_attribute(&self, local_name: &LocalName, value: DOMString)1320     pub fn set_atomic_attribute(&self, local_name: &LocalName, value: DOMString) {
1321         assert!(*local_name == local_name.to_ascii_lowercase());
1322         let value = AttrValue::from_atomic(value.into());
1323         self.set_attribute(local_name, value);
1324     }
1325 
has_attribute(&self, local_name: &LocalName) -> bool1326     pub fn has_attribute(&self, local_name: &LocalName) -> bool {
1327         assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b));
1328         self.attrs
1329             .borrow()
1330             .iter()
1331             .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
1332     }
1333 
set_bool_attribute(&self, local_name: &LocalName, value: bool)1334     pub fn set_bool_attribute(&self, local_name: &LocalName, value: bool) {
1335         if self.has_attribute(local_name) == value {
1336             return;
1337         }
1338         if value {
1339             self.set_string_attribute(local_name, DOMString::new());
1340         } else {
1341             self.remove_attribute(&ns!(), local_name);
1342         }
1343     }
1344 
get_url_attribute(&self, local_name: &LocalName) -> DOMString1345     pub fn get_url_attribute(&self, local_name: &LocalName) -> DOMString {
1346         assert!(*local_name == local_name.to_ascii_lowercase());
1347         let attr = match self.get_attribute(&ns!(), local_name) {
1348             Some(attr) => attr,
1349             None => return DOMString::new(),
1350         };
1351         let value = &**attr.value();
1352         // XXXManishearth this doesn't handle `javascript:` urls properly
1353         let base = document_from_node(self).base_url();
1354         let value = base.join(value)
1355             .map(|parsed| parsed.into_string())
1356             .unwrap_or_else(|_| value.to_owned());
1357         DOMString::from(value)
1358     }
1359 
get_string_attribute(&self, local_name: &LocalName) -> DOMString1360     pub fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
1361         match self.get_attribute(&ns!(), local_name) {
1362             Some(x) => x.Value(),
1363             None => DOMString::new(),
1364         }
1365     }
1366 
set_string_attribute(&self, local_name: &LocalName, value: DOMString)1367     pub fn set_string_attribute(&self, local_name: &LocalName, value: DOMString) {
1368         assert!(*local_name == local_name.to_ascii_lowercase());
1369         self.set_attribute(local_name, AttrValue::String(value.into()));
1370     }
1371 
get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom>1372     pub fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
1373         self.get_attribute(&ns!(), local_name).map(|attr| {
1374             attr.value()
1375                 .as_tokens()
1376                 .to_vec()
1377         }).unwrap_or(vec!())
1378     }
1379 
set_tokenlist_attribute(&self, local_name: &LocalName, value: DOMString)1380     pub fn set_tokenlist_attribute(&self, local_name: &LocalName, value: DOMString) {
1381         assert!(*local_name == local_name.to_ascii_lowercase());
1382         self.set_attribute(local_name,
1383                            AttrValue::from_serialized_tokenlist(value.into()));
1384     }
1385 
set_atomic_tokenlist_attribute(&self, local_name: &LocalName, tokens: Vec<Atom>)1386     pub fn set_atomic_tokenlist_attribute(&self, local_name: &LocalName, tokens: Vec<Atom>) {
1387         assert!(*local_name == local_name.to_ascii_lowercase());
1388         self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens));
1389     }
1390 
get_int_attribute(&self, local_name: &LocalName, default: i32) -> i321391     pub fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
1392         // TODO: Is this assert necessary?
1393         assert!(local_name.chars().all(|ch| {
1394             !ch.is_ascii() || ch.to_ascii_lowercase() == ch
1395         }));
1396         let attribute = self.get_attribute(&ns!(), local_name);
1397 
1398         match attribute {
1399             Some(ref attribute) => {
1400                 match *attribute.value() {
1401                     AttrValue::Int(_, value) => value,
1402                     _ => panic!("Expected an AttrValue::Int: \
1403                                  implement parse_plain_attribute"),
1404                 }
1405             }
1406             None => default,
1407         }
1408     }
1409 
set_int_attribute(&self, local_name: &LocalName, value: i32)1410     pub fn set_int_attribute(&self, local_name: &LocalName, value: i32) {
1411         assert!(*local_name == local_name.to_ascii_lowercase());
1412         self.set_attribute(local_name, AttrValue::Int(value.to_string(), value));
1413     }
1414 
get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u321415     pub fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
1416         assert!(local_name.chars().all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch));
1417         let attribute = self.get_attribute(&ns!(), local_name);
1418         match attribute {
1419             Some(ref attribute) => {
1420                 match *attribute.value() {
1421                     AttrValue::UInt(_, value) => value,
1422                     _ => panic!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
1423                 }
1424             }
1425             None => default,
1426         }
1427     }
set_uint_attribute(&self, local_name: &LocalName, value: u32)1428     pub fn set_uint_attribute(&self, local_name: &LocalName, value: u32) {
1429         assert!(*local_name == local_name.to_ascii_lowercase());
1430         self.set_attribute(local_name, AttrValue::UInt(value.to_string(), value));
1431     }
1432 
will_mutate_attr(&self, attr: &Attr)1433     pub fn will_mutate_attr(&self, attr: &Attr) {
1434         let node = self.upcast::<Node>();
1435         node.owner_doc().element_attr_will_change(self, attr);
1436     }
1437 
1438     // https://dom.spec.whatwg.org/#insert-adjacent
insert_adjacent(&self, where_: AdjacentPosition, node: &Node) -> Fallible<Option<DomRoot<Node>>>1439     pub fn insert_adjacent(&self, where_: AdjacentPosition, node: &Node)
1440                            -> Fallible<Option<DomRoot<Node>>> {
1441         let self_node = self.upcast::<Node>();
1442         match where_ {
1443             AdjacentPosition::BeforeBegin => {
1444                 if let Some(parent) = self_node.GetParentNode() {
1445                     Node::pre_insert(node, &parent, Some(self_node)).map(Some)
1446                 } else {
1447                     Ok(None)
1448                 }
1449             }
1450             AdjacentPosition::AfterBegin => {
1451                 Node::pre_insert(node, &self_node, self_node.GetFirstChild().r()).map(Some)
1452             }
1453             AdjacentPosition::BeforeEnd => {
1454                 Node::pre_insert(node, &self_node, None).map(Some)
1455             }
1456             AdjacentPosition::AfterEnd => {
1457                 if let Some(parent) = self_node.GetParentNode() {
1458                     Node::pre_insert(node, &parent, self_node.GetNextSibling().r()).map(Some)
1459                 } else {
1460                     Ok(None)
1461                 }
1462             }
1463         }
1464     }
1465 
1466     // https://drafts.csswg.org/cssom-view/#dom-element-scroll
scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior)1467     pub fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) {
1468         // Step 1.2 or 2.3
1469         let x = if x_.is_finite() { x_ } else { 0.0f64 };
1470         let y = if y_.is_finite() { y_ } else { 0.0f64 };
1471 
1472         let node = self.upcast::<Node>();
1473 
1474         // Step 3
1475         let doc = node.owner_doc();
1476 
1477         // Step 4
1478         if !doc.is_fully_active() {
1479             return;
1480         }
1481 
1482         // Step 5
1483         let win = match doc.GetDefaultView() {
1484             None => return,
1485             Some(win) => win,
1486         };
1487 
1488         // Step 7
1489         if *self.root_element() == *self {
1490             if doc.quirks_mode() != QuirksMode::Quirks {
1491                 win.scroll(x, y, behavior);
1492             }
1493 
1494             return;
1495         }
1496 
1497         // Step 9
1498         if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
1499            doc.quirks_mode() == QuirksMode::Quirks &&
1500            !self.potentially_scrollable() {
1501                win.scroll(x, y, behavior);
1502                return;
1503         }
1504 
1505         // Step 10
1506         if !self.has_css_layout_box() ||
1507            !self.has_scrolling_box() ||
1508            !self.has_overflow()
1509         {
1510             return;
1511         }
1512 
1513         // Step 11
1514         win.scroll_node(node, x, y, behavior);
1515     }
1516 
1517     // https://w3c.github.io/DOM-Parsing/#parsing
parse_fragment(&self, markup: DOMString) -> Fallible<DomRoot<DocumentFragment>>1518     pub fn parse_fragment(&self, markup: DOMString) -> Fallible<DomRoot<DocumentFragment>> {
1519         // Steps 1-2.
1520         let context_document = document_from_node(self);
1521         // TODO(#11995): XML case.
1522         let new_children = ServoParser::parse_html_fragment(self, markup);
1523         // Step 3.
1524         let fragment = DocumentFragment::new(&context_document);
1525         // Step 4.
1526         for child in new_children {
1527             fragment.upcast::<Node>().AppendChild(&child).unwrap();
1528         }
1529         // Step 5.
1530         Ok(fragment)
1531     }
1532 
fragment_parsing_context(owner_doc: &Document, element: Option<&Self>) -> DomRoot<Self>1533     pub fn fragment_parsing_context(owner_doc: &Document, element: Option<&Self>) -> DomRoot<Self> {
1534         match element {
1535             Some(elem) if elem.local_name() != &local_name!("html") || !elem.html_element_in_html_document() => {
1536                 DomRoot::from_ref(elem)
1537             },
1538             _ => {
1539                 DomRoot::upcast(HTMLBodyElement::new(local_name!("body"), None, owner_doc))
1540             }
1541         }
1542     }
1543 
1544     // https://fullscreen.spec.whatwg.org/#fullscreen-element-ready-check
fullscreen_element_ready_check(&self) -> bool1545     pub fn fullscreen_element_ready_check(&self) -> bool {
1546         if !self.is_connected() {
1547             return false
1548         }
1549         let document = document_from_node(self);
1550         document.get_allow_fullscreen()
1551     }
1552 
1553     // https://html.spec.whatwg.org/multipage/#home-subtree
is_in_same_home_subtree<T>(&self, other: &T) -> bool where T: DerivedFrom<Element> + DomObject1554     pub fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
1555         where T: DerivedFrom<Element> + DomObject
1556     {
1557         let other = other.upcast::<Element>();
1558         self.root_element() == other.root_element()
1559     }
1560 }
1561 
1562 impl ElementMethods for Element {
1563     // https://dom.spec.whatwg.org/#dom-element-namespaceuri
GetNamespaceURI(&self) -> Option<DOMString>1564     fn GetNamespaceURI(&self) -> Option<DOMString> {
1565         Node::namespace_to_string(self.namespace.clone())
1566     }
1567 
1568     // https://dom.spec.whatwg.org/#dom-element-localname
LocalName(&self) -> DOMString1569     fn LocalName(&self) -> DOMString {
1570         // FIXME(ajeffrey): Convert directly from LocalName to DOMString
1571         DOMString::from(&*self.local_name)
1572     }
1573 
1574     // https://dom.spec.whatwg.org/#dom-element-prefix
GetPrefix(&self) -> Option<DOMString>1575     fn GetPrefix(&self) -> Option<DOMString> {
1576         self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
1577     }
1578 
1579     // https://dom.spec.whatwg.org/#dom-element-tagname
TagName(&self) -> DOMString1580     fn TagName(&self) -> DOMString {
1581         let name = self.tag_name.or_init(|| {
1582             let qualified_name = match *self.prefix.borrow() {
1583                 Some(ref prefix) => {
1584                     Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name))
1585                 },
1586                 None => Cow::Borrowed(&*self.local_name)
1587             };
1588             if self.html_element_in_html_document() {
1589                 LocalName::from(qualified_name.to_ascii_uppercase())
1590             } else {
1591                 LocalName::from(qualified_name)
1592             }
1593         });
1594         DOMString::from(&*name)
1595     }
1596 
1597     // https://dom.spec.whatwg.org/#dom-element-id
Id(&self) -> DOMString1598     fn Id(&self) -> DOMString {
1599         self.get_string_attribute(&local_name!("id"))
1600     }
1601 
1602     // https://dom.spec.whatwg.org/#dom-element-id
SetId(&self, id: DOMString)1603     fn SetId(&self, id: DOMString) {
1604         self.set_atomic_attribute(&local_name!("id"), id);
1605     }
1606 
1607     // https://dom.spec.whatwg.org/#dom-element-classname
ClassName(&self) -> DOMString1608     fn ClassName(&self) -> DOMString {
1609         self.get_string_attribute(&local_name!("class"))
1610     }
1611 
1612     // https://dom.spec.whatwg.org/#dom-element-classname
SetClassName(&self, class: DOMString)1613     fn SetClassName(&self, class: DOMString) {
1614         self.set_tokenlist_attribute(&local_name!("class"), class);
1615     }
1616 
1617     // https://dom.spec.whatwg.org/#dom-element-classlist
ClassList(&self) -> DomRoot<DOMTokenList>1618     fn ClassList(&self) -> DomRoot<DOMTokenList> {
1619         self.class_list.or_init(|| DOMTokenList::new(self, &local_name!("class")))
1620     }
1621 
1622     // https://dom.spec.whatwg.org/#dom-element-attributes
Attributes(&self) -> DomRoot<NamedNodeMap>1623     fn Attributes(&self) -> DomRoot<NamedNodeMap> {
1624         self.attr_list.or_init(|| NamedNodeMap::new(&window_from_node(self), self))
1625     }
1626 
1627     // https://dom.spec.whatwg.org/#dom-element-hasattributes
HasAttributes(&self) -> bool1628     fn HasAttributes(&self) -> bool {
1629         !self.attrs.borrow().is_empty()
1630     }
1631 
1632     // https://dom.spec.whatwg.org/#dom-element-getattributenames
GetAttributeNames(&self) -> Vec<DOMString>1633     fn GetAttributeNames(&self) -> Vec<DOMString> {
1634         self.attrs.borrow().iter().map(|attr| attr.Name()).collect()
1635     }
1636 
1637     // https://dom.spec.whatwg.org/#dom-element-getattribute
GetAttribute(&self, name: DOMString) -> Option<DOMString>1638     fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
1639         self.GetAttributeNode(name)
1640             .map(|s| s.Value())
1641     }
1642 
1643     // https://dom.spec.whatwg.org/#dom-element-getattributens
GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString>1644     fn GetAttributeNS(&self,
1645                       namespace: Option<DOMString>,
1646                       local_name: DOMString)
1647                       -> Option<DOMString> {
1648         self.GetAttributeNodeNS(namespace, local_name)
1649             .map(|attr| attr.Value())
1650     }
1651 
1652     // https://dom.spec.whatwg.org/#dom-element-getattributenode
GetAttributeNode(&self, name: DOMString) -> Option<DomRoot<Attr>>1653     fn GetAttributeNode(&self, name: DOMString) -> Option<DomRoot<Attr>> {
1654         self.get_attribute_by_name(name)
1655     }
1656 
1657     // https://dom.spec.whatwg.org/#dom-element-getattributenodens
GetAttributeNodeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DomRoot<Attr>>1658     fn GetAttributeNodeNS(&self,
1659                           namespace: Option<DOMString>,
1660                           local_name: DOMString)
1661                           -> Option<DomRoot<Attr>> {
1662         let namespace = &namespace_from_domstring(namespace);
1663         self.get_attribute(namespace, &LocalName::from(local_name))
1664     }
1665 
1666     // https://dom.spec.whatwg.org/#dom-element-setattribute
SetAttribute(&self, name: DOMString, value: DOMString) -> ErrorResult1667     fn SetAttribute(&self, name: DOMString, value: DOMString) -> ErrorResult {
1668         // Step 1.
1669         if xml_name_type(&name) == InvalidXMLName {
1670             return Err(Error::InvalidCharacter);
1671         }
1672 
1673         // Step 2.
1674         let name = self.parsed_name(name);
1675 
1676         // Step 3-5.
1677         let value = self.parse_attribute(&ns!(), &name, value);
1678         self.set_first_matching_attribute(
1679             name.clone(), value, name.clone(), ns!(), None,
1680             |attr| *attr.name() == name);
1681         Ok(())
1682     }
1683 
1684     // https://dom.spec.whatwg.org/#dom-element-setattributens
SetAttributeNS(&self, namespace: Option<DOMString>, qualified_name: DOMString, value: DOMString) -> ErrorResult1685     fn SetAttributeNS(&self,
1686                       namespace: Option<DOMString>,
1687                       qualified_name: DOMString,
1688                       value: DOMString) -> ErrorResult {
1689         let (namespace, prefix, local_name) =
1690             validate_and_extract(namespace, &qualified_name)?;
1691         let qualified_name = LocalName::from(qualified_name);
1692         let value = self.parse_attribute(&namespace, &local_name, value);
1693         self.set_first_matching_attribute(
1694             local_name.clone(), value, qualified_name, namespace.clone(), prefix,
1695             |attr| *attr.local_name() == local_name && *attr.namespace() == namespace);
1696         Ok(())
1697     }
1698 
1699     // https://dom.spec.whatwg.org/#dom-element-setattributenode
SetAttributeNode(&self, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>>1700     fn SetAttributeNode(&self, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
1701         // Step 1.
1702         if let Some(owner) = attr.GetOwnerElement() {
1703             if &*owner != self {
1704                 return Err(Error::InUseAttribute);
1705             }
1706         }
1707 
1708         let vtable = vtable_for(self.upcast());
1709 
1710         // This ensures that the attribute is of the expected kind for this
1711         // specific element. This is inefficient and should probably be done
1712         // differently.
1713         attr.swap_value(
1714             &mut vtable.parse_plain_attribute(attr.local_name(), attr.Value()),
1715         );
1716 
1717         // Step 2.
1718         let position = self.attrs.borrow().iter().position(|old_attr| {
1719             attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
1720         });
1721 
1722         if let Some(position) = position {
1723             let old_attr = DomRoot::from_ref(&*self.attrs.borrow()[position]);
1724 
1725             // Step 3.
1726             if &*old_attr == attr {
1727                 return Ok(Some(DomRoot::from_ref(attr)));
1728             }
1729 
1730             // Step 4.
1731             if self.get_custom_element_definition().is_some() {
1732                 let old_name = old_attr.local_name().clone();
1733                 let old_value = DOMString::from(&**old_attr.value());
1734                 let new_value = DOMString::from(&**attr.value());
1735                 let namespace = old_attr.namespace().clone();
1736                 let reaction = CallbackReaction::AttributeChanged(old_name, Some(old_value),
1737                     Some(new_value), namespace);
1738                 ScriptThread::enqueue_callback_reaction(self, reaction, None);
1739             }
1740             self.will_mutate_attr(attr);
1741             attr.set_owner(Some(self));
1742             self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
1743             old_attr.set_owner(None);
1744             if attr.namespace() == &ns!() {
1745                 vtable.attribute_mutated(
1746                     &attr, AttributeMutation::Set(Some(&old_attr.value())));
1747             }
1748 
1749             // Step 6.
1750             Ok(Some(old_attr))
1751         } else {
1752             // Step 5.
1753             attr.set_owner(Some(self));
1754             self.push_attribute(attr);
1755 
1756             // Step 6.
1757             Ok(None)
1758         }
1759     }
1760 
1761     // https://dom.spec.whatwg.org/#dom-element-setattributenodens
SetAttributeNodeNS(&self, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>>1762     fn SetAttributeNodeNS(&self, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
1763         self.SetAttributeNode(attr)
1764     }
1765 
1766     // https://dom.spec.whatwg.org/#dom-element-removeattribute
RemoveAttribute(&self, name: DOMString)1767     fn RemoveAttribute(&self, name: DOMString) {
1768         let name = self.parsed_name(name);
1769         self.remove_attribute_by_name(&name);
1770     }
1771 
1772     // https://dom.spec.whatwg.org/#dom-element-removeattributens
RemoveAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString)1773     fn RemoveAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) {
1774         let namespace = namespace_from_domstring(namespace);
1775         let local_name = LocalName::from(local_name);
1776         self.remove_attribute(&namespace, &local_name);
1777     }
1778 
1779     // https://dom.spec.whatwg.org/#dom-element-removeattributenode
RemoveAttributeNode(&self, attr: &Attr) -> Fallible<DomRoot<Attr>>1780     fn RemoveAttributeNode(&self, attr: &Attr) -> Fallible<DomRoot<Attr>> {
1781         self.remove_first_matching_attribute(|a| a == attr)
1782             .ok_or(Error::NotFound)
1783     }
1784 
1785     // https://dom.spec.whatwg.org/#dom-element-hasattribute
HasAttribute(&self, name: DOMString) -> bool1786     fn HasAttribute(&self, name: DOMString) -> bool {
1787         self.GetAttribute(name).is_some()
1788     }
1789 
1790     // https://dom.spec.whatwg.org/#dom-element-hasattributens
HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool1791     fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
1792         self.GetAttributeNS(namespace, local_name).is_some()
1793     }
1794 
1795     // https://dom.spec.whatwg.org/#dom-element-getelementsbytagname
GetElementsByTagName(&self, localname: DOMString) -> DomRoot<HTMLCollection>1796     fn GetElementsByTagName(&self, localname: DOMString) -> DomRoot<HTMLCollection> {
1797         let window = window_from_node(self);
1798         HTMLCollection::by_qualified_name(&window, self.upcast(), LocalName::from(&*localname))
1799     }
1800 
1801     // https://dom.spec.whatwg.org/#dom-element-getelementsbytagnamens
GetElementsByTagNameNS(&self, maybe_ns: Option<DOMString>, localname: DOMString) -> DomRoot<HTMLCollection>1802     fn GetElementsByTagNameNS(&self,
1803                               maybe_ns: Option<DOMString>,
1804                               localname: DOMString)
1805                               -> DomRoot<HTMLCollection> {
1806         let window = window_from_node(self);
1807         HTMLCollection::by_tag_name_ns(&window, self.upcast(), localname, maybe_ns)
1808     }
1809 
1810     // https://dom.spec.whatwg.org/#dom-element-getelementsbyclassname
GetElementsByClassName(&self, classes: DOMString) -> DomRoot<HTMLCollection>1811     fn GetElementsByClassName(&self, classes: DOMString) -> DomRoot<HTMLCollection> {
1812         let window = window_from_node(self);
1813         HTMLCollection::by_class_name(&window, self.upcast(), classes)
1814     }
1815 
1816     // https://drafts.csswg.org/cssom-view/#dom-element-getclientrects
GetClientRects(&self) -> Vec<DomRoot<DOMRect>>1817     fn GetClientRects(&self) -> Vec<DomRoot<DOMRect>> {
1818         let win = window_from_node(self);
1819         let raw_rects = self.upcast::<Node>().content_boxes();
1820         raw_rects.iter().map(|rect| {
1821             DOMRect::new(win.upcast(),
1822                          rect.origin.x.to_f64_px(),
1823                          rect.origin.y.to_f64_px(),
1824                          rect.size.width.to_f64_px(),
1825                          rect.size.height.to_f64_px())
1826         }).collect()
1827     }
1828 
1829     // https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect
GetBoundingClientRect(&self) -> DomRoot<DOMRect>1830     fn GetBoundingClientRect(&self) -> DomRoot<DOMRect> {
1831         let win = window_from_node(self);
1832         let rect = self.upcast::<Node>().bounding_content_box_or_zero();
1833         DOMRect::new(win.upcast(),
1834                      rect.origin.x.to_f64_px(),
1835                      rect.origin.y.to_f64_px(),
1836                      rect.size.width.to_f64_px(),
1837                      rect.size.height.to_f64_px())
1838     }
1839 
1840     // https://drafts.csswg.org/cssom-view/#dom-element-scroll
Scroll(&self, options: &ScrollToOptions)1841     fn Scroll(&self, options: &ScrollToOptions) {
1842         // Step 1
1843         let left = options.left.unwrap_or(self.ScrollLeft());
1844         let top = options.top.unwrap_or(self.ScrollTop());
1845         self.scroll(left, top, options.parent.behavior);
1846     }
1847 
1848     // https://drafts.csswg.org/cssom-view/#dom-element-scroll
Scroll_(&self, x: f64, y: f64)1849     fn Scroll_(&self, x: f64, y: f64) {
1850         self.scroll(x, y, ScrollBehavior::Auto);
1851     }
1852 
1853     // https://drafts.csswg.org/cssom-view/#dom-element-scrollto
ScrollTo(&self, options: &ScrollToOptions)1854     fn ScrollTo(&self, options: &ScrollToOptions) {
1855         self.Scroll(options);
1856     }
1857 
1858     // https://drafts.csswg.org/cssom-view/#dom-element-scrollto
ScrollTo_(&self, x: f64, y: f64)1859     fn ScrollTo_(&self, x: f64, y: f64) {
1860         self.Scroll_(x, y);
1861     }
1862 
1863     // https://drafts.csswg.org/cssom-view/#dom-element-scrollby
ScrollBy(&self, options: &ScrollToOptions)1864     fn ScrollBy(&self, options: &ScrollToOptions) {
1865         // Step 2
1866         let delta_left = options.left.unwrap_or(0.0f64);
1867         let delta_top = options.top.unwrap_or(0.0f64);
1868         let left = self.ScrollLeft();
1869         let top = self.ScrollTop();
1870         self.scroll(left + delta_left, top + delta_top,
1871                     options.parent.behavior);
1872     }
1873 
1874     // https://drafts.csswg.org/cssom-view/#dom-element-scrollby
ScrollBy_(&self, x: f64, y: f64)1875     fn ScrollBy_(&self, x: f64, y: f64) {
1876         let left = self.ScrollLeft();
1877         let top = self.ScrollTop();
1878         self.scroll(left + x, top + y, ScrollBehavior::Auto);
1879     }
1880 
1881     // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
ScrollTop(&self) -> f641882     fn ScrollTop(&self) -> f64 {
1883         let node = self.upcast::<Node>();
1884 
1885         // Step 1
1886         let doc = node.owner_doc();
1887 
1888         // Step 2
1889         if !doc.is_fully_active() {
1890             return 0.0;
1891         }
1892 
1893         // Step 3
1894         let win = match doc.GetDefaultView() {
1895             None => return 0.0,
1896             Some(win) => win,
1897         };
1898 
1899         // Step 5
1900         if *self.root_element() == *self {
1901             if doc.quirks_mode() == QuirksMode::Quirks {
1902                 return 0.0;
1903             }
1904 
1905             // Step 6
1906             return win.ScrollY() as f64;
1907         }
1908 
1909         // Step 7
1910         if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
1911            doc.quirks_mode() == QuirksMode::Quirks &&
1912            !self.potentially_scrollable() {
1913                return win.ScrollY() as f64;
1914         }
1915 
1916 
1917         // Step 8
1918         if !self.has_css_layout_box() {
1919             return 0.0;
1920         }
1921 
1922         // Step 9
1923         let point = node.scroll_offset();
1924         return point.y.abs() as f64;
1925     }
1926 
1927     // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
SetScrollTop(&self, y_: f64)1928     fn SetScrollTop(&self, y_: f64) {
1929         let behavior = ScrollBehavior::Auto;
1930 
1931         // Step 1, 2
1932         let y = if y_.is_finite() { y_ } else { 0.0f64 };
1933 
1934         let node = self.upcast::<Node>();
1935 
1936         // Step 3
1937         let doc = node.owner_doc();
1938 
1939         // Step 4
1940         if !doc.is_fully_active() {
1941             return;
1942         }
1943 
1944         // Step 5
1945         let win = match doc.GetDefaultView() {
1946             None => return,
1947             Some(win) => win,
1948         };
1949 
1950         // Step 7
1951         if *self.root_element() == *self {
1952             if doc.quirks_mode() != QuirksMode::Quirks {
1953                 win.scroll(win.ScrollX() as f64, y, behavior);
1954             }
1955 
1956             return;
1957         }
1958 
1959         // Step 9
1960         if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
1961            doc.quirks_mode() == QuirksMode::Quirks &&
1962            !self.potentially_scrollable() {
1963                win.scroll(win.ScrollX() as f64, y, behavior);
1964                return;
1965         }
1966 
1967         // Step 10
1968         if !self.has_css_layout_box() ||
1969            !self.has_scrolling_box() ||
1970            !self.has_overflow()
1971         {
1972             return;
1973         }
1974 
1975         // Step 11
1976         win.scroll_node(node, self.ScrollLeft(), y, behavior);
1977     }
1978 
1979     // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
ScrollLeft(&self) -> f641980     fn ScrollLeft(&self) -> f64 {
1981         let node = self.upcast::<Node>();
1982 
1983         // Step 1
1984         let doc = node.owner_doc();
1985 
1986         // Step 2
1987         if !doc.is_fully_active() {
1988             return 0.0;
1989         }
1990 
1991         // Step 3
1992         let win = match doc.GetDefaultView() {
1993             None => return 0.0,
1994             Some(win) => win,
1995         };
1996 
1997         // Step 5
1998         if *self.root_element() == *self {
1999             if doc.quirks_mode() != QuirksMode::Quirks {
2000                 // Step 6
2001                 return win.ScrollX() as f64;
2002             }
2003 
2004             return 0.0;
2005         }
2006 
2007         // Step 7
2008         if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
2009            doc.quirks_mode() == QuirksMode::Quirks &&
2010            !self.potentially_scrollable() {
2011                return win.ScrollX() as f64;
2012         }
2013 
2014 
2015         // Step 8
2016         if !self.has_css_layout_box() {
2017             return 0.0;
2018         }
2019 
2020         // Step 9
2021         let point = node.scroll_offset();
2022         return point.x.abs() as f64;
2023     }
2024 
2025     // https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
SetScrollLeft(&self, x_: f64)2026     fn SetScrollLeft(&self, x_: f64) {
2027         let behavior = ScrollBehavior::Auto;
2028 
2029         // Step 1, 2
2030         let x = if x_.is_finite() { x_ } else { 0.0f64 };
2031 
2032         let node = self.upcast::<Node>();
2033 
2034         // Step 3
2035         let doc = node.owner_doc();
2036 
2037         // Step 4
2038         if !doc.is_fully_active() {
2039             return;
2040         }
2041 
2042         // Step 5
2043         let win = match doc.GetDefaultView() {
2044             None => return,
2045             Some(win) => win,
2046         };
2047 
2048         // Step 7
2049         if *self.root_element() == *self {
2050             if doc.quirks_mode() == QuirksMode::Quirks {
2051                 return;
2052             }
2053 
2054             win.scroll(x, win.ScrollY() as f64, behavior);
2055             return;
2056         }
2057 
2058         // Step 9
2059         if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
2060            doc.quirks_mode() == QuirksMode::Quirks &&
2061            !self.potentially_scrollable() {
2062                win.scroll(x, win.ScrollY() as f64, behavior);
2063                return;
2064         }
2065 
2066         // Step 10
2067         if !self.has_css_layout_box() ||
2068            !self.has_scrolling_box() ||
2069            !self.has_overflow()
2070         {
2071             return;
2072         }
2073 
2074         // Step 11
2075         win.scroll_node(node, x, self.ScrollTop(), behavior);
2076     }
2077 
2078     // https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth
ScrollWidth(&self) -> i322079     fn ScrollWidth(&self) -> i32 {
2080         self.upcast::<Node>().scroll_area().size.width
2081     }
2082 
2083     // https://drafts.csswg.org/cssom-view/#dom-element-scrollheight
ScrollHeight(&self) -> i322084     fn ScrollHeight(&self) -> i32 {
2085         self.upcast::<Node>().scroll_area().size.height
2086     }
2087 
2088     // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
ClientTop(&self) -> i322089     fn ClientTop(&self) -> i32 {
2090         self.upcast::<Node>().client_rect().origin.y
2091     }
2092 
2093     // https://drafts.csswg.org/cssom-view/#dom-element-clientleft
ClientLeft(&self) -> i322094     fn ClientLeft(&self) -> i32 {
2095         self.upcast::<Node>().client_rect().origin.x
2096     }
2097 
2098     // https://drafts.csswg.org/cssom-view/#dom-element-clientwidth
ClientWidth(&self) -> i322099     fn ClientWidth(&self) -> i32 {
2100         self.upcast::<Node>().client_rect().size.width
2101     }
2102 
2103     // https://drafts.csswg.org/cssom-view/#dom-element-clientheight
ClientHeight(&self) -> i322104     fn ClientHeight(&self) -> i32 {
2105         self.upcast::<Node>().client_rect().size.height
2106     }
2107 
2108     /// <https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML>
GetInnerHTML(&self) -> Fallible<DOMString>2109     fn GetInnerHTML(&self) -> Fallible<DOMString> {
2110         let qname = QualName::new(self.prefix().clone(),
2111                                   self.namespace().clone(),
2112                                   self.local_name().clone());
2113         if document_from_node(self).is_html_document() {
2114             return self.serialize(ChildrenOnly(Some(qname)));
2115         } else {
2116             return self.xmlSerialize(XmlChildrenOnly(Some(qname)));
2117         }
2118     }
2119 
2120     /// <https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML>
SetInnerHTML(&self, value: DOMString) -> ErrorResult2121     fn SetInnerHTML(&self, value: DOMString) -> ErrorResult {
2122         // Step 1.
2123         let frag = self.parse_fragment(value)?;
2124         // Step 2.
2125         // https://github.com/w3c/DOM-Parsing/issues/1
2126         let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2127             DomRoot::upcast(template.Content())
2128         } else {
2129             DomRoot::from_ref(self.upcast())
2130         };
2131         Node::replace_all(Some(frag.upcast()), &target);
2132         Ok(())
2133     }
2134 
2135     // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#widl-Element-outerHTML
GetOuterHTML(&self) -> Fallible<DOMString>2136     fn GetOuterHTML(&self) -> Fallible<DOMString> {
2137         if document_from_node(self).is_html_document() {
2138             return self.serialize(IncludeNode);
2139         } else {
2140             return self.xmlSerialize(XmlIncludeNode);
2141         }
2142     }
2143 
2144     // https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml
SetOuterHTML(&self, value: DOMString) -> ErrorResult2145     fn SetOuterHTML(&self, value: DOMString) -> ErrorResult {
2146         let context_document = document_from_node(self);
2147         let context_node = self.upcast::<Node>();
2148         // Step 1.
2149         let context_parent = match context_node.GetParentNode() {
2150             None => {
2151                 // Step 2.
2152                 return Ok(());
2153             },
2154             Some(parent) => parent,
2155         };
2156 
2157         let parent = match context_parent.type_id() {
2158             // Step 3.
2159             NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed),
2160 
2161             // Step 4.
2162             NodeTypeId::DocumentFragment => {
2163                 let body_elem = Element::create(QualName::new(None, ns!(html), local_name!("body")),
2164                                                 None,
2165                                                 &context_document,
2166                                                 ElementCreator::ScriptCreated,
2167                                                 CustomElementCreationMode::Synchronous);
2168                 DomRoot::upcast(body_elem)
2169             },
2170             _ => context_node.GetParentElement().unwrap()
2171         };
2172 
2173         // Step 5.
2174         let frag = parent.parse_fragment(value)?;
2175         // Step 6.
2176         context_parent.ReplaceChild(frag.upcast(), context_node)?;
2177         Ok(())
2178     }
2179 
2180     // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
GetPreviousElementSibling(&self) -> Option<DomRoot<Element>>2181     fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
2182         self.upcast::<Node>().preceding_siblings().filter_map(DomRoot::downcast).next()
2183     }
2184 
2185     // https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
GetNextElementSibling(&self) -> Option<DomRoot<Element>>2186     fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
2187         self.upcast::<Node>().following_siblings().filter_map(DomRoot::downcast).next()
2188     }
2189 
2190     // https://dom.spec.whatwg.org/#dom-parentnode-children
Children(&self) -> DomRoot<HTMLCollection>2191     fn Children(&self) -> DomRoot<HTMLCollection> {
2192         let window = window_from_node(self);
2193         HTMLCollection::children(&window, self.upcast())
2194     }
2195 
2196     // https://dom.spec.whatwg.org/#dom-parentnode-firstelementchild
GetFirstElementChild(&self) -> Option<DomRoot<Element>>2197     fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
2198         self.upcast::<Node>().child_elements().next()
2199     }
2200 
2201     // https://dom.spec.whatwg.org/#dom-parentnode-lastelementchild
GetLastElementChild(&self) -> Option<DomRoot<Element>>2202     fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
2203         self.upcast::<Node>().rev_children().filter_map(DomRoot::downcast::<Element>).next()
2204     }
2205 
2206     // https://dom.spec.whatwg.org/#dom-parentnode-childelementcount
ChildElementCount(&self) -> u322207     fn ChildElementCount(&self) -> u32 {
2208         self.upcast::<Node>().child_elements().count() as u32
2209     }
2210 
2211     // https://dom.spec.whatwg.org/#dom-parentnode-prepend
Prepend(&self, nodes: Vec<NodeOrString>) -> ErrorResult2212     fn Prepend(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
2213         self.upcast::<Node>().prepend(nodes)
2214     }
2215 
2216     // https://dom.spec.whatwg.org/#dom-parentnode-append
Append(&self, nodes: Vec<NodeOrString>) -> ErrorResult2217     fn Append(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
2218         self.upcast::<Node>().append(nodes)
2219     }
2220 
2221     // https://dom.spec.whatwg.org/#dom-parentnode-queryselector
QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>>2222     fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
2223         let root = self.upcast::<Node>();
2224         root.query_selector(selectors)
2225     }
2226 
2227     // https://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>>2228     fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
2229         let root = self.upcast::<Node>();
2230         root.query_selector_all(selectors)
2231     }
2232 
2233     // https://dom.spec.whatwg.org/#dom-childnode-before
Before(&self, nodes: Vec<NodeOrString>) -> ErrorResult2234     fn Before(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
2235         self.upcast::<Node>().before(nodes)
2236     }
2237 
2238     // https://dom.spec.whatwg.org/#dom-childnode-after
After(&self, nodes: Vec<NodeOrString>) -> ErrorResult2239     fn After(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
2240         self.upcast::<Node>().after(nodes)
2241     }
2242 
2243     // https://dom.spec.whatwg.org/#dom-childnode-replacewith
ReplaceWith(&self, nodes: Vec<NodeOrString>) -> ErrorResult2244     fn ReplaceWith(&self, nodes: Vec<NodeOrString>) -> ErrorResult {
2245         self.upcast::<Node>().replace_with(nodes)
2246     }
2247 
2248     // https://dom.spec.whatwg.org/#dom-childnode-remove
Remove(&self)2249     fn Remove(&self) {
2250         self.upcast::<Node>().remove_self();
2251     }
2252 
2253     // https://dom.spec.whatwg.org/#dom-element-matches
Matches(&self, selectors: DOMString) -> Fallible<bool>2254     fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
2255         let selectors =
2256             match SelectorParser::parse_author_origin_no_namespace(&selectors) {
2257                 Err(_) => return Err(Error::Syntax),
2258                 Ok(selectors) => selectors,
2259             };
2260 
2261         let quirks_mode = document_from_node(self).quirks_mode();
2262         let element = DomRoot::from_ref(self);
2263 
2264         Ok(dom_apis::element_matches(&element, &selectors, quirks_mode))
2265     }
2266 
2267     // https://dom.spec.whatwg.org/#dom-element-webkitmatchesselector
WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool>2268     fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
2269         self.Matches(selectors)
2270     }
2271 
2272     // https://dom.spec.whatwg.org/#dom-element-closest
Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>>2273     fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
2274         let selectors =
2275             match SelectorParser::parse_author_origin_no_namespace(&selectors) {
2276                 Err(_) => return Err(Error::Syntax),
2277                 Ok(selectors) => selectors,
2278             };
2279 
2280         let quirks_mode = document_from_node(self).quirks_mode();
2281         Ok(dom_apis::element_closest(
2282             DomRoot::from_ref(self),
2283             &selectors,
2284             quirks_mode,
2285         ))
2286     }
2287 
2288     // https://dom.spec.whatwg.org/#dom-element-insertadjacentelement
InsertAdjacentElement(&self, where_: DOMString, element: &Element) -> Fallible<Option<DomRoot<Element>>>2289     fn InsertAdjacentElement(&self, where_: DOMString, element: &Element)
2290                              -> Fallible<Option<DomRoot<Element>>> {
2291         let where_ = where_.parse::<AdjacentPosition>()?;
2292         let inserted_node = self.insert_adjacent(where_, element.upcast())?;
2293         Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
2294     }
2295 
2296     // https://dom.spec.whatwg.org/#dom-element-insertadjacenttext
InsertAdjacentText(&self, where_: DOMString, data: DOMString) -> ErrorResult2297     fn InsertAdjacentText(&self, where_: DOMString, data: DOMString)
2298                           -> ErrorResult {
2299         // Step 1.
2300         let text = Text::new(data, &document_from_node(self));
2301 
2302         // Step 2.
2303         let where_ = where_.parse::<AdjacentPosition>()?;
2304         self.insert_adjacent(where_, text.upcast()).map(|_| ())
2305     }
2306 
2307     // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
InsertAdjacentHTML(&self, position: DOMString, text: DOMString) -> ErrorResult2308     fn InsertAdjacentHTML(&self, position: DOMString, text: DOMString)
2309                           -> ErrorResult {
2310         // Step 1.
2311         let position = position.parse::<AdjacentPosition>()?;
2312 
2313         let context = match position {
2314             AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
2315                 match self.upcast::<Node>().GetParentNode() {
2316                     Some(ref node) if node.is::<Document>() => {
2317                         return Err(Error::NoModificationAllowed)
2318                     }
2319                     None => return Err(Error::NoModificationAllowed),
2320                     Some(node) => node,
2321                 }
2322             }
2323             AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
2324                 DomRoot::from_ref(self.upcast::<Node>())
2325             }
2326         };
2327 
2328         // Step 2.
2329         let context = Element::fragment_parsing_context(
2330             &context.owner_doc(), context.downcast::<Element>());
2331 
2332         // Step 3.
2333         let fragment = context.parse_fragment(text)?;
2334 
2335         // Step 4.
2336         self.insert_adjacent(position, fragment.upcast()).map(|_| ())
2337     }
2338 
2339     // check-tidy: no specs after this line
EnterFormalActivationState(&self) -> ErrorResult2340     fn EnterFormalActivationState(&self) -> ErrorResult {
2341         match self.as_maybe_activatable() {
2342             Some(a) => {
2343                 a.enter_formal_activation_state();
2344                 return Ok(());
2345             },
2346             None => return Err(Error::NotSupported)
2347         }
2348     }
2349 
ExitFormalActivationState(&self) -> ErrorResult2350     fn ExitFormalActivationState(&self) -> ErrorResult {
2351         match self.as_maybe_activatable() {
2352             Some(a) => {
2353                 a.exit_formal_activation_state();
2354                 return Ok(());
2355             },
2356             None => return Err(Error::NotSupported)
2357         }
2358     }
2359 
2360     // https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
2361     #[allow(unrooted_must_root)]
RequestFullscreen(&self) -> Rc<Promise>2362     fn RequestFullscreen(&self) -> Rc<Promise> {
2363         let doc = document_from_node(self);
2364         doc.enter_fullscreen(self)
2365     }
2366 }
2367 
2368 impl VirtualMethods for Element {
super_type(&self) -> Option<&VirtualMethods>2369     fn super_type(&self) -> Option<&VirtualMethods> {
2370         Some(self.upcast::<Node>() as &VirtualMethods)
2371     }
2372 
attribute_affects_presentational_hints(&self, attr: &Attr) -> bool2373     fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
2374         // FIXME: This should be more fine-grained, not all elements care about these.
2375         if attr.local_name() == &local_name!("width") ||
2376            attr.local_name() == &local_name!("height") {
2377             return true;
2378         }
2379 
2380         self.super_type().unwrap().attribute_affects_presentational_hints(attr)
2381     }
2382 
attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation)2383     fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
2384         self.super_type().unwrap().attribute_mutated(attr, mutation);
2385         let node = self.upcast::<Node>();
2386         let doc = node.owner_doc();
2387         match attr.local_name() {
2388             &local_name!("style") => {
2389                 // Modifying the `style` attribute might change style.
2390                 *self.style_attribute.borrow_mut() = match mutation {
2391                     AttributeMutation::Set(..) => {
2392                         // This is the fast path we use from
2393                         // CSSStyleDeclaration.
2394                         //
2395                         // Juggle a bit to keep the borrow checker happy
2396                         // while avoiding the extra clone.
2397                         let is_declaration = match *attr.value() {
2398                             AttrValue::Declaration(..) => true,
2399                             _ => false,
2400                         };
2401 
2402                         let block = if is_declaration {
2403                             let mut value = AttrValue::String(String::new());
2404                             attr.swap_value(&mut value);
2405                             let (serialization, block) = match value {
2406                                 AttrValue::Declaration(s, b) => (s, b),
2407                                 _ => unreachable!(),
2408                             };
2409                             let mut value = AttrValue::String(serialization);
2410                             attr.swap_value(&mut value);
2411                             block
2412                         } else {
2413                             let win = window_from_node(self);
2414                             Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
2415                                 &attr.value(),
2416                                 &doc.base_url(),
2417                                 win.css_error_reporter(),
2418                                 doc.quirks_mode())))
2419                         };
2420 
2421                         Some(block)
2422                     }
2423                     AttributeMutation::Removed => {
2424                         None
2425                     }
2426                 };
2427             },
2428             &local_name!("id") => {
2429                 *self.id_attribute.borrow_mut() =
2430                     mutation.new_value(attr).and_then(|value| {
2431                         let value = value.as_atom();
2432                         if value != &atom!("") {
2433                             Some(value.clone())
2434                         } else {
2435                             None
2436                         }
2437                     });
2438                 if node.is_in_doc() {
2439                     let value = attr.value().as_atom().clone();
2440                     match mutation {
2441                         AttributeMutation::Set(old_value) => {
2442                             if let Some(old_value) = old_value {
2443                                 let old_value = old_value.as_atom().clone();
2444                                 doc.unregister_named_element(self, old_value);
2445                             }
2446                             if value != atom!("") {
2447                                 doc.register_named_element(self, value);
2448                             }
2449                         },
2450                         AttributeMutation::Removed => {
2451                             if value != atom!("") {
2452                                 doc.unregister_named_element(self, value);
2453                             }
2454                         }
2455                     }
2456                 }
2457             },
2458             _ => {
2459                 // FIXME(emilio): This is pretty dubious, and should be done in
2460                 // the relevant super-classes.
2461                 if attr.namespace() == &ns!() &&
2462                    attr.local_name() == &local_name!("src") {
2463                     node.dirty(NodeDamage::OtherNodeDamage);
2464                 }
2465             },
2466         };
2467 
2468         // Make sure we rev the version even if we didn't dirty the node. If we
2469         // don't do this, various attribute-dependent htmlcollections (like those
2470         // generated by getElementsByClassName) might become stale.
2471         node.rev_version();
2472     }
2473 
parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue2474     fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
2475         match name {
2476             &local_name!("id") => AttrValue::from_atomic(value.into()),
2477             &local_name!("class") => AttrValue::from_serialized_tokenlist(value.into()),
2478             _ => self.super_type().unwrap().parse_plain_attribute(name, value),
2479         }
2480     }
2481 
bind_to_tree(&self, tree_in_doc: bool)2482     fn bind_to_tree(&self, tree_in_doc: bool) {
2483         if let Some(ref s) = self.super_type() {
2484             s.bind_to_tree(tree_in_doc);
2485         }
2486 
2487         if let Some(f) = self.as_maybe_form_control() {
2488             f.bind_form_control_to_tree();
2489         }
2490 
2491         if !tree_in_doc {
2492             return;
2493         }
2494 
2495         let doc = document_from_node(self);
2496         if let Some(ref value) = *self.id_attribute.borrow() {
2497             doc.register_named_element(self, value.clone());
2498         }
2499         // This is used for layout optimization.
2500         doc.increment_dom_count();
2501     }
2502 
unbind_from_tree(&self, context: &UnbindContext)2503     fn unbind_from_tree(&self, context: &UnbindContext) {
2504         self.super_type().unwrap().unbind_from_tree(context);
2505 
2506         if let Some(f) = self.as_maybe_form_control() {
2507             f.unbind_form_control_from_tree();
2508         }
2509 
2510         if !context.tree_in_doc {
2511             return;
2512         }
2513 
2514         let doc = document_from_node(self);
2515         let fullscreen = doc.GetFullscreenElement();
2516         if fullscreen.r() == Some(self) {
2517             doc.exit_fullscreen();
2518         }
2519         if let Some(ref value) = *self.id_attribute.borrow() {
2520             doc.unregister_named_element(self, value.clone());
2521         }
2522         // This is used for layout optimization.
2523         doc.decrement_dom_count();
2524     }
2525 
children_changed(&self, mutation: &ChildrenMutation)2526     fn children_changed(&self, mutation: &ChildrenMutation) {
2527         if let Some(ref s) = self.super_type() {
2528             s.children_changed(mutation);
2529         }
2530 
2531         let flags = self.selector_flags.get();
2532         if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
2533             // All children of this node need to be restyled when any child changes.
2534             self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
2535         } else {
2536             if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
2537                 if let Some(next_child) = mutation.next_child() {
2538                     for child in next_child.inclusively_following_siblings() {
2539                         if child.is::<Element>() {
2540                             child.dirty(NodeDamage::OtherNodeDamage);
2541                         }
2542                     }
2543                 }
2544             }
2545             if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
2546                 if let Some(child) = mutation.modified_edge_element() {
2547                     child.dirty(NodeDamage::OtherNodeDamage);
2548                 }
2549             }
2550         }
2551     }
2552 
adopting_steps(&self, old_doc: &Document)2553     fn adopting_steps(&self, old_doc: &Document) {
2554         self.super_type().unwrap().adopting_steps(old_doc);
2555 
2556         if document_from_node(self).is_html_document() != old_doc.is_html_document() {
2557             self.tag_name.clear();
2558         }
2559     }
2560 }
2561 
2562 impl<'a> SelectorsElement for DomRoot<Element> {
2563     type Impl = SelectorImpl;
2564 
opaque(&self) -> ::selectors::OpaqueElement2565     fn opaque(&self) -> ::selectors::OpaqueElement {
2566         ::selectors::OpaqueElement::new(self.reflector().get_jsobject().get())
2567     }
2568 
parent_element(&self) -> Option<DomRoot<Element>>2569     fn parent_element(&self) -> Option<DomRoot<Element>> {
2570         self.upcast::<Node>().GetParentElement()
2571     }
2572 
match_pseudo_element( &self, _pseudo: &PseudoElement, _context: &mut MatchingContext<Self::Impl>, ) -> bool2573     fn match_pseudo_element(
2574         &self,
2575         _pseudo: &PseudoElement,
2576         _context: &mut MatchingContext<Self::Impl>,
2577     ) -> bool {
2578         false
2579     }
2580 
2581 
first_child_element(&self) -> Option<DomRoot<Element>>2582     fn first_child_element(&self) -> Option<DomRoot<Element>> {
2583         self.node.child_elements().next()
2584     }
2585 
last_child_element(&self) -> Option<DomRoot<Element>>2586     fn last_child_element(&self) -> Option<DomRoot<Element>> {
2587         self.node.rev_children().filter_map(DomRoot::downcast).next()
2588     }
2589 
prev_sibling_element(&self) -> Option<DomRoot<Element>>2590     fn prev_sibling_element(&self) -> Option<DomRoot<Element>> {
2591         self.node.preceding_siblings().filter_map(DomRoot::downcast).next()
2592     }
2593 
next_sibling_element(&self) -> Option<DomRoot<Element>>2594     fn next_sibling_element(&self) -> Option<DomRoot<Element>> {
2595         self.node.following_siblings().filter_map(DomRoot::downcast).next()
2596     }
2597 
attr_matches(&self, ns: &NamespaceConstraint<&Namespace>, local_name: &LocalName, operation: &AttrSelectorOperation<&String>) -> bool2598     fn attr_matches(&self,
2599                     ns: &NamespaceConstraint<&Namespace>,
2600                     local_name: &LocalName,
2601                     operation: &AttrSelectorOperation<&String>)
2602                     -> bool {
2603         match *ns {
2604             NamespaceConstraint::Specific(ref ns) => {
2605                 self.get_attribute(ns, local_name)
2606                     .map_or(false, |attr| attr.value().eval_selector(operation))
2607             }
2608             NamespaceConstraint::Any => {
2609                 self.attrs.borrow().iter().any(|attr| {
2610                     attr.local_name() == local_name &&
2611                     attr.value().eval_selector(operation)
2612                 })
2613             }
2614         }
2615     }
2616 
is_root(&self) -> bool2617     fn is_root(&self) -> bool {
2618         match self.node.GetParentNode() {
2619             None => false,
2620             Some(node) => node.is::<Document>(),
2621         }
2622     }
2623 
is_empty(&self) -> bool2624     fn is_empty(&self) -> bool {
2625         self.node.children().all(|node| !node.is::<Element>() && match node.downcast::<Text>() {
2626             None => true,
2627             Some(text) => text.upcast::<CharacterData>().data().is_empty()
2628         })
2629     }
2630 
local_name(&self) -> &LocalName2631     fn local_name(&self) -> &LocalName {
2632         Element::local_name(self)
2633     }
2634 
namespace(&self) -> &Namespace2635     fn namespace(&self) -> &Namespace {
2636         Element::namespace(self)
2637     }
2638 
match_non_ts_pseudo_class<F>( &self, pseudo_class: &NonTSPseudoClass, _: &mut MatchingContext<Self::Impl>, _: &mut F, ) -> bool where F: FnMut(&Self, ElementSelectorFlags),2639     fn match_non_ts_pseudo_class<F>(
2640         &self,
2641         pseudo_class: &NonTSPseudoClass,
2642         _: &mut MatchingContext<Self::Impl>,
2643         _: &mut F,
2644     ) -> bool
2645     where
2646         F: FnMut(&Self, ElementSelectorFlags),
2647     {
2648         match *pseudo_class {
2649             // https://github.com/servo/servo/issues/8718
2650             NonTSPseudoClass::Link |
2651             NonTSPseudoClass::AnyLink => self.is_link(),
2652             NonTSPseudoClass::Visited => false,
2653 
2654             NonTSPseudoClass::ServoNonZeroBorder => {
2655                 match self.downcast::<HTMLTableElement>() {
2656                     None => false,
2657                     Some(this) => {
2658                         match this.get_border() {
2659                             None | Some(0) => false,
2660                             Some(_) => true,
2661                         }
2662                     }
2663                 }
2664             },
2665 
2666             NonTSPseudoClass::ServoCaseSensitiveTypeAttr(ref expected_value) => {
2667                 self.get_attribute(&ns!(), &local_name!("type"))
2668                     .map_or(false, |attr| attr.value().eq(expected_value))
2669             }
2670 
2671             // FIXME(heycam): This is wrong, since extended_filtering accepts
2672             // a string containing commas (separating each language tag in
2673             // a list) but the pseudo-class instead should be parsing and
2674             // storing separate <ident> or <string>s for each language tag.
2675             NonTSPseudoClass::Lang(ref lang) => extended_filtering(&*self.get_lang(), &*lang),
2676 
2677             NonTSPseudoClass::ReadOnly =>
2678                 !Element::state(self).contains(pseudo_class.state_flag()),
2679 
2680             NonTSPseudoClass::Active |
2681             NonTSPseudoClass::Focus |
2682             NonTSPseudoClass::Fullscreen |
2683             NonTSPseudoClass::Hover |
2684             NonTSPseudoClass::Enabled |
2685             NonTSPseudoClass::Disabled |
2686             NonTSPseudoClass::Checked |
2687             NonTSPseudoClass::Indeterminate |
2688             NonTSPseudoClass::ReadWrite |
2689             NonTSPseudoClass::PlaceholderShown |
2690             NonTSPseudoClass::Target =>
2691                 Element::state(self).contains(pseudo_class.state_flag()),
2692         }
2693     }
2694 
is_link(&self) -> bool2695     fn is_link(&self) -> bool {
2696         // FIXME: This is HTML only.
2697         let node = self.upcast::<Node>();
2698         match node.type_id() {
2699             // https://html.spec.whatwg.org/multipage/#selector-link
2700             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) |
2701             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) |
2702             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
2703                 self.has_attribute(&local_name!("href"))
2704             },
2705             _ => false,
2706         }
2707     }
2708 
has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool2709     fn has_id(&self, id: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2710         self.id_attribute.borrow().as_ref().map_or(false, |atom| case_sensitivity.eq_atom(id, atom))
2711     }
2712 
has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool2713     fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2714         Element::has_class(&**self, name, case_sensitivity)
2715     }
2716 
is_html_element_in_html_document(&self) -> bool2717     fn is_html_element_in_html_document(&self) -> bool {
2718         self.html_element_in_html_document()
2719     }
2720 
is_html_slot_element(&self) -> bool2721     fn is_html_slot_element(&self) -> bool {
2722         self.is_html_element() && self.local_name() == &local_name!("slot")
2723     }
2724 }
2725 
2726 
2727 impl Element {
as_maybe_activatable(&self) -> Option<&Activatable>2728     pub fn as_maybe_activatable(&self) -> Option<&Activatable> {
2729         let element = match self.upcast::<Node>().type_id() {
2730             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
2731                 let element = self.downcast::<HTMLInputElement>().unwrap();
2732                 Some(element as &Activatable)
2733             },
2734             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
2735                 let element = self.downcast::<HTMLButtonElement>().unwrap();
2736                 Some(element as &Activatable)
2737             },
2738             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => {
2739                 let element = self.downcast::<HTMLAnchorElement>().unwrap();
2740                 Some(element as &Activatable)
2741             },
2742             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
2743                 let element = self.downcast::<HTMLLabelElement>().unwrap();
2744                 Some(element as &Activatable)
2745             },
2746             _ => {
2747                 None
2748             }
2749         };
2750         element.and_then(|elem| {
2751             if elem.is_instance_activatable() {
2752                 Some(elem)
2753             } else {
2754                 None
2755             }
2756         })
2757     }
2758 
as_stylesheet_owner(&self) -> Option<&StylesheetOwner>2759     pub fn as_stylesheet_owner(&self) -> Option<&StylesheetOwner> {
2760         if let Some(s) = self.downcast::<HTMLStyleElement>() {
2761             return Some(s as &StylesheetOwner)
2762         }
2763 
2764         if let Some(l) = self.downcast::<HTMLLinkElement>() {
2765             return Some(l as &StylesheetOwner)
2766         }
2767 
2768         None
2769     }
2770 
2771     // https://html.spec.whatwg.org/multipage/#category-submit
as_maybe_validatable(&self) -> Option<&Validatable>2772     pub fn as_maybe_validatable(&self) -> Option<&Validatable> {
2773         let element = match self.upcast::<Node>().type_id() {
2774             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
2775                 let element = self.downcast::<HTMLInputElement>().unwrap();
2776                 Some(element as &Validatable)
2777             },
2778             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
2779                 let element = self.downcast::<HTMLButtonElement>().unwrap();
2780                 Some(element as &Validatable)
2781             },
2782             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
2783                 let element = self.downcast::<HTMLObjectElement>().unwrap();
2784                 Some(element as &Validatable)
2785             },
2786             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) => {
2787                 let element = self.downcast::<HTMLSelectElement>().unwrap();
2788                 Some(element as &Validatable)
2789             },
2790             NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
2791                 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
2792                 Some(element as &Validatable)
2793             },
2794             _ => {
2795                 None
2796             }
2797         };
2798         element
2799     }
2800 
click_in_progress(&self) -> bool2801     pub fn click_in_progress(&self) -> bool {
2802         self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
2803     }
2804 
set_click_in_progress(&self, click: bool)2805     pub fn set_click_in_progress(&self, click: bool) {
2806         self.upcast::<Node>().set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
2807     }
2808 
2809     // https://html.spec.whatwg.org/multipage/#nearest-activatable-element
nearest_activable_element(&self) -> Option<DomRoot<Element>>2810     pub fn nearest_activable_element(&self) -> Option<DomRoot<Element>> {
2811         match self.as_maybe_activatable() {
2812             Some(el) => Some(DomRoot::from_ref(el.as_element())),
2813             None => {
2814                 let node = self.upcast::<Node>();
2815                 for node in node.ancestors() {
2816                     if let Some(node) = node.downcast::<Element>() {
2817                         if node.as_maybe_activatable().is_some() {
2818                             return Some(DomRoot::from_ref(node));
2819                         }
2820                     }
2821                 }
2822                 None
2823             }
2824         }
2825     }
2826 
2827     /// Please call this method *only* for real click events
2828     ///
2829     /// <https://html.spec.whatwg.org/multipage/#run-authentic-click-activation-steps>
2830     ///
2831     /// Use an element's synthetic click activation (or handle_event) for any script-triggered clicks.
2832     /// If the spec says otherwise, check with Manishearth first
authentic_click_activation(&self, event: &Event)2833     pub fn authentic_click_activation(&self, event: &Event) {
2834         // Not explicitly part of the spec, however this helps enforce the invariants
2835         // required to save state between pre-activation and post-activation
2836         // since we cannot nest authentic clicks (unlike synthetic click activation, where
2837         // the script can generate more click events from the handler)
2838         assert!(!self.click_in_progress());
2839 
2840         let target = self.upcast();
2841         // Step 2 (requires canvas support)
2842         // Step 3
2843         self.set_click_in_progress(true);
2844         // Step 4
2845         let e = self.nearest_activable_element();
2846         match e {
2847             Some(ref el) => match el.as_maybe_activatable() {
2848                 Some(elem) => {
2849                     // Step 5-6
2850                     elem.pre_click_activation();
2851                     event.fire(target);
2852                     if !event.DefaultPrevented() {
2853                         // post click activation
2854                         elem.activation_behavior(event, target);
2855                     } else {
2856                         elem.canceled_activation();
2857                     }
2858                 }
2859                 // Step 6
2860                 None => {
2861                     event.fire(target);
2862                 }
2863             },
2864             // Step 6
2865             None => {
2866                 event.fire(target);
2867             }
2868         }
2869         // Step 7
2870         self.set_click_in_progress(false);
2871     }
2872 
2873     // https://html.spec.whatwg.org/multipage/#language
get_lang(&self) -> String2874     pub fn get_lang(&self) -> String {
2875         self.upcast::<Node>().inclusive_ancestors().filter_map(|node| {
2876             node.downcast::<Element>().and_then(|el| {
2877                 el.get_attribute(&ns!(xml), &local_name!("lang")).or_else(|| {
2878                     el.get_attribute(&ns!(), &local_name!("lang"))
2879                 }).map(|attr| String::from(attr.Value()))
2880             })
2881         // TODO: Check meta tags for a pragma-set default language
2882         // TODO: Check HTTP Content-Language header
2883         }).next().unwrap_or(String::new())
2884     }
2885 
state(&self) -> ElementState2886     pub fn state(&self) -> ElementState {
2887         self.state.get()
2888     }
2889 
set_state(&self, which: ElementState, value: bool)2890     pub fn set_state(&self, which: ElementState, value: bool) {
2891         let mut state = self.state.get();
2892         if state.contains(which) == value {
2893             return;
2894         }
2895         let node = self.upcast::<Node>();
2896         node.owner_doc().element_state_will_change(self);
2897         if value {
2898             state.insert(which);
2899         } else {
2900             state.remove(which);
2901         }
2902         self.state.set(state);
2903     }
2904 
active_state(&self) -> bool2905     pub fn active_state(&self) -> bool {
2906         self.state.get().contains(ElementState::IN_ACTIVE_STATE)
2907     }
2908 
2909     /// <https://html.spec.whatwg.org/multipage/#concept-selector-active>
set_active_state(&self, value: bool)2910     pub fn set_active_state(&self, value: bool) {
2911         self.set_state(ElementState::IN_ACTIVE_STATE, value);
2912 
2913         if let Some(parent) = self.upcast::<Node>().GetParentElement() {
2914             parent.set_active_state(value);
2915         }
2916     }
2917 
focus_state(&self) -> bool2918     pub fn focus_state(&self) -> bool {
2919         self.state.get().contains(ElementState::IN_FOCUS_STATE)
2920     }
2921 
set_focus_state(&self, value: bool)2922     pub fn set_focus_state(&self, value: bool) {
2923         self.set_state(ElementState::IN_FOCUS_STATE, value);
2924         self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
2925     }
2926 
hover_state(&self) -> bool2927     pub fn hover_state(&self) -> bool {
2928         self.state.get().contains(ElementState::IN_HOVER_STATE)
2929     }
2930 
set_hover_state(&self, value: bool)2931     pub fn set_hover_state(&self, value: bool) {
2932         self.set_state(ElementState::IN_HOVER_STATE, value)
2933     }
2934 
enabled_state(&self) -> bool2935     pub fn enabled_state(&self) -> bool {
2936         self.state.get().contains(ElementState::IN_ENABLED_STATE)
2937     }
2938 
set_enabled_state(&self, value: bool)2939     pub fn set_enabled_state(&self, value: bool) {
2940         self.set_state(ElementState::IN_ENABLED_STATE, value)
2941     }
2942 
disabled_state(&self) -> bool2943     pub fn disabled_state(&self) -> bool {
2944         self.state.get().contains(ElementState::IN_DISABLED_STATE)
2945     }
2946 
set_disabled_state(&self, value: bool)2947     pub fn set_disabled_state(&self, value: bool) {
2948         self.set_state(ElementState::IN_DISABLED_STATE, value)
2949     }
2950 
read_write_state(&self) -> bool2951     pub fn read_write_state(&self) -> bool {
2952         self.state.get().contains(ElementState::IN_READ_WRITE_STATE)
2953     }
2954 
set_read_write_state(&self, value: bool)2955     pub fn set_read_write_state(&self, value: bool) {
2956         self.set_state(ElementState::IN_READ_WRITE_STATE, value)
2957     }
2958 
placeholder_shown_state(&self) -> bool2959     pub fn placeholder_shown_state(&self) -> bool {
2960         self.state.get().contains(ElementState::IN_PLACEHOLDER_SHOWN_STATE)
2961     }
2962 
set_placeholder_shown_state(&self, value: bool)2963     pub fn set_placeholder_shown_state(&self, value: bool) {
2964         if self.placeholder_shown_state() != value {
2965             self.set_state(ElementState::IN_PLACEHOLDER_SHOWN_STATE, value);
2966             self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
2967         }
2968     }
2969 
target_state(&self) -> bool2970     pub fn target_state(&self) -> bool {
2971         self.state.get().contains(ElementState::IN_TARGET_STATE)
2972     }
2973 
set_target_state(&self, value: bool)2974     pub fn set_target_state(&self, value: bool) {
2975         self.set_state(ElementState::IN_TARGET_STATE, value)
2976     }
2977 
fullscreen_state(&self) -> bool2978     pub fn fullscreen_state(&self) -> bool {
2979         self.state.get().contains(ElementState::IN_FULLSCREEN_STATE)
2980     }
2981 
set_fullscreen_state(&self, value: bool)2982     pub fn set_fullscreen_state(&self, value: bool) {
2983         self.set_state(ElementState::IN_FULLSCREEN_STATE, value)
2984     }
2985 
2986     /// <https://dom.spec.whatwg.org/#connected>
is_connected(&self) -> bool2987     pub fn is_connected(&self) -> bool {
2988         let node = self.upcast::<Node>();
2989         let root = node.GetRootNode();
2990         root.is::<Document>()
2991     }
2992 }
2993 
2994 impl Element {
check_ancestors_disabled_state_for_form_control(&self)2995     pub fn check_ancestors_disabled_state_for_form_control(&self) {
2996         let node = self.upcast::<Node>();
2997         if self.disabled_state() {
2998             return;
2999         }
3000         for ancestor in node.ancestors() {
3001             if !ancestor.is::<HTMLFieldSetElement>() {
3002                 continue;
3003             }
3004             if !ancestor.downcast::<Element>().unwrap().disabled_state() {
3005                 continue;
3006             }
3007             if ancestor.is_parent_of(node) {
3008                 self.set_disabled_state(true);
3009                 self.set_enabled_state(false);
3010                 return;
3011             }
3012             if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
3013                 // XXXabinader: should we save previous ancestor to avoid this iteration?
3014                 if node.ancestors().any(|ancestor| ancestor == *legend) {
3015                     continue;
3016                 }
3017             }
3018             self.set_disabled_state(true);
3019             self.set_enabled_state(false);
3020             return;
3021         }
3022     }
3023 
check_parent_disabled_state_for_option(&self)3024     pub fn check_parent_disabled_state_for_option(&self) {
3025         if self.disabled_state() {
3026             return;
3027         }
3028         let node = self.upcast::<Node>();
3029         if let Some(ref parent) = node.GetParentNode() {
3030             if parent.is::<HTMLOptGroupElement>() &&
3031                parent.downcast::<Element>().unwrap().disabled_state() {
3032                 self.set_disabled_state(true);
3033                 self.set_enabled_state(false);
3034             }
3035         }
3036     }
3037 
check_disabled_attribute(&self)3038     pub fn check_disabled_attribute(&self) {
3039         let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
3040         self.set_disabled_state(has_disabled_attrib);
3041         self.set_enabled_state(!has_disabled_attrib);
3042     }
3043 }
3044 
3045 #[derive(Clone, Copy)]
3046 pub enum AttributeMutation<'a> {
3047     /// The attribute is set, keep track of old value.
3048     /// <https://dom.spec.whatwg.org/#attribute-is-set>
3049     Set(Option<&'a AttrValue>),
3050 
3051     /// The attribute is removed.
3052     /// <https://dom.spec.whatwg.org/#attribute-is-removed>
3053     Removed,
3054 }
3055 
3056 impl<'a> AttributeMutation<'a> {
is_removal(&self) -> bool3057     pub fn is_removal(&self) -> bool {
3058         match *self {
3059             AttributeMutation::Removed => true,
3060             AttributeMutation::Set(..) => false,
3061         }
3062     }
3063 
new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>>3064     pub fn new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>> {
3065         match *self {
3066             AttributeMutation::Set(_) => Some(attr.value()),
3067             AttributeMutation::Removed => None,
3068         }
3069     }
3070 }
3071 
3072 /// A holder for an element's "tag name", which will be lazily
3073 /// resolved and cached. Should be reset when the document
3074 /// owner changes.
3075 #[derive(JSTraceable, MallocSizeOf)]
3076 struct TagName {
3077     ptr: DomRefCell<Option<LocalName>>,
3078 }
3079 
3080 impl TagName {
new() -> TagName3081     fn new() -> TagName {
3082         TagName { ptr: DomRefCell::new(None) }
3083     }
3084 
3085     /// Retrieve a copy of the current inner value. If it is `None`, it is
3086     /// initialized with the result of `cb` first.
or_init<F>(&self, cb: F) -> LocalName where F: FnOnce() -> LocalName3087     fn or_init<F>(&self, cb: F) -> LocalName
3088         where F: FnOnce() -> LocalName
3089     {
3090         match &mut *self.ptr.borrow_mut() {
3091             &mut Some(ref name) => name.clone(),
3092             ptr => {
3093                 let name = cb();
3094                 *ptr = Some(name.clone());
3095                 name
3096             }
3097         }
3098     }
3099 
3100     /// Clear the cached tag name, so that it will be re-calculated the
3101     /// next time that `or_init()` is called.
clear(&self)3102     fn clear(&self) {
3103         *self.ptr.borrow_mut() = None;
3104     }
3105 }
3106 
3107 pub struct ElementPerformFullscreenEnter {
3108     element: Trusted<Element>,
3109     promise: TrustedPromise,
3110     error: bool,
3111 }
3112 
3113 impl ElementPerformFullscreenEnter {
new(element: Trusted<Element>, promise: TrustedPromise, error: bool) -> Box<ElementPerformFullscreenEnter>3114     pub fn new(element: Trusted<Element>, promise: TrustedPromise, error: bool) -> Box<ElementPerformFullscreenEnter> {
3115         Box::new(ElementPerformFullscreenEnter {
3116             element: element,
3117             promise: promise,
3118             error: error,
3119         })
3120     }
3121 }
3122 
3123 impl TaskOnce for ElementPerformFullscreenEnter {
3124     #[allow(unrooted_must_root)]
run_once(self)3125     fn run_once(self) {
3126         let element = self.element.root();
3127         let promise = self.promise.root();
3128         let document = document_from_node(element.r());
3129 
3130         // Step 7.1
3131         if self.error || !element.fullscreen_element_ready_check() {
3132             document.upcast::<EventTarget>().fire_event(atom!("fullscreenerror"));
3133             promise.reject_error(Error::Type(String::from("fullscreen is not connected")));
3134             return
3135         }
3136 
3137         // TODO Step 7.2-4
3138         // Step 7.5
3139         element.set_fullscreen_state(true);
3140         document.set_fullscreen_element(Some(&element));
3141         document.window().reflow(ReflowGoal::Full, ReflowReason::ElementStateChanged);
3142 
3143         // Step 7.6
3144         document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
3145 
3146         // Step 7.7
3147         promise.resolve_native(&());
3148     }
3149 }
3150 
3151 pub struct ElementPerformFullscreenExit {
3152     element: Trusted<Element>,
3153     promise: TrustedPromise,
3154 }
3155 
3156 impl ElementPerformFullscreenExit {
new(element: Trusted<Element>, promise: TrustedPromise) -> Box<ElementPerformFullscreenExit>3157     pub fn new(element: Trusted<Element>, promise: TrustedPromise) -> Box<ElementPerformFullscreenExit> {
3158         Box::new(ElementPerformFullscreenExit {
3159             element: element,
3160             promise: promise,
3161         })
3162     }
3163 }
3164 
3165 impl TaskOnce for ElementPerformFullscreenExit {
3166     #[allow(unrooted_must_root)]
run_once(self)3167     fn run_once(self) {
3168         let element = self.element.root();
3169         let document = document_from_node(element.r());
3170         // TODO Step 9.1-5
3171         // Step 9.6
3172         element.set_fullscreen_state(false);
3173 
3174         document.window().reflow(ReflowGoal::Full, ReflowReason::ElementStateChanged);
3175 
3176         document.set_fullscreen_element(None);
3177 
3178         // Step 9.8
3179         document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
3180 
3181         // Step 9.10
3182         self.promise.root().resolve_native(&());
3183     }
3184 }
3185 
reflect_cross_origin_attribute(element: &Element) -> Option<DOMString>3186 pub fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
3187     let attr = element.get_attribute(&ns!(), &local_name!("crossorigin"));
3188 
3189     if let Some(mut val) = attr.map(|v| v.Value()) {
3190         val.make_ascii_lowercase();
3191         if val == "anonymous" || val == "use-credentials" {
3192             return Some(val);
3193         }
3194         return Some(DOMString::from("anonymous"));
3195     }
3196     None
3197 }
3198 
set_cross_origin_attribute(element: &Element, value: Option<DOMString>)3199 pub fn set_cross_origin_attribute(element: &Element, value: Option<DOMString>) {
3200     match value {
3201         Some(val) => element.set_string_attribute(&local_name!("crossorigin"), val),
3202         None => {
3203             element.remove_attribute(&ns!(), &local_name!("crossorigin"));
3204         }
3205     }
3206 }
3207 
cors_setting_for_element(element: &Element) -> Option<CorsSettings>3208 pub fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
3209     reflect_cross_origin_attribute(element).map_or(None, |attr| {
3210         match &*attr {
3211             "anonymous" => Some(CorsSettings::Anonymous),
3212             "use-credentials" => Some(CorsSettings::UseCredentials),
3213             _ => unreachable!()
3214         }
3215     })
3216 }
3217