Bug 838582 - Part 2: Move HTMLTextAreaElement to Web IDL bindings; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 19 Feb 2013 00:54:23 -0500
changeset 122665 87ab1cbdcea34320a9f21dc4e709620b8b587c20
parent 122664 2b40ffaf95cbfa2a3924a72d98e4e7502b2500f3
child 122666 e7d1e1d555344d9bd7927cc736c1eac3b98600e7
push id23426
push usereakhgari@mozilla.com
push dateFri, 22 Feb 2013 17:17:43 +0000
treeherdermozilla-inbound@87ab1cbdcea3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs838582
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 838582 - Part 2: Move HTMLTextAreaElement to Web IDL bindings; r=bzbarsky
content/base/test/test_bug166235.html
content/base/test/test_copypaste.html
content/html/content/src/HTMLTextAreaElement.cpp
content/html/content/src/HTMLTextAreaElement.h
content/html/content/test/Makefile.in
content/html/content/test/reflect.js
content/html/content/test/test_bug388558.html
content/html/content/test/test_bug838582.html
dom/bindings/Bindings.conf
dom/interfaces/core/nsIDOMNSEditableElement.idl
dom/interfaces/html/nsIDOMHTMLTextAreaElement.idl
dom/plugins/test/mochitest/test_copyText.html
dom/webidl/HTMLTextAreaElement.webidl
dom/webidl/WebIDL.mk
editor/composer/test/test_bug338427.html
editor/libeditor/text/tests/test_bug596333.html
editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
layout/forms/test/test_bug595310.html
layout/generic/test/test_selection_expanding.html
--- a/content/base/test/test_bug166235.html
+++ b/content/base/test/test_bug166235.html
@@ -35,17 +35,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   var docShell = webnav.QueryInterface(SpecialPowers.Ci.nsIDocShell);
 
   var documentViewer = docShell.contentViewer
                                .QueryInterface(SpecialPowers.Ci.nsIContentViewerEdit);
 
   var clipboard = Cc["@mozilla.org/widget/clipboard;1"]
                     .getService(SpecialPowers.Ci.nsIClipboard);
 
-  var textarea = SpecialPowers.wrap(document).getElementById('input');
+  var textarea = SpecialPowers.wrap(document.getElementById('input'));
 
   function getLoadContext() {
     return SpecialPowers.wrap(window).QueryInterface(Ci.nsIInterfaceRequestor)
                                      .getInterface(Ci.nsIWebNavigation)
                                      .QueryInterface(Ci.nsILoadContext);
   }
 
   function copyChildrenToClipboard(id) {
@@ -73,18 +73,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data,
       expected,
       mime + " value in the clipboard");
     return data.value;
   }
   function testPasteText(expected, test) {
     textarea.value="";
     textarea.focus();
-    textarea.QueryInterface(SpecialPowers.Ci.nsIDOMNSEditableElement)
-            .editor.paste(1);
+    textarea.editor.paste(1);
     is(textarea.value, expected, test + ": textarea paste");
   }
   function testInnerHTML(id, expected) {
     var value = document.getElementById(id).innerHTML;
     is(value, expected, id + ".innerHTML");
   }
 
 // expected results for Selection.toString()
--- a/content/base/test/test_copypaste.html
+++ b/content/base/test/test_copypaste.html
@@ -51,17 +51,17 @@ function testCopyPaste () {
   var docShell = webnav.QueryInterface(Components.interfaces.nsIDocShell);
 
   var documentViewer = docShell.contentViewer
                                .QueryInterface(Components.interfaces.nsIContentViewerEdit);
 
   var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
                             .getService(Components.interfaces.nsIClipboard);
 
-  var textarea = document.getElementById('input');
+  var textarea = SpecialPowers.wrap(document.getElementById('input'));
 
   function copySelectionToClipboard() {
     documentViewer.copySelection();
     ok(clipboard.hasDataMatchingFlavors(["text/unicode"], 1,1), "check text/unicode");
     ok(clipboard.hasDataMatchingFlavors(["text/html"], 1,1), "check text/html");
   }
   function copyToClipboard(node) {
     textarea.blur();
@@ -106,18 +106,17 @@ function testCopyPaste () {
         data.value.QueryInterface(Components.interfaces.nsISupportsString).data,
       expected,
       mime + " value in the clipboard");
     return data.value;
   }
   function testPasteText(expected) {
     textarea.value="";
     textarea.focus();
-    textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement)
-            .editor.paste(1);
+    textarea.editor.paste(1);
     is(textarea.value, expected, "value of the textarea after the paste");
   }
   function testSelectionToString(expected) {
     is(window.getSelection().toString().replace(/\r\n/g,"\n"), expected, "Selection.toString");
   }
   function testInnerHTML(id, expected) {
     var value = document.getElementById(id).innerHTML;
     is(value, expected, id + ".innerHTML");
--- a/content/html/content/src/HTMLTextAreaElement.cpp
+++ b/content/html/content/src/HTMLTextAreaElement.cpp
@@ -1,29 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=2 et tw=80: */
 /* 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/. */
 
 #include "mozilla/dom/HTMLTextAreaElement.h"
+#include "mozilla/dom/HTMLTextAreaElementBinding.h"
 #include "mozilla/Util.h"
 
 #include "nsIControllers.h"
 #include "nsFocusManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsContentCID.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIFormControl.h"
 #include "nsIForm.h"
 #include "nsFormSubmission.h"
 #include "nsIDOMEventTarget.h"
 #include "nsAttrValueInlines.h"
-#include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
 #include "nsIFormControlFrame.h"
 #include "nsITextControlFrame.h"
 #include "nsLinebreakConverter.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
@@ -68,16 +68,18 @@ HTMLTextAreaElement::HTMLTextAreaElement
   // Set up our default state.  By default we're enabled (since we're
   // a control type that can be disabled but not actually disabled
   // right now), optional, and valid.  We are NOT readwrite by default
   // until someone calls UpdateEditableState on us, apparently!  Also
   // by default we don't have to show validity UI and so forth.
   AddStatesSilently(NS_EVENT_STATE_ENABLED |
                     NS_EVENT_STATE_OPTIONAL |
                     NS_EVENT_STATE_VALID);
+
+  SetIsDOMBinding();
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLTextAreaElement,
                                                 nsGenericHTMLFormElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   tmp->mState.Unlink();
@@ -231,17 +233,17 @@ void
 HTMLTextAreaElement::GetValueInternal(nsAString& aValue, bool aIgnoreWrap) const
 {
   mState.GetValue(aValue, aIgnoreWrap);
 }
 
 NS_IMETHODIMP_(nsIEditor*)
 HTMLTextAreaElement::GetTextEditor()
 {
-  return mState.GetEditor();
+  return GetEditor();
 }
 
 NS_IMETHODIMP_(nsISelectionController*)
 HTMLTextAreaElement::GetSelectionController()
 {
   return mState.GetSelectionController();
 }
 
@@ -366,21 +368,31 @@ HTMLTextAreaElement::GetDefaultValue(nsA
 {
   nsContentUtils::GetNodeTextContent(this, false, aDefaultValue);
   return NS_OK;
 }  
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue)
 {
+  ErrorResult error;
+  SetDefaultValue(aDefaultValue, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aError)
+{
   nsresult rv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true);
   if (NS_SUCCEEDED(rv) && !mValueChanged) {
     Reset();
   }
-  return rv;
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
 }
 
 bool
 HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID,
                                     nsIAtom* aAttribute,
                                     const nsAString& aValue,
                                     nsAttrValue& aResult)
 {
@@ -558,127 +570,201 @@ HTMLTextAreaElement::DoneAddingChildren(
 bool
 HTMLTextAreaElement::IsDoneAddingChildren()
 {
   return mDoneAddingChildren;
 }
 
 // Controllers Methods
 
+nsIControllers*
+HTMLTextAreaElement::GetControllers(ErrorResult& aError)
+{
+  if (!mControllers)
+  {
+    nsresult rv;
+    mControllers = do_CreateInstance(kXULControllersCID, &rv);
+    if (NS_FAILED(rv)) {
+      aError.Throw(rv);
+      return nullptr;
+    }
+
+    nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/editorcontroller;1", &rv);
+    if (NS_FAILED(rv)) {
+      aError.Throw(rv);
+      return nullptr;
+    }
+
+    mControllers->AppendController(controller);
+
+    controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1", &rv);
+    if (NS_FAILED(rv)) {
+      aError.Throw(rv);
+      return nullptr;
+    }
+
+    mControllers->AppendController(controller);
+  }
+
+  return mControllers;
+}
+
 NS_IMETHODIMP
 HTMLTextAreaElement::GetControllers(nsIControllers** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
 
-  if (!mControllers)
-  {
-    nsresult rv;
-    mControllers = do_CreateInstance(kXULControllersCID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/editorcontroller;1", &rv);
-    if (NS_FAILED(rv))
-      return rv;
-
-    mControllers->AppendController(controller);
-
-    controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1", &rv);
-    if (NS_FAILED(rv))
-      return rv;
-
-    mControllers->AppendController(controller);
-  }
-
-  *aResult = mControllers;
+  ErrorResult error;
+  *aResult = GetControllers(error);
   NS_IF_ADDREF(*aResult);
 
-  return NS_OK;
+  return error.ErrorCode();
+}
+
+uint32_t
+HTMLTextAreaElement::GetTextLength()
+{
+  nsAutoString val;
+  GetValue(val);
+  return val.Length();
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::GetTextLength(int32_t *aTextLength)
 {
   NS_ENSURE_ARG_POINTER(aTextLength);
-  nsAutoString val;
-  nsresult rv = GetValue(val);
-  *aTextLength = val.Length();
+  *aTextLength = GetTextLength();
 
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::GetSelectionStart(int32_t *aSelectionStart)
 {
   NS_ENSURE_ARG_POINTER(aSelectionStart);
 
-  int32_t selEnd;
-  nsresult rv = GetSelectionRange(aSelectionStart, &selEnd);
+  ErrorResult error;
+  *aSelectionStart = GetSelectionStart(error);
+  return error.ErrorCode();
+}
+
+uint32_t
+HTMLTextAreaElement::GetSelectionStart(ErrorResult& aError)
+{
+  int32_t selStart, selEnd;
+  nsresult rv = GetSelectionRange(&selStart, &selEnd);
 
   if (NS_FAILED(rv) && mState.IsSelectionCached()) {
-    *aSelectionStart = mState.GetSelectionProperties().mStart;
-    return NS_OK;
+    return mState.GetSelectionProperties().mStart;
   }
-  return rv;
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
+  return selStart;
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetSelectionStart(int32_t aSelectionStart)
 {
+  ErrorResult error;
+  SetSelectionStart(aSelectionStart, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::SetSelectionStart(uint32_t aSelectionStart, ErrorResult& aError)
+{
   if (mState.IsSelectionCached()) {
     mState.GetSelectionProperties().mStart = aSelectionStart;
-    return NS_OK;
+    return;
   }
 
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+    return;
+  }
   int32_t start, end;
   rv = GetSelectionRange(&start, &end);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+    return;
+  }
   start = aSelectionStart;
   if (end < start) {
     end = start;
   }
-  return SetSelectionRange(start, end, direction);
+  rv = SetSelectionRange(start, end, direction);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::GetSelectionEnd(int32_t *aSelectionEnd)
 {
   NS_ENSURE_ARG_POINTER(aSelectionEnd);
 
-  int32_t selStart;
-  nsresult rv = GetSelectionRange(&selStart, aSelectionEnd);
+  ErrorResult error;
+  *aSelectionEnd = GetSelectionEnd(error);
+  return error.ErrorCode();
+}
+
+uint32_t
+HTMLTextAreaElement::GetSelectionEnd(ErrorResult& aError)
+{
+  int32_t selStart, selEnd;
+  nsresult rv = GetSelectionRange(&selStart, &selEnd);
 
   if (NS_FAILED(rv) && mState.IsSelectionCached()) {
-    *aSelectionEnd = mState.GetSelectionProperties().mEnd;
-    return NS_OK;
+    return mState.GetSelectionProperties().mEnd;
   }
-  return rv;
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
+  return selEnd;
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetSelectionEnd(int32_t aSelectionEnd)
 {
+  ErrorResult error;
+  SetSelectionEnd(aSelectionEnd, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::SetSelectionEnd(uint32_t aSelectionEnd, ErrorResult& aError)
+{
   if (mState.IsSelectionCached()) {
     mState.GetSelectionProperties().mEnd = aSelectionEnd;
-    return NS_OK;
+    return;
   }
 
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+    return;
+  }
   int32_t start, end;
   rv = GetSelectionRange(&start, &end);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+    return;
+  }
   end = aSelectionEnd;
   if (start > end) {
     start = end;
   }
-  return SetSelectionRange(start, end, direction);
+  rv = SetSelectionRange(start, end, direction);
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
 }
 
 nsresult
 HTMLTextAreaElement::GetSelectionRange(int32_t* aSelectionStart,
                                        int32_t* aSelectionEnd)
 {
   nsresult rv = NS_ERROR_FAILURE;
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
@@ -704,16 +790,24 @@ DirectionToName(nsITextControlFrame::Sel
   } else {
     NS_NOTREACHED("Invalid SelectionDirection value");
   }
 }
 
 nsresult
 HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection)
 {
+  ErrorResult error;
+  GetSelectionDirection(aDirection, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aError)
+{
   nsresult rv = NS_ERROR_FAILURE;
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
 
   if (formControlFrame) {
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame) {
       nsITextControlFrame::SelectionDirection dir;
       rv = textControlFrame->GetSelectionRange(nullptr, nullptr, &dir);
@@ -721,73 +815,97 @@ HTMLTextAreaElement::GetSelectionDirecti
         DirectionToName(dir, aDirection);
       }
     }
   }
 
   if (NS_FAILED(rv)) {
     if (mState.IsSelectionCached()) {
       DirectionToName(mState.GetSelectionProperties().mDirection, aDirection);
-      return NS_OK;
+      return;
     }
+    aError.Throw(rv);
   }
-
-  return rv;
 }
 
 NS_IMETHODIMP
-HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection) {
+HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection)
+{
+  ErrorResult error;
+  SetSelectionDirection(aDirection, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection, ErrorResult& aError)
+{
   if (mState.IsSelectionCached()) {
     nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
     if (aDirection.EqualsLiteral("forward")) {
       dir = nsITextControlFrame::eForward;
     } else if (aDirection.EqualsLiteral("backward")) {
       dir = nsITextControlFrame::eBackward;
     }
     mState.GetSelectionProperties().mDirection = dir;
-    return NS_OK;
+    return;
   }
 
   int32_t start, end;
   nsresult rv = GetSelectionRange(&start, &end);
   if (NS_SUCCEEDED(rv)) {
     rv = SetSelectionRange(start, end, aDirection);
   }
-
-  return rv;
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetSelectionRange(int32_t aSelectionStart,
                                        int32_t aSelectionEnd,
                                        const nsAString& aDirection)
-{ 
+{
+  ErrorResult error;
+  Optional<nsAString> dir;
+  dir = &aDirection;
+  SetSelectionRange(aSelectionStart, aSelectionEnd, dir, error);
+  return error.ErrorCode();
+}
+
+void
+HTMLTextAreaElement::SetSelectionRange(uint32_t aSelectionStart,
+                                       uint32_t aSelectionEnd,
+                                       const Optional<nsAString>& aDirection,
+                                       ErrorResult& aError)
+{
   nsresult rv = NS_ERROR_FAILURE;
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
 
   if (formControlFrame) {
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame) {
       // Default to forward, even if not specified.
       // Note that we don't currently support directionless selections, so
       // "none" is treated like "forward".
       nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eForward;
-      if (aDirection.EqualsLiteral("backward")) {
+      if (aDirection.WasPassed() && aDirection.Value().EqualsLiteral("backward")) {
         dir = nsITextControlFrame::eBackward;
       }
 
       rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd, dir);
       if (NS_SUCCEEDED(rv)) {
         rv = textControlFrame->ScrollSelectionIntoView();
       }
     }
   }
 
-  return rv;
-} 
+  if (NS_FAILED(rv)) {
+    aError.Throw(rv);
+  }
+}
 
 nsresult
 HTMLTextAreaElement::Reset()
 {
   nsresult rv;
 
   // To get the initial spellchecking, reset value to
   // empty string before setting the default value.
@@ -1305,10 +1423,17 @@ void
 HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify)
 {
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
   nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
 
+JSObject*
+HTMLTextAreaElement::WrapNode(JSContext* aCx, JSObject* aScope,
+                              bool* aTriedToWrap)
+{
+  return HTMLTextAreaElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/HTMLTextAreaElement.h
+++ b/content/html/content/src/HTMLTextAreaElement.h
@@ -11,16 +11,17 @@
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsCOMPtr.h"
 #include "nsGenericHTMLElement.h"
 #include "nsEventStates.h"
 #include "nsStubMutationObserver.h"
 #include "nsIConstraintValidation.h"
 #include "nsHTMLFormElement.h"
+#include "nsGkAtoms.h"
 
 #include "nsTextEditorState.h"
 
 class nsFormSubmission;
 class nsIControllers;
 class nsIDocument;
 class nsPresContext;
 class nsPresState;
@@ -154,19 +155,133 @@ public:
   bool     IsTooLong();
   bool     IsValueMissing() const;
   void     UpdateTooLongValidityState();
   void     UpdateValueMissingValidityState();
   void     UpdateBarredFromConstraintValidation();
   nsresult GetValidationMessage(nsAString& aValidationMessage,
                                 ValidityStateType aType);
 
+  // Web IDL binding methods
+  bool Autofocus()
+  {
+    return GetBoolAttr(nsGkAtoms::autofocus);
+  }
+  void SetAutofocus(bool aAutoFocus, ErrorResult& aError)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::autofocus, aAutoFocus, aError);
+  }
+  uint32_t Cols()
+  {
+    return GetIntAttr(nsGkAtoms::cols, DEFAULT_COLS);
+  }
+  void SetCols(uint32_t aCols, ErrorResult& aError)
+  {
+    if (aCols == 0) {
+      aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    } else {
+      SetHTMLUnsignedIntAttr(nsGkAtoms::cols, aCols, aError);
+    }
+  }
+  bool Disabled()
+  {
+    return GetBoolAttr(nsGkAtoms::disabled);
+  }
+  void SetDisabled(bool aDisabled, ErrorResult& aError)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError);
+  }
+  // nsGenericHTMLFormElement::GetForm is fine
+  using nsGenericHTMLFormElement::GetForm;
+  int32_t MaxLength()
+  {
+    return GetIntAttr(nsGkAtoms::maxlength, -1);
+  }
+  void SetMaxLength(int32_t aMaxLength, ErrorResult& aError)
+  {
+    if (aMaxLength < 0) {
+      aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    } else {
+      SetHTMLIntAttr(nsGkAtoms::maxlength, aMaxLength, aError);
+    }
+  }
+  // XPCOM GetName is fine
+  void SetName(const nsAString& aName, ErrorResult& aError)
+  {
+    SetHTMLAttr(nsGkAtoms::name, aName, aError);
+  }
+  // XPCOM GetPlaceholder is fine
+  void SetPlaceholder(const nsAString& aPlaceholder, ErrorResult& aError)
+  {
+    SetHTMLAttr(nsGkAtoms::placeholder, aPlaceholder, aError);
+  }
+  bool ReadOnly()
+  {
+    return GetBoolAttr(nsGkAtoms::readonly);
+  }
+  void SetReadOnly(bool aReadOnly, ErrorResult& aError)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::readonly, aReadOnly, aError);
+  }
+  bool Required()
+  {
+    return GetBoolAttr(nsGkAtoms::required);
+  }
+  void SetRequired(bool aRequired, ErrorResult& aError)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::required, aRequired, aError);
+  }
+  uint32_t Rows()
+  {
+    return GetIntAttr(nsGkAtoms::rows, DEFAULT_ROWS_TEXTAREA);
+  }
+  void SetRows(uint32_t aRows, ErrorResult& aError)
+  {
+    if (aRows == 0) {
+      aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    } else {
+      SetHTMLUnsignedIntAttr(nsGkAtoms::rows, aRows, aError);
+    }
+  }
+  // XPCOM GetWrap is fine
+  void SetWrap(const nsAString& aWrap, ErrorResult& aError)
+  {
+    SetHTMLAttr(nsGkAtoms::wrap, aWrap, aError);
+  }
+  // XPCOM GetType is fine
+  // XPCOM GetDefaultValue is fine
+  void SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aError);
+  // XPCOM GetValue/SetValue are fine
+  uint32_t GetTextLength();
+  // nsIConstraintValidation::WillValidate is fine.
+  // nsIConstraintValidation::Validity() is fine.
+  // nsIConstraintValidation::GetValidationMessage() is fine.
+  // nsIConstraintValidation::CheckValidity() is fine.
+  using nsIConstraintValidation::CheckValidity;
+  // nsIConstraintValidation::SetCustomValidity() is fine.
+  // XPCOM Select is fine
+  uint32_t GetSelectionStart(ErrorResult& aError);
+  void SetSelectionStart(uint32_t aSelectionStart, ErrorResult& aError);
+  uint32_t GetSelectionEnd(ErrorResult& aError);
+  void SetSelectionEnd(uint32_t aSelectionEnd, ErrorResult& aError);
+  void GetSelectionDirection(nsAString& aDirection, ErrorResult& aError);
+  void SetSelectionDirection(const nsAString& aDirection, ErrorResult& aError);
+  void SetSelectionRange(uint32_t aSelectionStart, uint32_t aSelectionEnd, const Optional<nsAString>& aDirecton, ErrorResult& aError);
+  nsIControllers* GetControllers(ErrorResult& aError);
+  nsIEditor* GetEditor()
+  {
+    return mState.GetEditor();
+  }
+
 protected:
   using nsGenericHTMLFormElement::IsSingleLineTextControl; // get rid of the compiler warning
 
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
+
   nsCOMPtr<nsIControllers> mControllers;
   /** Whether or not the value has changed since its default value was given. */
   bool                     mValueChanged;
   /** Whether or not we are already handling select event. */
   bool                     mHandlingSelect;
   /** Whether or not we are done adding children (always true if not
       created by a parser */
   bool                     mDoneAddingChildren;
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -274,16 +274,17 @@ MOCHITEST_FILES = \
 		test_input_file_picker.html \
 		test_bug763626.html \
 		test_bug780993.html \
 		test_bug797113.html \
 		test_bug787134.html \
 		test_bug803677.html \
 		test_bug827126.html \
 		test_bug827426.html \
+		test_bug838582.html \
 		test_bug841466.html \
 		test_iframe_sandbox_inheritance.html \
 		file_iframe_sandbox_a_if1.html \
 		file_iframe_sandbox_a_if2.html \
 		file_iframe_sandbox_a_if3.html \
 		file_iframe_sandbox_a_if4.html \
 		file_iframe_sandbox_a_if5.html \
 		file_iframe_sandbox_a_if6.html \
--- a/content/html/content/test/reflect.js
+++ b/content/html/content/test/reflect.js
@@ -53,18 +53,17 @@ function reflectString(aParameters)
   is(element[idlAttr], "null",
      "null should have been stringified to 'null'");
   element.removeAttribute(contentAttr);
 
   element[idlAttr] = null;
   // TODO: remove this ugly hack when null stringification will work as expected.
   var todoAttrs = {
     form: [ "acceptCharset", "name", "target" ],
-    input: [ "accept", "alt", "formTarget", "max", "min", "name", "pattern", "placeholder", "step", "defaultValue" ],
-    textarea: [ "name", "placeholder" ]
+    input: [ "accept", "alt", "formTarget", "max", "min", "name", "pattern", "placeholder", "step", "defaultValue" ]
   };
   if (!(element.localName in todoAttrs) || todoAttrs[element.localName].indexOf(idlAttr) == -1) {
     is(element.getAttribute(contentAttr), "null",
        "null should have been stringified to 'null'");
     is(element[idlAttr], "null", "null should have been stringified to 'null'");
     element.removeAttribute(contentAttr);
   } else {
     todo_is(element.getAttribute(contentAttr), "null",
--- a/content/html/content/test/test_bug388558.html
+++ b/content/html/content/test/test_bug388558.html
@@ -20,17 +20,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 388558 **/
 var inputChange = 0;
 var textareaChange = 0;
 
 function testUserInput() {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   var input = document.getElementById("input");
-  var textarea = document.getElementById("textarea");
+  var textarea = SpecialPowers.wrap(document.getElementById("textarea"));
 
   input.focus();
   input.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
   input.blur();
   is(inputChange, 1, "Input element should have got one change event.");
 
   input.focus();
   input.value = "bar";
@@ -42,31 +42,31 @@ function testUserInput() {
   is(inputChange, 1, 
      "Change event dispatched when setting the value of the input element (2).");
 
   input.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
   is(inputChange, 1,
      "Change event dispatched when input element doesn't have focus.");
 
   textarea.focus();
-  textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
+  textarea.setUserInput("foo");
   textarea.blur();
   is(textareaChange, 1, "Textarea element should have got one change event.");
 
   textarea.focus();
   textarea.value = "bar";
   textarea.blur();
   is(textareaChange, 1,
      "Change event dispatched when setting the value of the textarea element.");
 
   textarea.value = "";
   is(textareaChange, 1,
      "Change event dispatched when setting the value of the textarea element (2).");
 
-  textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).setUserInput("foo");
+  textarea.setUserInput("foo");
   is(textareaChange, 1,
      "Change event dispatched when textarea element doesn't have focus.");
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(testUserInput);
 addLoadEvent(SimpleTest.finish);
 
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug838582.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=838582
+-->
+<head>
+  <title>Test for Bug 838582</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="reflect.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=838582">Mozilla Bug 838582</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<textarea id="t">abc</textarea>
+<script type="application/javascript">
+
+/** Test for Bug 838582 **/
+
+var textarea = document.getElementById("t");
+
+is(t.textLength, 3, "Correct textLength for defaultValue");
+t.value = "abcdef";
+is(t.textLength, 6, "Correct textLength for value");
+ok(!("controllers" in t), "Don't have web-visible controllers property");
+ok("controllers" in SpecialPowers.wrap(t), "Have chrome-visible controllers property");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -425,16 +425,25 @@ DOMInterfaces = {
 },
 
 'HTMLTableSectionElement': {
     'resultNotAddRefed': [
         'rows'
     ]
 },
 
+'HTMLTextAreaElement': {
+    'resultNotAddRefed': [
+        'form', 'controllers', 'editor'
+    ],
+    'binaryNames': {
+        'textLength': 'getTextLength'
+    }
+},
+
 'HTMLStyleElement': {
     'resultNotAddRefed': [
         'sheet'
     ]
 },
 
 'HTMLUListElement': {
     'nativeType' : 'mozilla::dom::HTMLSharedListElement'
@@ -1209,16 +1218,17 @@ addExternalIface('MozFrameLoader', nativ
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('NamedNodeMap')
 addExternalIface('NodeIterator')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
+addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('Selection', nativeType='nsISelection')
 addExternalIface('StyleSheet', nativeType='nsIStyleSheet')
 addExternalIface('StyleSheetList')
 addExternalIface('SVGAnimatedEnumeration', headerFile='nsIDOMSVGAnimatedEnum.h')
--- a/dom/interfaces/core/nsIDOMNSEditableElement.idl
+++ b/dom/interfaces/core/nsIDOMNSEditableElement.idl
@@ -4,18 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIEditor;
 
 /**
  * This interface is implemented by elements which have inner editable content,
- * such as HTML input and textarea. 
-*/
+ * such as HTML input and textarea.
+ *
+ * Please make sure to update the HTMLTextAreaElement Web IDL interface to
+ * mirror this interface when changing it.
+ */
 
 [scriptable, uuid(b33eb56c-3120-418c-892b-774b00c7dde8)]
 interface nsIDOMNSEditableElement : nsISupports
 {
   readonly attribute nsIEditor editor;
   // This is similar to set .value on nsIDOMInput/TextAreaElements, but
   // handling of the value change is closer to the normal user input, so 
   // 'change' event for example will be dispatched when focusing out the
--- a/dom/interfaces/html/nsIDOMHTMLTextAreaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTextAreaElement.idl
@@ -55,10 +55,12 @@ interface nsIDOMHTMLTextAreaElement : ns
   void select();
            attribute long                  selectionStart;
            attribute long                  selectionEnd;
   void setSelectionRange(in long selectionStart, in long selectionEnd, [optional] in DOMString direction);
            attribute DOMString             selectionDirection;
 
 
   // Mozilla extensions
+  // Please make sure to update the HTMLTextAreaElement Web IDL interface to
+  // mirror the list of Mozilla extensions here when changing it.
   readonly attribute nsIControllers   controllers;
 };
--- a/dom/plugins/test/mochitest/test_copyText.html
+++ b/dom/plugins/test/mochitest/test_copyText.html
@@ -10,18 +10,17 @@ function runTests() {
 
   var text = " some text \n to copy 'n paste "
   var textElt = document.getElementById("input");
   var plugin = document.getElementById("plugin1");
 
   textElt.focus();
   textElt.value = text;
   textElt.select();
-  textElt.QueryInterface(Components.interfaces.nsIDOMNSEditableElement)
-      .editor.copy();
+  SpecialPowers.wrap(textElt).editor.copy();
 
   is(plugin.getClipboardText(), text);
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLTextAreaElement.webidl
@@ -0,0 +1,93 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * http://www.whatwg.org/specs/web-apps/current-work/#the-textarea-element
+ * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+interface nsIEditor;
+interface MozControllers;
+
+interface HTMLTextAreaElement : HTMLElement {
+           // attribute DOMString autocomplete;
+  [SetterThrows, Pure]
+           attribute boolean autofocus;
+  [SetterThrows, Pure]
+           attribute unsigned long cols;
+           // attribute DOMString dirName;
+  [SetterThrows, Pure]
+           attribute boolean disabled;
+  [Pure]
+  readonly attribute HTMLFormElement? form;
+           // attribute DOMString inputMode;
+  [SetterThrows, Pure]
+           attribute long maxLength;
+  [SetterThrows, Pure]
+           attribute DOMString name;
+  [SetterThrows, Pure]
+           attribute DOMString placeholder;
+  [SetterThrows, Pure]
+           attribute boolean readOnly;
+  [SetterThrows, Pure]
+           attribute boolean required;
+  [SetterThrows, Pure]
+           attribute unsigned long rows;
+  [SetterThrows, Pure]
+           attribute DOMString wrap;
+
+  [Constant]
+  readonly attribute DOMString type;
+  [SetterThrows, Pure]
+           attribute DOMString defaultValue;
+  [TreatNullAs=EmptyString] attribute DOMString value;
+  readonly attribute unsigned long textLength;
+
+  readonly attribute boolean willValidate;
+  readonly attribute ValidityState validity;
+  readonly attribute DOMString validationMessage;
+  boolean checkValidity();
+  void setCustomValidity(DOMString error);
+
+  // readonly attribute NodeList labels;
+
+  void select();
+  [Throws]
+           attribute unsigned long selectionStart;
+  [Throws]
+           attribute unsigned long selectionEnd;
+  [Throws]
+           attribute DOMString selectionDirection;
+  // void setRangeText(DOMString replacement);
+  // void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode);
+  [Throws]
+  void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction);
+};
+
+partial interface HTMLTextAreaElement {
+  // Mirrored chrome-only Mozilla extensions to nsIDOMHTMLTextAreaElement.
+  // Please make sure to update this list of nsIDOMHTMLTextAreaElement changes.
+
+  [Throws, ChromeOnly]
+  readonly attribute MozControllers controllers;
+};
+
+partial interface HTMLTextAreaElement {
+  // Mirrored chrome-only nsIDOMNSEditableElement methods.  Please make sure
+  // to update this list if nsIDOMNSEditableElement changes.
+
+  [ChromeOnly]
+  readonly attribute nsIEditor? editor;
+
+  // This is similar to set .value on nsIDOMInput/TextAreaElements, but
+  // handling of the value change is closer to the normal user input, so
+  // 'change' event for example will be dispatched when focusing out the
+  // element.
+  [ChromeOnly]
+  void setUserInput(DOMString input);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -103,16 +103,17 @@ webidl_files = \
   HTMLSpanElement.webidl \
   HTMLStyleElement.webidl \
   HTMLTableCaptionElement.webidl \
   HTMLTableCellElement.webidl \
   HTMLTableColElement.webidl \
   HTMLTableElement.webidl \
   HTMLTableRowElement.webidl \
   HTMLTableSectionElement.webidl \
+  HTMLTextAreaElement.webidl \
   HTMLTimeElement.webidl \
   HTMLTitleElement.webidl \
   HTMLUListElement.webidl \
   ImageData.webidl \
   LinkStyle.webidl \
   LocalMediaStream.webidl \
   Location.webidl \
   MediaStream.webidl \
--- a/editor/composer/test/test_bug338427.html
+++ b/editor/composer/test/test_bug338427.html
@@ -16,17 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 338427 **/
 function init() {
     var textarea = document.getElementById("editor");
-    var editor = textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
+    var editor = textarea.editor;
     var spellchecker = editor.getInlineSpellChecker(true);
     spellchecker.enableRealTimeSpell = true;
 
     var list = {}, count = {};
     spellchecker.spellChecker.GetDictionaryList(list, count);
     if (count.value === 0) {
         return; // no dictionary, no test possible
     }
--- a/editor/libeditor/text/tests/test_bug596333.html
+++ b/editor/libeditor/text/tests/test_bug596333.html
@@ -22,19 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 const Ci = SpecialPowers.Ci;
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() SimpleTest.executeSoon(runTest));
 
 var gMisspeltWords;
 
 function getEditor() {
-  return document.getElementById("edit")
-                 .QueryInterface(Ci.nsIDOMNSEditableElement)
-                 .editor;
+  return SpecialPowers.wrap(document.getElementById("edit")).editor;
 }
 
 function getSpellCheckSelection() {
   var editor = getEditor();
   var selcon = editor.selectionController;
   return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
 }
 
--- a/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
+++ b/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
@@ -422,17 +422,17 @@ function runTests()
 
   textarea.setAttribute("readonly", "readonly");
   doTest(textarea, "<textarea readonly>", false, true, true);
 
   // make non-tabbable plaintext editor
   textarea.removeAttribute("readonly");
   const nsIPlaintextEditor = Components.interfaces.nsIPlaintextEditor;
   const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
-  var editor = textarea.QueryInterface(nsIDOMNSEditableElement).editor;
+  var editor = SpecialPowers.wrap(textarea).editor;
   var flags = editor.flags;
   editor.flags = flags & ~(nsIPlaintextEditor.eEditorWidgetMask |
                            nsIPlaintextEditor.eEditorAllowInteraction);
   doTest(textarea, "non-tabbable <textarea>", false, false, false);
 
   textarea.setAttribute("readonly", "readonly");
   doTest(textarea, "non-tabbable <textarea readonly>", false, true, false);
 
--- a/layout/forms/test/test_bug595310.html
+++ b/layout/forms/test/test_bug595310.html
@@ -25,17 +25,17 @@ SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
   // We want to compare to value="bar" and no placeholder shown.
   // That is what is currently showed.
   var s1 = snapshotWindow(window, false);
 
   var content = document.getElementById('content');
   var i = document.getElementById('i');
-  var t = document.getElementById('t');
+  var t = SpecialPowers.wrap(document.getElementById('t'));
   i.value = ""; i.placeholder = "foo";
   t.value = ""; t.placeholder = "foo";
 
   // Flushing.
   // Note: one call would have been enough actually but I didn't want to favour
   // one element... ;)
   i.getBoundingClientRect();
   t.getBoundingClientRect();
--- a/layout/generic/test/test_selection_expanding.html
+++ b/layout/generic/test/test_selection_expanding.html
@@ -70,17 +70,17 @@ var div1 = document.getElementById("div1
 var div2 = document.getElementById("div2");
 var div3 = document.getElementById("div3");
 var xbl = document.getElementById("xbl");
 var xbl_child = document.getElementById("xbl_child");
 var fixedDiv1 = document.getElementById("fixedDiv1");
 var fixedDiv2 = document.getElementById("fixedDiv2");
 var iframe = document.getElementById("iframe");
 var input = document.getElementById("input");
-var textarea = document.getElementById("textarea");
+var textarea = SpecialPowers.wrap(document.getElementById("textarea"));
 
 function test()
 {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   function getSelectionForEditor(aEditorElement)
   {
     const nsIDOMNSEditableElement =
@@ -404,9 +404,9 @@ function test()
 
   SimpleTest.finish();
 }
 window.onload = function() { setTimeout(test, 0); };
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 </body>
-</html>
\ No newline at end of file
+</html>