Bug 1375910 - Don't remove text node when setting value is empty string. r?masayuki draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Wed, 28 Jun 2017 07:42:09 +0900
changeset 601379 ec21a952f639338bffc32eded4dee2e4887ccea5
parent 600616 f4e52135d9bdc6ce98bb37b450021445aed894ce
child 635233 9fee91397a211f488e4fca652e7b749a3067fc14
push id66034
push userbmo:m_kato@ga2.so-net.ne.jp
push dateWed, 28 Jun 2017 18:06:18 +0000
reviewersmasayuki
bugs1375910
milestone56.0a1
Bug 1375910 - Don't remove text node when setting value is empty string. r?masayuki When setting empty value by input.value, we remove text node and insert bogus node. But creating and removing node are expensive. So we should keep text node for performance if possible. Now, DocumentIsEmpty only checks bogus node to detect empty. So, keeping text node change causes that document cannot detect as empty. If root has only text node and all is empty, we should detect empty document. This change should be only plain text editor. HTML editor already allows multiple text nodes, so we should keep old behaviour on HTML editor. MozReview-Commit-ID: Gt8GmdWAA3E
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/TextEditRules.cpp
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -705,16 +705,22 @@ HTMLEditRules::DidDoAction(Selection* aS
       return DidAbsolutePosition();
     }
     default:
       // pass through to TextEditRules
       return TextEditRules::DidDoAction(aSelection, aInfo, aResult);
   }
 }
 
+NS_IMETHODIMP_(bool)
+HTMLEditRules::DocumentIsEmpty()
+{
+  return !!mBogusNode;
+}
+
 nsresult
 HTMLEditRules::GetListState(bool* aMixed,
                             bool* aOL,
                             bool* aUL,
                             bool* aDL)
 {
   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
   *aMixed = false;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -89,16 +89,17 @@ public:
   NS_IMETHOD BeforeEdit(EditAction action,
                         nsIEditor::EDirection aDirection) override;
   NS_IMETHOD AfterEdit(EditAction action,
                        nsIEditor::EDirection aDirection) override;
   NS_IMETHOD WillDoAction(Selection* aSelection, RulesInfo* aInfo,
                           bool* aCancel, bool* aHandled) override;
   NS_IMETHOD DidDoAction(Selection* aSelection, RulesInfo* aInfo,
                          nsresult aResult) override;
+  NS_IMETHOD_(bool) DocumentIsEmpty() override;
   NS_IMETHOD DocumentModified() override;
 
   nsresult GetListState(bool* aMixed, bool* aOL, bool* aUL, bool* aDL);
   nsresult GetListItemState(bool* aMixed, bool* aLI, bool* aDT, bool* aDD);
   nsresult GetIndentState(bool* aCanIndent, bool* aCanOutdent);
   nsresult GetAlignment(bool* aMixed, nsIHTMLEditor::EAlignment* aAlign);
   nsresult GetParagraphState(bool* aMixed, nsAString& outFormat);
   nsresult MakeSureElemStartsOrEndsOnCR(nsINode& aNode);
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -344,20 +344,47 @@ TextEditRules::DidDoAction(Selection* aS
     case EditAction::outputText:
       return DidOutputText(aSelection, aResult);
     default:
       // Don't fail on transactions we don't handle here!
       return NS_OK;
   }
 }
 
+/**
+ * Return false if the editor has non-empty text nodes or non-text
+ * nodes.  Otherwise, i.e., there is no meaningful content,
+ * return true.
+ */
 NS_IMETHODIMP_(bool)
 TextEditRules::DocumentIsEmpty()
 {
-  return (mBogusNode != nullptr);
+  if (mBogusNode) {
+    return true;
+  }
+
+  // Even if there is no bogus node, we should detect as empty document
+  // if all children are text node and these are no content.
+  if (NS_WARN_IF(!mTextEditor)) {
+    return true;
+  }
+  Element* rootElement = mTextEditor->GetRoot();
+  if (!rootElement) {
+    return true;
+  }
+
+  uint32_t childCount = rootElement->GetChildCount();
+  for (uint32_t i = 0; i < childCount; i++) {
+    nsINode* node = rootElement->GetChildAt(i);
+    if (!EditorBase::IsTextNode(node) ||
+        node->Length()) {
+      return false;
+    }
+  }
+  return true;
 }
 
 void
 TextEditRules::WillInsert(Selection& aSelection, bool* aCancel)
 {
   MOZ_ASSERT(aCancel);
 
   if (IsReadonly() || IsDisabled()) {
@@ -867,26 +894,19 @@ TextEditRules::WillSetText(Selection& aS
 
     return NS_OK;
   }
 
   nsINode* curNode = rootElement->GetFirstChild();
   if (NS_WARN_IF(!EditorBase::IsTextNode(curNode))) {
     return NS_OK;
   }
-  if (tString.IsEmpty()) {
-    nsresult rv = textEditor->DeleteNode(curNode);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
 
-    *aHandled = true;
-    return NS_OK;
-  }
-
+  // Even if empty text, we don't remove text node and set empty text
+  // for performance
   nsresult rv = textEditor->SetTextImpl(tString, *curNode->GetAsText());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   *aHandled = true;
 
   ASSERT_PASSWORD_LENGTHS_EQUAL();