servo: Merge #7965 - Implement 'labels' attribute on 'labelable elements' (from frewsxcv:labelable-elements-label-attribute); r=nox
authorCorey Farwell <coreyf@rwell.org>
Sun, 01 Nov 2015 20:21:48 +0500
changeset 337465 b0e6b686660da95c9b0fe3f92d9ee70023e5a7e4
parent 337464 df250fc8e7b593b8681b67e57445a95052338056
child 337466 d6f150fa20c8814ddc2cc08c730eda43cf27a6c5
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnox
servo: Merge #7965 - Implement 'labels' attribute on 'labelable elements' (from frewsxcv:labelable-elements-label-attribute); r=nox Source-Repo: https://github.com/servo/servo Source-Revision: 0e70a1f8a88fb1962e4ada447479b4228d09d724
servo/components/script/dom/htmlbuttonelement.rs
servo/components/script/dom/htmlelement.rs
servo/components/script/dom/htmlinputelement.rs
servo/components/script/dom/htmllabelelement.rs
servo/components/script/dom/htmlmeterelement.rs
servo/components/script/dom/htmloutputelement.rs
servo/components/script/dom/htmlprogresselement.rs
servo/components/script/dom/htmlselectelement.rs
servo/components/script/dom/htmltextareaelement.rs
servo/components/script/dom/nodelist.rs
servo/components/script/dom/webidls/HTMLButtonElement.webidl
servo/components/script/dom/webidls/HTMLInputElement.webidl
servo/components/script/dom/webidls/HTMLMeterElement.webidl
servo/components/script/dom/webidls/HTMLOutputElement.webidl
servo/components/script/dom/webidls/HTMLProgressElement.webidl
servo/components/script/dom/webidls/HTMLSelectElement.webidl
servo/components/script/dom/webidls/HTMLTextAreaElement.webidl
--- a/servo/components/script/dom/htmlbuttonelement.rs
+++ b/servo/components/script/dom/htmlbuttonelement.rs
@@ -12,16 +12,17 @@ use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::event::Event;
 use dom::eventtarget::EventTarget;
 use dom::htmlelement::HTMLElement;
 use dom::htmlfieldsetelement::HTMLFieldSetElement;
 use dom::htmlformelement::{FormControl, FormSubmitter};
 use dom::htmlformelement::{SubmittedFrom, HTMLFormElement};
 use dom::node::{Node, document_from_node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::validitystate::ValidityState;
 use dom::virtualmethods::VirtualMethods;
 use selectors::states::*;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use util::str::DOMString;
 
@@ -126,16 +127,21 @@ impl HTMLButtonElementMethods for HTMLBu
     // https://html.spec.whatwg.org/multipage/#dom-fe-name
     make_setter!(SetName, "name");
 
     // https://html.spec.whatwg.org/multipage/#dom-button-value
     make_getter!(Value);
 
     // https://html.spec.whatwg.org/multipage/#dom-button-value
     make_setter!(SetValue, "value");
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
 }
 
 impl VirtualMethods for HTMLButtonElement {
     fn super_type(&self) -> Option<&VirtualMethods> {
         Some(self.upcast::<HTMLElement>() as &VirtualMethods)
     }
 
     fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
--- a/servo/components/script/dom/htmlelement.rs
+++ b/servo/components/script/dom/htmlelement.rs
@@ -1,35 +1,38 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::attr::Attr;
 use dom::attr::AttrValue;
+use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
 use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
 use dom::bindings::codegen::Bindings::HTMLElementBinding;
 use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
 use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
 use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
 use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId};
 use dom::bindings::conversions::Castable;
 use dom::bindings::error::{Error, ErrorResult};
-use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
 use dom::bindings::utils::Reflectable;
 use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration};
 use dom::document::Document;
 use dom::domstringmap::DOMStringMap;
 use dom::element::{AttributeMutation, Element};
 use dom::eventtarget::EventTarget;
 use dom::htmlbodyelement::HTMLBodyElement;
 use dom::htmlframesetelement::HTMLFrameSetElement;
 use dom::htmlhtmlelement::HTMLHtmlElement;
 use dom::htmlinputelement::HTMLInputElement;
+use dom::htmllabelelement::HTMLLabelElement;
 use dom::node::{Node, SEQUENTIALLY_FOCUSABLE};
 use dom::node::{document_from_node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::virtualmethods::VirtualMethods;
 use msg::constellation_msg::FocusType;
 use selectors::states::*;
 use std::ascii::AsciiExt;
 use std::borrow::ToOwned;
 use std::default::Default;
 use std::intrinsics;
 use std::rc::Rc;
@@ -360,16 +363,55 @@ impl HTMLElement {
 
     pub fn supported_prop_names_custom_attr(&self) -> Vec<DOMString> {
         let element = self.upcast::<Element>();
         element.attrs().iter().filter_map(|attr| {
             let raw_name = attr.local_name();
             to_camel_case(&raw_name)
         }).collect()
     }
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    pub fn labels(&self) -> Root<NodeList> {
+        debug_assert!(self.is_labelable_element());
+
+        let element = self.upcast::<Element>();
+        let window = window_from_node(element);
+
+        // Traverse ancestors for implicitly associated <label> elements
+        // https://html.spec.whatwg.org/multipage/#the-label-element:attr-label-for-4
+        let ancestors =
+            self.upcast::<Node>()
+                .ancestors()
+                .filter_map(Root::downcast::<HTMLElement>)
+                // If we reach a labelable element, we have a guarantee no ancestors above it
+                // will be a label for this HTMLElement
+                .take_while(|elem| !elem.is_labelable_element())
+                .filter_map(Root::downcast::<HTMLLabelElement>)
+                .filter(|elem| !elem.upcast::<Element>().has_attribute(&atom!("for")))
+                .filter(|elem| elem.first_labelable_descendant().r() == Some(self))
+                .map(Root::upcast::<Node>);
+
+        let id = element.Id();
+        let id = match &id as &str {
+            "" => return NodeList::new_simple_list(window.r(), ancestors),
+            id => id,
+        };
+
+        // Traverse entire tree for <label> elements with `for` attribute matching `id`
+        let root_element = element.get_root_element();
+        let root_node = root_element.upcast::<Node>();
+        let children = root_node.traverse_preorder()
+                                .filter_map(Root::downcast::<Element>)
+                                .filter(|elem| elem.is::<HTMLLabelElement>())
+                                .filter(|elem| elem.get_string_attribute(&atom!("for")) == id)
+                                .map(Root::upcast::<Node>);
+
+        NodeList::new_simple_list(window.r(), children.chain(ancestors))
+    }
 }
 
 impl VirtualMethods for HTMLElement {
     fn super_type(&self) -> Option<&VirtualMethods> {
         Some(self.upcast::<Element>() as &VirtualMethods)
     }
 
     fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
--- a/servo/components/script/dom/htmlinputelement.rs
+++ b/servo/components/script/dom/htmlinputelement.rs
@@ -20,16 +20,17 @@ use dom::event::{Event, EventBubbles, Ev
 use dom::eventtarget::EventTarget;
 use dom::htmlelement::HTMLElement;
 use dom::htmlfieldsetelement::HTMLFieldSetElement;
 use dom::htmlformelement::{FormControl, FormDatum, FormSubmitter, HTMLFormElement};
 use dom::htmlformelement::{ResetFrom, SubmittedFrom};
 use dom::keyboardevent::KeyboardEvent;
 use dom::node::{Node, NodeDamage};
 use dom::node::{document_from_node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::virtualmethods::VirtualMethods;
 use msg::constellation_msg::ConstellationChan;
 use selectors::states::*;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use string_cache::Atom;
 use textinput::KeyReaction::{DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction};
 use textinput::Lines::Single;
@@ -328,16 +329,26 @@ impl HTMLInputElementMethods for HTMLInp
     fn Indeterminate(&self) -> bool {
         self.upcast::<Element>().get_state().contains(IN_INDETERMINATE_STATE)
     }
 
     // https://html.spec.whatwg.org/multipage/#dom-input-indeterminate
     fn SetIndeterminate(&self, val: bool) {
         self.upcast::<Element>().set_state(IN_INDETERMINATE_STATE, val)
     }
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        if self.Type() == "hidden" {
+            let window = window_from_node(self);
+            NodeList::empty(&window)
+        } else {
+            self.upcast::<HTMLElement>().labels()
+        }
+    }
 }
 
 
 #[allow(unsafe_code)]
 fn broadcast_radio_checked(broadcaster: &HTMLInputElement, group: Option<&Atom>) {
     match group {
         None | Some(&atom!("")) => {
             // Radio input elements with a missing or empty name are alone in their
--- a/servo/components/script/dom/htmllabelelement.rs
+++ b/servo/components/script/dom/htmllabelelement.rs
@@ -118,17 +118,17 @@ impl VirtualMethods for HTMLLabelElement
         match name {
             &atom!("for") => AttrValue::from_atomic(value),
             _ => self.super_type().unwrap().parse_plain_attribute(name, value),
         }
     }
 }
 
 impl HTMLLabelElement {
-    fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> {
+    pub fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> {
         self.upcast::<Node>()
             .traverse_preorder()
             .filter_map(Root::downcast::<HTMLElement>)
             .filter(|elem| elem.is_labelable_element())
             .next()
     }
 }
 
--- a/servo/components/script/dom/htmlmeterelement.rs
+++ b/servo/components/script/dom/htmlmeterelement.rs
@@ -1,17 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use dom::bindings::codegen::Bindings::HTMLMeterElementBinding;
+use dom::bindings::codegen::Bindings::HTMLMeterElementBinding::{self, HTMLMeterElementMethods};
+use dom::bindings::conversions::Castable;
 use dom::bindings::js::Root;
 use dom::document::Document;
 use dom::htmlelement::HTMLElement;
 use dom::node::Node;
+use dom::nodelist::NodeList;
 use util::str::DOMString;
 
 #[dom_struct]
 pub struct HTMLMeterElement {
     htmlelement: HTMLElement
 }
 
 impl HTMLMeterElement {
@@ -26,8 +28,15 @@ impl HTMLMeterElement {
     #[allow(unrooted_must_root)]
     pub fn new(localName: DOMString,
                prefix: Option<DOMString>,
                document: &Document) -> Root<HTMLMeterElement> {
         let element = HTMLMeterElement::new_inherited(localName, prefix, document);
         Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap)
     }
 }
+
+impl HTMLMeterElementMethods for HTMLMeterElement {
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
+}
--- a/servo/components/script/dom/htmloutputelement.rs
+++ b/servo/components/script/dom/htmloutputelement.rs
@@ -1,19 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::bindings::codegen::Bindings::HTMLOutputElementBinding;
 use dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods;
+use dom::bindings::conversions::Castable;
 use dom::bindings::js::Root;
 use dom::document::Document;
 use dom::htmlelement::HTMLElement;
 use dom::htmlformelement::{FormControl, HTMLFormElement};
 use dom::node::{Node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::validitystate::ValidityState;
 use util::str::DOMString;
 
 #[dom_struct]
 pub struct HTMLOutputElement {
     htmlelement: HTMLElement
 }
 
@@ -42,11 +44,16 @@ impl HTMLOutputElementMethods for HTMLOu
         let window = window_from_node(self);
         ValidityState::new(window.r())
     }
 
     // https://html.spec.whatwg.org/multipage/#dom-fae-form
     fn GetForm(&self) -> Option<Root<HTMLFormElement>> {
         self.form_owner()
     }
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
 }
 
 impl FormControl for HTMLOutputElement {}
--- a/servo/components/script/dom/htmlprogresselement.rs
+++ b/servo/components/script/dom/htmlprogresselement.rs
@@ -1,17 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use dom::bindings::codegen::Bindings::HTMLProgressElementBinding;
+use dom::bindings::codegen::Bindings::HTMLProgressElementBinding::{self, HTMLProgressElementMethods};
+use dom::bindings::conversions::Castable;
 use dom::bindings::js::Root;
 use dom::document::Document;
 use dom::htmlelement::HTMLElement;
 use dom::node::Node;
+use dom::nodelist::NodeList;
 use util::str::DOMString;
 
 #[dom_struct]
 pub struct HTMLProgressElement {
     htmlelement: HTMLElement,
 }
 
 impl HTMLProgressElement {
@@ -27,8 +29,15 @@ impl HTMLProgressElement {
     #[allow(unrooted_must_root)]
     pub fn new(localName: DOMString,
                prefix: Option<DOMString>,
                document: &Document) -> Root<HTMLProgressElement> {
         let element = HTMLProgressElement::new_inherited(localName, prefix, document);
         Node::reflect_node(box element, document, HTMLProgressElementBinding::Wrap)
     }
 }
+
+impl HTMLProgressElementMethods for HTMLProgressElement {
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
+}
--- a/servo/components/script/dom/htmlselectelement.rs
+++ b/servo/components/script/dom/htmlselectelement.rs
@@ -12,16 +12,17 @@ use dom::bindings::conversions::Castable
 use dom::bindings::js::Root;
 use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::htmlelement::HTMLElement;
 use dom::htmlfieldsetelement::HTMLFieldSetElement;
 use dom::htmlformelement::{FormControl, HTMLFormElement};
 use dom::htmloptionelement::HTMLOptionElement;
 use dom::node::{Node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::validitystate::ValidityState;
 use dom::virtualmethods::VirtualMethods;
 use selectors::states::*;
 use std::borrow::ToOwned;
 use string_cache::Atom;
 use util::str::DOMString;
 
 #[dom_struct]
@@ -153,16 +154,21 @@ impl HTMLSelectElementMethods for HTMLSe
     // https://html.spec.whatwg.org/multipage/#dom-select-type
     fn Type(&self) -> DOMString {
         if self.Multiple() {
             "select-multiple".to_owned()
         } else {
             "select-one".to_owned()
         }
     }
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
 }
 
 impl VirtualMethods for HTMLSelectElement {
     fn super_type(&self) -> Option<&VirtualMethods> {
         Some(self.upcast::<HTMLElement>() as &VirtualMethods)
     }
 
     fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
--- a/servo/components/script/dom/htmltextareaelement.rs
+++ b/servo/components/script/dom/htmltextareaelement.rs
@@ -17,16 +17,17 @@ use dom::element::{AttributeMutation, El
 use dom::event::{Event, EventBubbles, EventCancelable};
 use dom::eventtarget::EventTarget;
 use dom::htmlelement::HTMLElement;
 use dom::htmlfieldsetelement::HTMLFieldSetElement;
 use dom::htmlformelement::{FormControl, HTMLFormElement};
 use dom::keyboardevent::KeyboardEvent;
 use dom::node::{ChildrenMutation, Node, NodeDamage};
 use dom::node::{document_from_node, window_from_node};
+use dom::nodelist::NodeList;
 use dom::virtualmethods::VirtualMethods;
 use msg::constellation_msg::ConstellationChan;
 use script_task::ScriptTaskEventCategory::InputEvent;
 use script_task::{CommonScriptMsg, Runnable};
 use selectors::states::*;
 use std::borrow::ToOwned;
 use std::cell::Cell;
 use string_cache::Atom;
@@ -200,16 +201,21 @@ impl HTMLTextAreaElementMethods for HTML
     // https://html.spec.whatwg.org/multipage/#dom-textarea-value
     fn SetValue(&self, value: DOMString) {
         // TODO move the cursor to the end of the field
         self.textinput.borrow_mut().set_content(value);
         self.value_changed.set(true);
 
         self.force_relayout();
     }
+
+    // https://html.spec.whatwg.org/multipage/#dom-lfe-labels
+    fn Labels(&self) -> Root<NodeList> {
+        self.upcast::<HTMLElement>().labels()
+    }
 }
 
 
 impl HTMLTextAreaElement {
     // https://html.spec.whatwg.org/multipage/#concept-fe-mutable
     pub fn mutable(&self) -> bool {
         // https://html.spec.whatwg.org/multipage/#the-textarea-element:concept-fe-mutable
         !(self.Disabled() || self.ReadOnly())
--- a/servo/components/script/dom/nodelist.rs
+++ b/servo/components/script/dom/nodelist.rs
@@ -46,16 +46,20 @@ impl NodeList {
                               -> Root<NodeList>
                               where T: Iterator<Item=Root<Node>> {
         NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_rooted(&r)).collect()))
     }
 
     pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
         NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
     }
+
+    pub fn empty(window: &Window) -> Root<NodeList> {
+        NodeList::new(window, NodeListType::Simple(vec![]))
+    }
 }
 
 impl NodeListMethods for NodeList {
     // https://dom.spec.whatwg.org/#dom-nodelist-length
     fn Length(&self) -> u32 {
         match self.list_type {
             NodeListType::Simple(ref elems) => elems.len() as u32,
             NodeListType::Children(ref list) => list.len(),
--- a/servo/components/script/dom/webidls/HTMLButtonElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLButtonElement.webidl
@@ -20,10 +20,10 @@ interface HTMLButtonElement : HTMLElemen
 
   //readonly attribute boolean willValidate;
   readonly attribute ValidityState validity;
   //readonly attribute DOMString validationMessage;
   //boolean checkValidity();
   //boolean reportValidity();
   //void setCustomValidity(DOMString error);
 
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 };
--- a/servo/components/script/dom/webidls/HTMLInputElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLInputElement.webidl
@@ -52,17 +52,17 @@ interface HTMLInputElement : HTMLElement
 
   //readonly attribute boolean willValidate;
   //readonly attribute ValidityState validity;
   //readonly attribute DOMString validationMessage;
   //boolean checkValidity();
   //boolean reportValidity();
   //void setCustomValidity(DOMString error);
 
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 
   //void select();
   //         attribute unsigned long selectionStart;
   //         attribute unsigned long selectionEnd;
   //         attribute DOMString selectionDirection;
   //void setRangeText(DOMString replacement);
   //void setRangeText(DOMString replacement, unsigned long start, unsigned long end,
   //                  optional SelectionMode selectionMode = "preserve");
--- a/servo/components/script/dom/webidls/HTMLMeterElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLMeterElement.webidl
@@ -6,10 +6,10 @@
 // https://html.spec.whatwg.org/multipage/#htmlmeterelement
 interface HTMLMeterElement : HTMLElement {
   //         attribute double value;
   //         attribute double min;
   //         attribute double max;
   //         attribute double low;
   //         attribute double high;
   //         attribute double optimum;
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 };
--- a/servo/components/script/dom/webidls/HTMLOutputElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLOutputElement.webidl
@@ -15,10 +15,10 @@ interface HTMLOutputElement : HTMLElemen
 
   //readonly attribute boolean willValidate;
   readonly attribute ValidityState validity;
   //readonly attribute DOMString validationMessage;
   //boolean checkValidity();
   //boolean reportValidity();
   //void setCustomValidity(DOMString error);
 
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 };
--- a/servo/components/script/dom/webidls/HTMLProgressElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLProgressElement.webidl
@@ -3,10 +3,10 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // https://html.spec.whatwg.org/multipage/#htmlprogresselement
 interface HTMLProgressElement : HTMLElement {
   //         attribute double value;
   //         attribute double max;
   //readonly attribute double position;
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 };
--- a/servo/components/script/dom/webidls/HTMLSelectElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLSelectElement.webidl
@@ -31,10 +31,10 @@ interface HTMLSelectElement : HTMLElemen
 
   //readonly attribute boolean willValidate;
   readonly attribute ValidityState validity;
   //readonly attribute DOMString validationMessage;
   //boolean checkValidity();
   //boolean reportValidity();
   //void setCustomValidity(DOMString error);
 
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 };
--- a/servo/components/script/dom/webidls/HTMLTextAreaElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLTextAreaElement.webidl
@@ -30,17 +30,17 @@ interface HTMLTextAreaElement : HTMLElem
 
   //readonly attribute boolean willValidate;
   //readonly attribute ValidityState validity;
   //readonly attribute DOMString validationMessage;
   //boolean checkValidity();
   //boolean reportValidity();
   //void setCustomValidity(DOMString error);
 
-  //readonly attribute NodeList labels;
+  readonly attribute NodeList labels;
 
   //void select();
   //         attribute unsigned long selectionStart;
   //         attribute unsigned long selectionEnd;
   //         attribute DOMString selectionDirection;
   //void setRangeText(DOMString replacement);
   //void setRangeText(DOMString replacement, unsigned long start, unsigned long end,
   //                  optional SelectionMode selectionMode = "preserve");