Back out bug 612128 because it regressed Fennec with bug 618357, which blocks Fennec beta3; a=blocking-fennecb3+
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 10 Dec 2010 21:20:00 -0500
changeset 59099 580f9d4ebf9fad0f77894e388b06ef5aa1ff307f
parent 58930 6323eea0244254278aff7356f2eac829ddfcb37d
child 59100 45b179a0b64a341af267826f9e914492210e5c8a
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersblocking-fennecb3
bugs612128, 618357
milestone2.0b8pre
Back out bug 612128 because it regressed Fennec with bug 618357, which blocks Fennec beta3; a=blocking-fennecb3+
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLInputElement.h
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsTextEditorState.cpp
editor/libeditor/base/crashtests/382527-1.html
editor/libeditor/base/nsEditor.h
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/tests/Makefile.in
editor/libeditor/html/tests/test_bug612128.html
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsIAnonymousContentCreator.h
layout/reftests/editor/readonly-editable-ref.html
layout/reftests/editor/readonly-editable.html
layout/reftests/editor/readonly-non-editable-ref.html
layout/reftests/editor/readonly-non-editable.html
layout/reftests/editor/readwrite-editable-ref.html
layout/reftests/editor/readwrite-editable.html
layout/reftests/editor/readwrite-non-editable-ref.html
layout/reftests/editor/readwrite-non-editable.html
layout/reftests/editor/reftest.list
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1671,16 +1671,48 @@ nsGenericHTMLElement::MapCommonAttribute
     if (disp->mDisplay.GetUnit() == eCSSUnit_Null) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
         disp->mDisplay.SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
+void
+nsGenericHTMLFormElement::UpdateEditableFormControlState()
+{
+  // nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
+  // function, so should be kept in sync with that.
+
+  ContentEditableTristate value = GetContentEditableValue();
+  if (value != eInherit) {
+    SetEditableFlag(!!value);
+
+    return;
+  }
+
+  nsIContent *parent = GetParent();
+
+  if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
+    SetEditableFlag(PR_TRUE);
+    return;
+  }
+
+  if (!IsTextControl(PR_FALSE)) {
+    SetEditableFlag(PR_FALSE);
+    return;
+  }
+
+  // If not contentEditable we still need to check the readonly attribute.
+  PRBool roState;
+  GetBoolAttr(nsGkAtoms::readonly, &roState);
+
+  SetEditableFlag(!roState);
+}
+
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
   { &nsGkAtoms::lang },
   { &nsGkAtoms::hidden },
   { nsnull }
 };
@@ -2760,28 +2792,16 @@ nsGenericHTMLFormElement::IntrinsicState
   
   if (mForm && mForm->IsDefaultSubmitElement(this)) {
       NS_ASSERTION(IsSubmitControl(),
                    "Default submit element that isn't a submit control.");
       // We are the default submit element (:default)
       state |= NS_EVENT_STATE_DEFAULT;
   }
 
-  // Make the text controls read-write
-  if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
-      IsTextControl(PR_FALSE)) {
-    PRBool roState;
-    GetBoolAttr(nsGkAtoms::readonly, &roState);
-
-    if (!roState) {
-      state |= NS_EVENT_STATE_MOZ_READWRITE;
-      state &= ~NS_EVENT_STATE_MOZ_READONLY;
-    }
-  }
-
   return state;
 }
 
 nsGenericHTMLFormElement::FocusTristate
 nsGenericHTMLFormElement::FocusState()
 {
   // We can't be focused if we aren't in a document
   nsIDocument* doc = GetCurrentDoc();
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -934,16 +934,18 @@ protected:
   /**
    * Returns if the element should react on autofocus attribute.
    */
   virtual PRBool AcceptAutofocus() const
   {
     return PR_FALSE;
   }
 
+  void UpdateEditableFormControlState();
+
   PRBool IsSingleLineTextControlInternal(PRBool aExcludePassword, PRInt32 mType) const;
 
   /**
    * This method will update the form owner, using @form or looking to a parent.
    *
    * @param aBindToTree Whether the element is being attached to the tree.
    * @param aFormIdElement The element associated with the id in @form. If
    * aBindToTree is false, aFormIdElement *must* contain the element associated
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -928,16 +928,23 @@ nsHTMLInputElement::AfterSetAttr(PRInt32
       UpdatePatternMismatchValidityState();
       states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
                 NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
 
     if (aNotify) {
       nsIDocument* doc = GetCurrentDoc();
 
+      if (aName == nsGkAtoms::type) {
+        UpdateEditableState();
+      } else if (IsSingleLineTextControl(PR_FALSE) && aName == nsGkAtoms::readonly) {
+        UpdateEditableState();
+        states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
+      }
+
       if (doc && !states.IsEmpty()) {
         MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
         doc->ContentStatesChanged(this, nsnull, states);
       }
     }
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -240,16 +240,21 @@ public:
    * @return the selected button (or null).
    */
   already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   NS_IMETHOD FireAsyncClickHandler();
 
+  virtual void UpdateEditableState()
+  {
+    return UpdateEditableFormControlState();
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement,
                                                      nsGenericHTMLFormElement)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
   // which directory was last used on a site-by-site basis
   static void InitUploadLastDir();
   static void DestroyUploadLastDir();
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -199,16 +199,21 @@ public:
                                  const nsAString* aValue, PRBool aNotify);
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
+  virtual void UpdateEditableState()
+  {
+    return UpdateEditableFormControlState();
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
                                            nsGenericHTMLFormElement)
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   // nsIConstraintValidation
   PRBool   IsTooLong();
   PRBool   IsValueMissing() const;
@@ -1223,16 +1228,21 @@ nsHTMLTextAreaElement::AfterSetAttr(PRIn
       UpdateTooLongValidityState();
       states |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID |
                 NS_EVENT_STATE_MOZ_UI_VALID | NS_EVENT_STATE_MOZ_UI_INVALID;
     }
 
     if (aNotify) {
       nsIDocument* doc = GetCurrentDoc();
 
+      if (aName == nsGkAtoms::readonly) {
+        UpdateEditableState();
+        states |= NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE;
+      }
+
       if (doc && !states.IsEmpty()) {
         MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
         doc->ContentStatesChanged(this, nsnull, states);
       }
     }
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1520,19 +1520,16 @@ nsTextEditorState::CreateRootNode()
   nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nsnull,
                                                  kNameSpaceID_XHTML);
   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = NS_NewHTMLElement(getter_AddRefs(mRootNode), nodeInfo.forget(),
                                   NOT_FROM_PARSER);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Make our root node editable
-  mRootNode->SetFlags(NODE_IS_EDITABLE);
-
   // Set the necessary classes on the text control. We use class values
   // instead of a 'style' attribute so that the style comes from a user-agent
   // style sheet and is still applied even if author styles are disabled.
   nsAutoString classValue;
   classValue.AppendLiteral("anonymous-div");
   PRInt32 wrapCols = GetWrapCols();
   if (wrapCols >= 0) {
     classValue.AppendLiteral(" wrap");
--- a/editor/libeditor/base/crashtests/382527-1.html
+++ b/editor/libeditor/base/crashtests/382527-1.html
@@ -31,19 +31,17 @@ function init2()
 
 function init3()
 {
   var rng = targetDocument.createRange(); 
   rng.setStart(textNode, 1);
   rng.setEnd(textNode, 1);
   targetWindow.getSelection().addRange(rng);
 
-  try {
-    targetDocument.execCommand("inserthtml", false, "<p>");
-  } catch(e) {}
+  targetDocument.execCommand("inserthtml", false, "<p>");
   
   document.documentElement.removeAttribute("class");
 }
 
 
 </script>
 
 </head>
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -508,17 +508,17 @@ public:
 
   /** returns PR_TRUE if aNode is a descendant of our root node */
   PRBool IsDescendantOfBody(nsIDOMNode *inNode);
 
   /** returns PR_TRUE if aNode is a container */
   virtual PRBool IsContainer(nsIDOMNode *aNode);
 
   /** returns PR_TRUE if aNode is an editable node */
-  virtual PRBool IsEditable(nsIDOMNode *aNode);
+  PRBool IsEditable(nsIDOMNode *aNode);
 
   virtual PRBool IsTextInDirtyFrameVisible(nsIDOMNode *aNode);
 
   /** returns PR_TRUE if aNode is a MozEditorBogus node */
   PRBool IsMozEditorBogusNode(nsIDOMNode *aNode);
 
   /** counts number of editable child nodes */
   nsresult CountEditableChildren(nsIDOMNode *aNode, PRUint32 &outCount);
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -310,19 +310,17 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
   nsCOMPtr<nsIDOMNode> targetNode, tempNode;
   PRInt32 targetOffset=0;
 
   if (!aDestNode)
   {
     // if caller didn't provide the destination/target node,
     // fetch the paste insertion point from our selection
     res = GetStartNodeAndOffset(selection, getter_AddRefs(targetNode), &targetOffset);
-    if (!targetNode || !IsEditable(targetNode)) {
-      res = NS_ERROR_FAILURE;
-    }
+    if (!targetNode) res = NS_ERROR_FAILURE;
     NS_ENSURE_SUCCESS(res, res);
   }
   else
   {
     targetNode = aDestNode;
     targetOffset = aDestOffset;
   }
 
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -410,21 +410,16 @@ nsHTMLEditor::FindSelectionRoot(nsINode 
   // permission script.
   if (IsReadonly()) {
     // We still want to allow selection in a readonly editor.
     content = do_QueryInterface(GetRoot());
     return content.forget();
   }
 
   if (!content->HasFlag(NODE_IS_EDITABLE)) {
-    // If the content is in read-write state but is not editable itself,
-    // return it as the selection root.
-    if (content->IntrinsicState().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
-      return content.forget();
-    }
     return nsnull;
   }
 
   // For non-readonly editors we want to find the root of the editable subtree
   // containing aContent.
   content = content->GetEditingHost();
   return content.forget();
 }
@@ -6030,27 +6025,8 @@ nsHTMLEditor::GetPreferredIMEState(PRUin
     *aState = nsIContent::IME_STATUS_DISABLE;
     return NS_OK;
   }
 
   // HTML editor don't prefer the CSS ime-mode because IE didn't do so too.
   *aState = nsIContent::IME_STATUS_ENABLE;
   return NS_OK;
 }
-
-PRBool
-nsHTMLEditor::IsEditable(nsIDOMNode* aNode) {
-  if (!nsPlaintextEditor::IsEditable(aNode)) {
-    return PR_FALSE;
-  }
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  if (!node) {
-    // If what we're dealing with is not a node, then it's not editable!
-    return PR_FALSE;
-  }
-  if (node->IsElement()) {
-    // If we're dealing with an element, then ask it whether it's editable.
-    return node->IsEditable();
-  }
-  // We might be dealing with a text node for example, which we always consider
-  // to be editable.
-  return PR_TRUE;
-}
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -150,17 +150,16 @@ public:
   NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable);
   NS_IMETHOD BeginningOfDocument();
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
   virtual already_AddRefed<nsIContent> GetFocusedContent();
   virtual PRBool IsActiveInDOMWindow();
   virtual already_AddRefed<nsPIDOMEventTarget> GetPIDOMEventTarget();
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
   virtual PRBool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
-  virtual PRBool IsEditable(nsIDOMNode *aNode);
 
   /* ------------ nsStubMutationObserver overrides --------- */
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   /* ------------ nsIEditorIMESupport overrides ------------ */
   NS_IMETHOD GetPreferredIMEState(PRUint32 *aState);
--- a/editor/libeditor/html/tests/Makefile.in
+++ b/editor/libeditor/html/tests/Makefile.in
@@ -63,17 +63,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug537046.html \
 		test_bug550434.html \
 		test_bug551704.html \
 		test_bug592592.html \
 		test_bug597784.html \
 		test_bug599322.html \
 		test_bug607584.html \
 		test_bug611182.html \
-		test_bug612128.html \
 		test_bug612447.html \
 		test_CF_HTML_clipboard.html \
 		test_contenteditable_focus.html \
 		test_contenteditable_text_input_handling.html \
 		test_htmleditor_keyevent_handling.html \
 		test_select_all_without_body.html \
 		file_select_all_without_body.html \
 		test_root_element_replacement.html \
deleted file mode 100644
--- a/editor/libeditor/html/tests/test_bug612128.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=612128
--->
-<head>
-  <title>Test for Bug 612128</title>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.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=612128">Mozilla Bug 612128</a>
-<p id="display"></p>
-<div id="content">
-<input>
-<div contenteditable></div>
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 612128 **/
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(function() {
-  document.querySelector("input").focus();
-  var threw = false;
-  try {
-    document.execCommand("inserthtml", null, "<span>f" + "oo</span>");
-  } catch (e) {
-    threw = true;
-  }
-  ok(threw, "The inserthtml command should fail");
-  is(document.querySelectorAll("span").length, 0, "No span element should be injected inside the page");
-  is(document.body.innerHTML.indexOf("f" + "oo"), -1, "No text should be injected inside the page");
-  SimpleTest.finish();
-});
-
-</script>
-</pre>
-</body>
-</html>
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3922,41 +3922,16 @@ nsCSSFrameConstructor::CreateAnonymousFr
       // create the frame and attach it to our frame
       ConstructFrame(aState, content, aParentFrame, aChildItems);
     }
   }
 
   return NS_OK;
 }
 
-static void
-SetFlagsOnSubtree(nsIContent *aNode, PtrBits aFlagsToSet)
-{
-#ifdef DEBUG
-  // Make sure that the node passed to us doesn't have any XBL children
-  {
-    nsIDocument *doc = aNode->GetOwnerDoc();
-    NS_ASSERTION(doc, "The node must be in a document");
-    NS_ASSERTION(!doc->BindingManager()->GetXBLChildNodesFor(aNode),
-                 "The node should not have any XBL children");
-  }
-#endif
-
-  // Set the flag on the node itself
-  aNode->SetFlags(aFlagsToSet);
-
-  // Set the flag on all of its children recursively
-  PRUint32 count;
-  nsIContent * const *children = aNode->GetChildArray(&count);
-
-  for (PRUint32 index = 0; index < count; ++index) {
-    SetFlagsOnSubtree(children[index], aFlagsToSet);
-  }
-}
-
 nsresult
 nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
                                            nsIFrame* aParentFrame,
                                            nsTArray<nsIContent*>& aContent)
 {
   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
   if (!creator)
     return NS_OK;
@@ -3977,27 +3952,17 @@ nsCSSFrameConstructor::GetAnonymousConte
         aParent->NodeInfo()->Equals(nsGkAtoms::use, kNameSpaceID_SVG)) {
       content->SetFlags(NODE_IS_ANONYMOUS);
     } else
 #endif
     {
       content->SetNativeAnonymous();
     }
 
-    PRBool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
     rv = content->BindToTree(mDocument, aParent, aParent, PR_TRUE);
-    // If the anonymous content creator requested that the content should be
-    // editable, honor its request.
-    // We need to set the flag on the whole subtree, because existing
-    // children's flags have already been set as part of the BindToTree operation.
-    if (anonContentIsEditable) {
-      NS_ASSERTION(aParentFrame->GetType() == nsGkAtoms::textInputFrame,
-                   "We only expect this for anonymous content under a text control frame");
-      SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
-    }
     if (NS_FAILED(rv)) {
       content->UnbindFromTree();
       return rv;
     }
   }
 
   return NS_OK;
 }
@@ -6226,40 +6191,59 @@ nsCSSFrameConstructor::ReframeTextIfNeed
     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
     return;
   }
   NS_ASSERTION(!aContent->GetPrimaryFrame(),
                "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
   ContentInserted(aParentContent, aContent, nsnull, PR_FALSE);
 }
 
+// We want to disable lazy frame construction for nodes that are under an
+// editor. We use nsINode::IsEditable, but that includes inputs with type text
+// and password and textareas, which are common and aren't really editable (the
+// native anonymous content under them is what is actually editable) so we want
+// to construct frames for those lazily.
+// The logic for this check is based on
+// nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept
+// in sync with that. The presence of the NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR
+// flag only indicates a contenteditable attribute, it doesn't indicate if it
+// is true or false, so we force eager construction in some cases when the node
+// is not editable, but that should be rare.
+static inline PRBool
+IsActuallyEditable(nsIContent* aContainer, nsIContent* aChild)
+{
+  return (aChild->IsEditable() &&
+          (aContainer->IsEditable() ||
+           aChild->HasFlag(NODE_MAY_HAVE_CONTENT_EDITABLE_ATTR)));
+}
+
 // For inserts aChild should be valid, for appends it should be null.
 // Returns true if this operation can be lazy, false if not.
 PRBool
 nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
                                             nsIContent* aContainer,
                                             nsIContent* aChild)
 {
   if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
       aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXUL()) {
     return PR_FALSE;
   }
 
   if (aOperation == CONTENTINSERT) {
     if (aChild->IsRootOfAnonymousSubtree() ||
-        aChild->IsEditable() || aChild->IsXUL()) {
+        aChild->IsXUL() || IsActuallyEditable(aContainer, aChild)) {
       return PR_FALSE;
     }
   } else { // CONTENTAPPEND
     NS_ASSERTION(aOperation == CONTENTAPPEND,
                  "operation should be either insert or append");
     for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
       NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
                    "Should be coming through the CONTENTAPPEND case");
-      if (child->IsXUL() || child->IsEditable()) {
+      if (child->IsXUL() || IsActuallyEditable(aContainer, child)) {
         return PR_FALSE;
       }
     }
   }
 
   // We can construct lazily; just need to set suitable bits in the content
   // tree.
 
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -59,20 +59,16 @@ class nsIAnonymousContentCreator
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsIAnonymousContentCreator)
 
   /**
    * Creates "native" anonymous content and adds the created content to
    * the aElements array. None of the returned elements can be nsnull.
    *
-   * If the anonymous content creator sets the editable flag on some
-   * of the elements that it creates, the flag will be applied to the node
-   * upon being bound to the document.
-   *
    * @note The returned elements are owned by this object. This object is
    *       responsible for calling UnbindFromTree on the elements it returned
    *       from CreateAnonymousContent when appropriate (i.e. before releasing
    *       them).
    */
   virtual nsresult CreateAnonymousContent(nsTArray<nsIContent*>& aElements)=0;
 
   /**
deleted file mode 100644
--- a/layout/reftests/editor/readonly-editable-ref.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <body>
-    <input>
-    <input readonly>
-    <input type=password>
-    <input type=password readonly>
-    <input type=email>
-    <input type=email readonly>
-    <textarea></textarea>
-    <textarea readonly></textarea>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readonly-editable.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      :-moz-read-write + span {
-        display: none;
-      }
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body contenteditable>
-    <input><span>hide me</span>
-    <input readonly><span>hide me</span>
-    <input type=password><span>hide me</span>
-    <input type=password readonly><span>hide me</span>
-    <input type=email><span>hide me</span>
-    <input type=email readonly><span>hide me</span>
-    <textarea></textarea><span>hide me</span>
-    <textarea readonly></textarea><span>hide me</span>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readonly-non-editable-ref.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body>
-    <input><span>hide me</span>
-    <input readonly>
-    <input type=password><span>hide me</span>
-    <input type=password readonly>
-    <input type=email><span>hide me</span>
-    <input type=email readonly>
-    <textarea></textarea><span>hide me</span>
-    <textarea readonly></textarea>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readonly-non-editable.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      :-moz-read-only + span {
-        display: none;
-      }
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body>
-    <input><span>hide me</span>
-    <input readonly><span>hide me</span>
-    <input type=password><span>hide me</span>
-    <input type=password readonly><span>hide me</span>
-    <input type=email><span>hide me</span>
-    <input type=email readonly><span>hide me</span>
-    <textarea></textarea><span>hide me</span>
-    <textarea readonly></textarea><span>hide me</span>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readwrite-editable-ref.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <body>
-    <input>
-    <input readonly>
-    <input type=password>
-    <input type=password readonly>
-    <input type=email>
-    <input type=email readonly>
-    <textarea></textarea>
-    <textarea readonly></textarea>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readwrite-editable.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      :-moz-read-write + span {
-        display: none;
-      }
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body contenteditable>
-    <input><span>hide me</span>
-    <input readonly><span>hide me</span>
-    <input type=password><span>hide me</span>
-    <input type=password readonly><span>hide me</span>
-    <input type=email><span>hide me</span>
-    <input type=email readonly><span>hide me</span>
-    <textarea></textarea><span>hide me</span>
-    <textarea readonly></textarea><span>hide me</span>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readwrite-non-editable-ref.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body>
-    <input>
-    <input readonly><span>hide me</span>
-    <input type=password>
-    <input type=password readonly><span>hide me</span>
-    <input type=email>
-    <input type=email readonly><span>hide me</span>
-    <textarea></textarea>
-    <textarea readonly></textarea><span>hide me</span>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/reftests/editor/readwrite-non-editable.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <style>
-      :-moz-read-write + span {
-        display: none;
-      }
-      span {
-        color: transparent; /* workaround for bug 617524 */
-        outline: 1px solid green;
-      }
-    </style>
-  </head>
-  <body>
-    <input><span>hide me</span>
-    <input readonly><span>hide me</span>
-    <input type=password><span>hide me</span>
-    <input type=password readonly><span>hide me</span>
-    <input type=email><span>hide me</span>
-    <input type=email readonly><span>hide me</span>
-    <textarea></textarea><span>hide me</span>
-    <textarea readonly></textarea><span>hide me</span>
-  </body>
-</html>
--- a/layout/reftests/editor/reftest.list
+++ b/layout/reftests/editor/reftest.list
@@ -42,12 +42,8 @@ asserts(1) == passwd-4.html passwd-ref.h
 != spellcheck-textarea-property-dynamic-override-inherit.html spellcheck-textarea-ref.html
 == caret_on_focus.html caret_on_focus-ref.html
 != caret_on_textarea_lastline.html caret_on_textarea_lastline-ref.html
 == input-text-onfocus-reframe.html input-text-onfocus-reframe-ref.html
 == input-text-notheme-onfocus-reframe.html input-text-notheme-onfocus-reframe-ref.html
 == caret_after_reframe.html caret_after_reframe-ref.html
 == nobogusnode-1.html nobogusnode-ref.html
 == nobogusnode-2.html nobogusnode-ref.html
-== readwrite-non-editable.html readwrite-non-editable-ref.html
-== readwrite-editable.html readwrite-editable-ref.html
-== readonly-non-editable.html readonly-non-editable-ref.html
-== readonly-editable.html readonly-editable-ref.html