Backout changeset a72195ce0eaa (bug 612128) becasue of Fennec regressions
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 22 Sep 2011 18:09:44 -0400
changeset 78398 3045a91f856fc75e753c1c2168dfb1cf9460e0e8
parent 78397 4cae8b392bae20b3c509a7839d11c0cd41cdfb53
child 78399 743e78a1a24d5a4359544de42893a89c2b970ffc
push id340
push userclegnitto@mozilla.com
push dateTue, 08 Nov 2011 22:56:33 +0000
treeherdermozilla-beta@f745dc151615 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs612128
milestone9.0a1
backs outa72195ce0eaa20bbc1fcf5c8e98c6b64044b972b
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
Backout changeset a72195ce0eaa (bug 612128) becasue of Fennec regressions
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/base/nsEditorCommands.cpp
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
editor/libeditor/html/tests/test_bug676401.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
@@ -1784,16 +1784,47 @@ nsGenericHTMLElement::MapCommonAttribute
     if (display->GetUnit() == eCSSUnit_Null) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
         display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
+void
+nsGenericHTMLFormElement::UpdateEditableFormControlState(PRBool aNotify)
+{
+  // nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
+  // function, so should be kept in sync with that.
+
+  ContentEditableTristate value = GetContentEditableValue();
+  if (value != eInherit) {
+    DoSetEditableFlag(!!value, aNotify);
+    return;
+  }
+
+  nsIContent *parent = GetParent();
+
+  if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
+    DoSetEditableFlag(PR_TRUE, aNotify);
+    return;
+  }
+
+  if (!IsTextControl(PR_FALSE)) {
+    DoSetEditableFlag(PR_FALSE, aNotify);
+    return;
+  }
+
+  // If not contentEditable we still need to check the readonly attribute.
+  PRBool roState;
+  GetBoolAttr(nsGkAtoms::readonly, &roState);
+
+  DoSetEditableFlag(!roState, aNotify);
+}
+
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
   { &nsGkAtoms::lang },
   { &nsGkAtoms::hidden },
   { nsnull }
 };
@@ -2876,28 +2907,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
@@ -923,16 +923,18 @@ public:
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
 
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify);
 
+  void UpdateEditableFormControlState(PRBool aNotify);
+
   /**
    * 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
    * with the id in @form. Otherwise, it *must* be null.
    *
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -843,16 +843,17 @@ nsHTMLInputElement::AfterSetAttr(PRInt32
     } else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     } else if (aName == nsGkAtoms::pattern) {
       UpdatePatternMismatchValidityState();
     } else if (aName == nsGkAtoms::multiple) {
       UpdateTypeMismatchValidityState();
     }
 
+    UpdateEditableState(aNotify);
     UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 // nsIDOMHTMLInputElement
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -230,16 +230,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(PRBool aNotify)
+  {
+    return UpdateEditableFormControlState(aNotify);
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(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
@@ -195,16 +195,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(PRBool aNotify)
+  {
+    return UpdateEditableFormControlState(aNotify);
+  }
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
                                            nsGenericHTMLFormElement)
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   // nsIConstraintValidation
   PRBool   IsTooLong();
   PRBool   IsValueMissing() const;
@@ -1257,16 +1262,19 @@ nsHTMLTextAreaElement::AfterSetAttr(PRIn
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
     } else if (aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     }
 
+    if (aName == nsGkAtoms::readonly) {
+      UpdateEditableState(aNotify);
+    }
     UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                                 aNotify);
 }
 
 nsresult
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1554,19 +1554,16 @@ nsTextEditorState::CreateRootNode()
   }
 
   return rv;
 }
 
 nsresult
 nsTextEditorState::InitializeRootNode()
 {
-  // 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
@@ -543,17 +543,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/base/nsEditorCommands.cpp
+++ b/editor/libeditor/base/nsEditorCommands.cpp
@@ -656,18 +656,23 @@ nsDeleteCommand::GetCommandStateParams(c
 
 NS_IMETHODIMP
 nsSelectAllCommand::IsCommandEnabled(const char * aCommandName,
                                      nsISupports *aCommandRefCon,
                                      PRBool *outCmdEnabled)
 {
   NS_ENSURE_ARG_POINTER(outCmdEnabled);
 
-  // You can always select all!
-  *outCmdEnabled = PR_TRUE;
+  // you can select all if there is an editor (and potentially no contents)
+  // some day we may want to change this
+  nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
+  if (editor)
+    return editor->GetIsSelectionEditable(outCmdEnabled);
+
+  *outCmdEnabled = PR_FALSE;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsSelectAllCommand::DoCommand(const char *aCommandName,
                               nsISupports *aCommandRefCon)
 {
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -307,19 +307,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
@@ -426,22 +426,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->IsElement() &&
-        content->AsElement()->State().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();
 }
@@ -6029,27 +6023,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
@@ -149,17 +149,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<nsIDOMEventTarget> GetDOMEventTarget();
   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
@@ -74,17 +74,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug551704.html \
 		test_bug552782.html \
 		test_bug570144.html \
 		test_bug592592.html \
 		test_bug597784.html \
 		test_bug599322.html \
 		test_bug607584.html \
 		test_bug611182.html \
-		test_bug612128.html \
 		test_bug612447.html \
 		test_bug620906.html \
 		test_bug622371.html \
 		test_bug629845.html \
 		test_bug640321.html \
 		test_bug668599.html \
 		test_bug674861.html \
 		test_bug676401.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/editor/libeditor/html/tests/test_bug676401.html
+++ b/editor/libeditor/html/tests/test_bug676401.html
@@ -30,27 +30,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests);
 
 var gBlock1, gBlock2;
 
 function IsCommandEnabled(command) {
   var enabled;
 
-  var resultInNonEditableRegion = false;
-  if (command == "selectAll") {
-    // The select all command is sort of exceptional, as it needs to be enabled
-    // everywhere.
-    resultInNonEditableRegion = true;
-  }
-
   // non-editable div: should return false
   window.getSelection().selectAllChildren(gBlock1);
   enabled = document.queryCommandEnabled(command);
-  is(enabled, resultInNonEditableRegion, "'" + command + "' should not be enabled on a non-editable block.");
+  is(enabled, false, "'" + command + "' should not be enabled on a non-editable block.");
 
   // editable div: should return true
   window.getSelection().selectAllChildren(gBlock2);
   enabled = document.queryCommandEnabled(command);
   is(enabled, true, "'" + command + "' should be enabled on an editable block.");
 }
 
 function runTests() {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3878,41 +3878,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<nsIAnonymousContentCreator::ContentInfo>& aContent)
 {
   nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
   if (!creator)
     return NS_OK;
@@ -3930,27 +3905,17 @@ nsCSSFrameConstructor::GetAnonymousConte
     // cascading rules for <svg:use> - bug 265894
     if (aParent &&
         aParent->NodeInfo()->Equals(nsGkAtoms::use, kNameSpaceID_SVG)) {
       content->SetFlags(NODE_IS_ANONYMOUS);
     } else {
       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;
 }
@@ -6167,40 +6132,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.  MayHaveContentEditableAttr() being true only indicates
+// a contenteditable attribute, it doesn't indicate whether 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->MayHaveContentEditableAttr()));
+}
+
 // 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
@@ -74,20 +74,16 @@ public:
     nsIContent* mContent;
     nsRefPtr<nsStyleContext> mStyleContext;
   };
 
   /**
    * 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<ContentInfo>& 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
@@ -64,13 +64,9 @@ fails-if(Android) != spellcheck-hyphen-m
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
 == 338427-1.html 338427-1-ref.html
 skip-if(Android) == 674212-spellcheck.html 674212-spellcheck-ref.html
 skip-if(Android) == 338427-2.html 338427-2-ref.html
 skip-if(Android) == 338427-3.html 338427-3-ref.html
 skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-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
 == dynamic-overflow-change.html dynamic-overflow-change-ref.html