Bug 1460509 - part 82: Refine comments of TextEditRules.h and HTMLEditRules.h r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 18 May 2018 12:38:32 +0900
changeset 798800 6c46689d352d82ceeb6ce3f08a2685d8dab7992a
parent 798799 94bb38460b6c811a94e5e4228fd28bb66e3e114c
child 798801 6bb7d22f611594454450aab5317d4fcba1383705
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 82: Refine comments of TextEditRules.h and HTMLEditRules.h r?m_kato This patch adds new rules of TextEditRules and HTMLEditRules about NS_ERROR_EDITOR_DESTROYED. Additionally, this patch moves some method explanation in each .cpp file to .h file. MozReview-Commit-ID: JqZFrWyrND8
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/TextEditRules.cpp
editor/libeditor/TextEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -3385,26 +3385,16 @@ HTMLEditRules::InsertBRIfNeeded()
         return NS_ERROR_FAILURE;
       }
       return NS_OK;
     }
   }
   return NS_OK;
 }
 
-/**
- * GetGoodSelPointForNode() finds where at a node you would want to set the
- * selection if you were trying to have a caret next to it.  Always returns a
- * valid value (unless mHTMLEditor has gone away).
- *
- * @param aNode         The node
- * @param aAction       Which edge to find:
- *                        eNext/eNextWord/eToEndOfLine indicates beginning,
- *                        ePrevious/PreviousWord/eToBeginningOfLine ending.
- */
 EditorDOMPoint
 HTMLEditRules::GetGoodSelPointForNode(nsINode& aNode,
                                       nsIEditor::EDirection aAction)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   MOZ_ASSERT(aAction == nsIEditor::eNext ||
              aAction == nsIEditor::eNextWord ||
              aAction == nsIEditor::ePrevious ||
@@ -6785,23 +6775,16 @@ HTMLEditRules::CheckForInvisibleBR(Eleme
   WSRunObject wsTester(&HTMLEditorRef(), testNode, testOffset);
   if (WSType::br == wsTester.mStartReason) {
     return wsTester.mStartReasonNode->AsElement();
   }
 
   return nullptr;
 }
 
-/**
- * aLists and aTables allow the caller to specify what kind of content to
- * "look inside".  If aTables is Tables::yes, look inside any table content,
- * and insert the inner content into the supplied nsTArray at offset
- * aIndex.  Similarly with aLists and list content.  aIndex is updated to
- * point past inserted elements.
- */
 void
 HTMLEditRules::GetInnerContent(
                  nsINode& aNode,
                  nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                  int32_t* aIndex,
                  Lists aLists,
                  Tables aTables)
 {
@@ -7145,20 +7128,16 @@ HTMLEditRules::NormalizeSelection()
   if (NS_WARN_IF(!CanHandleEditAction())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "Failed to extend selection");
   return NS_OK;
 }
 
-/**
- * GetPromotedPoint() figures out where a start or end point for a block
- * operation really is.
- */
 EditorDOMPoint
 HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
                                 nsINode& aNode,
                                 int32_t aOffset,
                                 EditAction actionID)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
@@ -7343,20 +7322,16 @@ HTMLEditRules::GetPromotedPoint(RulesEnd
     if (NS_WARN_IF(!point.AdvanceOffset())) {
       break;
     }
     nearNode = HTMLEditorRef().GetNextEditableHTMLNodeInBlock(point);
   }
   return point;
 }
 
-/**
- * GetPromotedRanges() runs all the selection range endpoint through
- * GetPromotedPoint().
- */
 void
 HTMLEditRules::GetPromotedRanges(nsTArray<RefPtr<nsRange>>& outArrayOfRanges,
                                  EditAction inOperationType)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   uint32_t rangeCount = SelectionRef().RangeCount();
   for (uint32_t i = 0; i < rangeCount; i++) {
@@ -7371,20 +7346,16 @@ HTMLEditRules::GetPromotedRanges(nsTArra
     // blocks that we will affect.  This call alters opRange.
     PromoteRange(*opRange, inOperationType);
 
     // Stuff new opRange into array
     outArrayOfRanges.AppendElement(opRange);
   }
 }
 
-/**
- * PromoteRange() expands a range to include any parents for which all editable
- * children are already in range.
- */
 void
 HTMLEditRules::PromoteRange(nsRange& aRange,
                             EditAction aOperationType)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
   MOZ_ASSERT(!aRange.IsInSelection());
 
   if (!aRange.IsPositioned()) {
@@ -7473,23 +7444,16 @@ public:
   {
     return !mArray.Contains(aNode);
   }
 
 private:
   nsTArray<OwningNonNull<nsINode>>& mArray;
 };
 
-/**
- * GetNodesForOperation() runs through the ranges in the array and construct a
- * new array of nodes to be acted on.
- *
- * XXX This name stats with "Get" but actually this modifies the DOM tree with
- *     transaction.  We should rename this to making clearer what this does.
- */
 nsresult
 HTMLEditRules::GetNodesForOperation(
                  nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
                  nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                  EditAction aOperationType,
                  TouchContent aTouchContent)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
@@ -7997,20 +7961,16 @@ HTMLEditRules::GetHighestInlineParent(ns
   for (nsIContent* parent = content->GetParent();
        parent && parent != host && IsInlineNode(*parent);
        parent = parent->GetParent()) {
     content = parent;
   }
   return content;
 }
 
-/**
- * GetNodesFromPoint() constructs a list of nodes from a point that will be
- * operated on.
- */
 nsresult
 HTMLEditRules::GetNodesFromPoint(
                  const EditorDOMPoint& aPoint,
                  EditAction aOperation,
                  nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
                  TouchContent aTouchContent)
 {
   if (NS_WARN_IF(!aPoint.IsSet())) {
@@ -8038,20 +7998,16 @@ HTMLEditRules::GetNodesFromPoint(
                          aTouchContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-/**
- * GetNodesFromSelection() constructs a list of nodes from the selection that
- * will be operated on.
- */
 nsresult
 HTMLEditRules::GetNodesFromSelection(
                  EditAction aOperation,
                  nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
                  TouchContent aTouchContent)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
@@ -8064,20 +8020,16 @@ HTMLEditRules::GetNodesFromSelection(
                                      aOperation, aTouchContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
-/**
- * MakeTransitionList() detects all the transitions in the array, where a
- * transition means that adjacent nodes in the array don't have the same parent.
- */
 void
 HTMLEditRules::MakeTransitionList(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
                                   nsTArray<bool>& aTransitionArray)
 {
   nsCOMPtr<nsINode> prevParent;
 
   aTransitionArray.EnsureLengthAtLeast(aNodeArray.Length());
   for (uint32_t i = 0; i < aNodeArray.Length(); i++) {
@@ -8087,21 +8039,16 @@ HTMLEditRules::MakeTransitionList(nsTArr
     } else {
       // Same parents: these nodes grew up together
       aTransitionArray[i] = false;
     }
     prevParent = aNodeArray[i]->GetParentNode();
   }
 }
 
-/**
- * If aNode is the descendant of a listitem, return that li.  But table element
- * boundaries are stoppers on the search.  Also stops on the active editor host
- * (contenteditable).  Also test if aNode is an li itself.
- */
 Element*
 HTMLEditRules::IsInListItem(nsINode* aNode)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   NS_ENSURE_TRUE(aNode, nullptr);
   if (HTMLEditUtils::IsListItem(aNode)) {
     return aNode->AsElement();
@@ -10192,19 +10139,16 @@ HTMLEditRules::SelectionEndpointInNode(n
         *aResult = true;
         return NS_OK;
       }
     }
   }
   return NS_OK;
 }
 
-/**
- * IsEmptyInline: Return true if aNode is an empty inline container
- */
 bool
 HTMLEditRules::IsEmptyInline(nsINode& aNode)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (IsInlineNode(aNode) && HTMLEditorRef().IsContainer(&aNode)) {
     bool isEmpty = true;
     HTMLEditorRef().IsEmptyNode(&aNode, &isEmpty);
@@ -10762,20 +10706,16 @@ HTMLEditRules::WillDeleteSelection(Selec
   }
   nsresult rv = mUtilRange->SetStartAndEnd(startPoint, endPoint);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
   UpdateDocChangeRange(mUtilRange);
 }
 
-// Let's remove all alignment hints in the children of aNode; it can
-// be an ALIGN attribute (in case we just remove it) or a CENTER
-// element (here we have to remove the container and keep its
-// children). We break on tables and don't look at their children.
 nsresult
 HTMLEditRules::RemoveAlignment(nsINode& aNode,
                                const nsAString& aAlignType,
                                bool aDescendantsOnly)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (EditorBase::IsTextNode(&aNode) || HTMLEditUtils::IsTable(&aNode)) {
@@ -10786,16 +10726,21 @@ HTMLEditRules::RemoveAlignment(nsINode& 
   if (aDescendantsOnly) {
     child = aNode.GetFirstChild();
   } else {
     child = &aNode;
   }
 
   bool useCSS = HTMLEditorRef().IsCSSEnabled();
 
+
+  // Let's remove all alignment hints in the children of aNode; it can
+  // be an ALIGN attribute (in case we just remove it) or a CENTER
+  // element (here we have to remove the container and keep its
+  // children). We break on tables and don't look at their children.
   while (child) {
     if (aDescendantsOnly) {
       // get the next sibling right now because we could have to remove child
       tmp = child->GetNextSibling();
     } else {
       tmp = nullptr;
     }
 
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -65,16 +65,30 @@ struct StyleCache final : public PropIte
   }
 
   ~StyleCache()
   {
     MOZ_COUNT_DTOR(StyleCache);
   }
 };
 
+/**
+ * Same as TextEditRules, any methods which may modify the DOM tree or
+ * Selection should be marked as MOZ_MUST_USE and return nsresult directly
+ * or with simple class like EditActionResult.  And every caller of them
+ * has to check whether the result is NS_ERROR_EDITOR_DESTROYED and if it is,
+ * its callers should stop handling edit action since after mutation event
+ * listener or selectionchange event listener disables the editor, we should
+ * not modify the DOM tree nor Selection anymore.  And also when methods of
+ * this class call methods of other classes like HTMLEditor and WSRunObject,
+ * they should check whether CanHandleEditAtion() returns false immediately
+ * after the calls.  If it returns false, they should return
+ * NS_ERROR_EDITOR_DESTROYED.
+ */
+
 #define SIZE_STYLE_TABLE 19
 
 class HTMLEditRules : public TextEditRules
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditRules, TextEditRules)
 
@@ -279,16 +293,26 @@ protected:
    * @param aNode           Reference to a block parent.
    * @param aInsertMozBR    true if this should insert a moz-<br> element.
    *                        Otherwise, i.e., this should insert a normal <br>
    *                        element, false.
    */
   MOZ_MUST_USE nsresult
   InsertBRIfNeededInternal(nsINode& aNode, bool aInsertMozBR);
 
+  /**
+   * GetGoodSelPointForNode() finds where at a node you would want to set the
+   * selection if you were trying to have a caret next to it.  Always returns a
+   * valid value (unless mHTMLEditor has gone away).
+   *
+   * @param aNode         The node
+   * @param aAction       Which edge to find:
+   *                        eNext/eNextWord/eToEndOfLine indicates beginning,
+   *                        ePrevious/PreviousWord/eToBeginningOfLine ending.
+   */
   EditorDOMPoint GetGoodSelPointForNode(nsINode& aNode,
                                         nsIEditor::EDirection aAction);
 
   /**
    * TryToJoinBlocksWithTransaction() tries to join two block elements.  The
    * right element is always joined to the left element.  If the elements are
    * the same type and not nested within each other,
    * JoinEditableNodesWithTransaction() is called (example, joining two list
@@ -573,23 +597,38 @@ protected:
    *                            should be aligned to.
    */
   MOZ_MUST_USE nsresult
   AlignContentsAtSelection(const nsAString& aAlignType);
 
   nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
                                   nsINode* aNode);
   nsresult GetFormatString(nsINode* aNode, nsAString &outFormat);
+
+  /**
+   * aLists and aTables allow the caller to specify what kind of content to
+   * "look inside".  If aTables is Tables::yes, look inside any table content,
+   * and insert the inner content into the supplied nsTArray at offset
+   * aIndex.  Similarly with aLists and list content.  aIndex is updated to
+   * point past inserted elements.
+   */
   enum class Lists { no, yes };
   enum class Tables { no, yes };
   void GetInnerContent(nsINode& aNode,
                        nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                        int32_t* aIndex, Lists aLists = Lists::yes,
                        Tables aTables = Tables::yes);
+
+  /**
+   * If aNode is the descendant of a listitem, return that li.  But table
+   * element boundaries are stoppers on the search.  Also stops on the active
+   * editor host (contenteditable).  Also test if aNode is an li itself.
+   */
   Element* IsInListItem(nsINode* aNode);
+
   nsAtom& DefaultParagraphSeparator();
 
   /**
    * ReturnInHeader() handles insertParagraph command (i.e., handling Enter
    * key press) in a heading element.  This splits aHeader element at
    * aOffset in aNode.  Then, if right heading element is empty, it'll be
    * removed and new paragraph is created (its type is decided with default
    * paragraph separator).
@@ -840,37 +879,71 @@ protected:
   /**
    * NormalizeSelection() adjust Selection if it's not collapsed and there is
    * only one range.  If range start and/or end point is <br> node or something
    * non-editable point, they should be moved to nearest text node or something
    * where the other methods easier to handle edit action.
    */
   MOZ_MUST_USE nsresult NormalizeSelection();
 
+  /**
+   * GetPromotedPoint() figures out where a start or end point for a block
+   * operation really is.
+   */
   EditorDOMPoint GetPromotedPoint(RulesEndpoint aWhere, nsINode& aNode,
                                   int32_t aOffset, EditAction actionID);
+
+  /**
+   * GetPromotedRanges() runs all the selection range endpoint through
+   * GetPromotedPoint().
+   */
   void GetPromotedRanges(nsTArray<RefPtr<nsRange>>& outArrayOfRanges,
                          EditAction inOperationType);
+
+  /**
+   * PromoteRange() expands a range to include any parents for which all
+   * editable children are already in range.
+   */
   void PromoteRange(nsRange& aRange, EditAction inOperationType);
+
+  /**
+   * GetNodesForOperation() runs through the ranges in the array and construct a
+   * new array of nodes to be acted on.
+   *
+   * XXX This name stats with "Get" but actually this modifies the DOM tree with
+   *     transaction.  We should rename this to making clearer what this does.
+   */
   enum class TouchContent { no, yes };
   MOZ_MUST_USE nsresult
   GetNodesForOperation(nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
                        nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                        EditAction aOperationType, TouchContent aTouchContent);
+
   void GetChildNodesForOperation(
          nsINode& aNode,
          nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes);
+
+  /**
+   * GetNodesFromPoint() constructs a list of nodes from a point that will be
+   * operated on.
+   */
   MOZ_MUST_USE nsresult
   GetNodesFromPoint(const EditorDOMPoint& aPoint, EditAction aOperation,
                     nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
                     TouchContent aTouchContent);
+
+  /**
+   * GetNodesFromSelection() constructs a list of nodes from the selection that
+   * will be operated on.
+   */
   MOZ_MUST_USE nsresult
   GetNodesFromSelection(EditAction aOperation,
                         nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
                         TouchContent aTouchContent);
+
   enum class EntireList { no, yes };
   MOZ_MUST_USE nsresult
   GetListActionNodes(nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
                      EntireList aEntireList, TouchContent aTouchContent);
   void GetDefinitionListItemTypes(Element* aElement, bool* aDT, bool* aDD);
   nsresult
   GetParagraphFormatNodes(nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes);
   void LookInsideDivBQandList(nsTArray<OwningNonNull<nsINode>>& aNodeArray);
@@ -903,16 +976,22 @@ protected:
                      nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes);
 
   /**
    * GetHiestInlineParent() returns the highest inline node parent between
    * aNode and the editing host.  Even if the editing host is an inline
    * element, this method never returns the editing host as the result.
    */
   nsIContent* GetHighestInlineParent(nsINode& aNode);
+
+  /**
+   * MakeTransitionList() detects all the transitions in the array, where a
+   * transition means that adjacent nodes in the array don't have the same
+   * parent.
+   */
   void MakeTransitionList(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
                           nsTArray<bool>& aTransitionArray);
 
   /**
    * RemoveBlockStyle() removes all format blocks, table related element,
    * etc in aNodeArray.
    * If aNodeArray has a format node, it will be removed and its contents
    * will be moved to where it was.
@@ -1127,17 +1206,21 @@ protected:
    * and only one Selection range.
    * XXX This method is not necessary because even if selection is outside the
    *     <body> element, elements outside the <body> element should be
    *     editable, e.g., any element can be inserted siblings as <body> element
    *     and other browsers allow to edit such elements.
    */
   MOZ_MUST_USE nsresult ConfirmSelectionInBody();
 
+  /**
+   * IsEmptyInline: Return true if aNode is an empty inline container
+   */
   bool IsEmptyInline(nsINode& aNode);
+
   bool ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& arrayOfNodes);
 
   /**
    * RemoveAlignment() removes align attributes, text-align properties and
    * <center> elements in aNode.
    *
    * @param aNode               Alignment information of the node and/or its
    *                            descendants will be removed.
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -388,21 +388,16 @@ TextEditRules::DidDoAction(Selection* aS
     case EditAction::redo:
       return DidRedo(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.
- */
 bool
 TextEditRules::DocumentIsEmpty()
 {
   bool retVal = false;
   if (!mTextEditor || NS_FAILED(mTextEditor->DocumentIsEmpty(&retVal))) {
     retVal = true;
   }
 
@@ -1191,37 +1186,36 @@ TextEditRules::WillUndo(bool* aCancel,
   }
   CANCEL_OPERATION_IF_READONLY_OR_DISABLED
   // initialize out param
   *aCancel = false;
   *aHandled = false;
   return NS_OK;
 }
 
-/**
- * The idea here is to see if the magic empty node has suddenly reappeared as
- * the result of the undo.  If it has, set our state so we remember it.
- * There is a tradeoff between doing here and at redo, or doing it everywhere
- * else that might care.  Since undo and redo are relatively rare, it makes
- * sense to take the (small) performance hit here.
- */
 nsresult
 TextEditRules::DidUndo(nsresult aResult)
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   // If aResult is an error, we return it.
   if (NS_WARN_IF(NS_FAILED(aResult))) {
     return aResult;
   }
 
   Element* rootElement = TextEditorRef().GetRoot();
   if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_FAILURE;
   }
+
+  // The idea here is to see if the magic empty node has suddenly reappeared as
+  // the result of the undo.  If it has, set our state so we remember it.
+  // There is a tradeoff between doing here and at redo, or doing it everywhere
+  // else that might care.  Since undo and redo are relatively rare, it makes
+  // sense to take the (small) performance hit here.
   nsIContent* node = TextEditorRef().GetLeftmostChild(rootElement);
   if (node && TextEditorRef().IsMozEditorBogusNode(node)) {
     mBogusNode = node;
   } else {
     mBogusNode = nullptr;
   }
   return aResult;
 }
--- a/editor/libeditor/TextEditRules.h
+++ b/editor/libeditor/TextEditRules.h
@@ -36,16 +36,28 @@ class Selection;
  * To be a good citizen, edit rules must live by these restrictions:
  * 1. All data manipulation is through the editor.
  *    Content nodes in the document tree must <B>not</B> be manipulated
  *    directly.  Content nodes in document fragments that are not part of the
  *    document itself may be manipulated at will.  Operations on document
  *    fragments must <B>not</B> go through the editor.
  * 2. Selection must not be explicitly set by the rule method.
  *    Any manipulation of Selection must be done by the editor.
+ * 3. Stop handling edit action if method returns NS_ERROR_EDITOR_DESTROYED
+ *    since if mutation event lister or selectionchange event listener disables
+ *    the editor, we should not modify the DOM tree anymore.
+ * 4. Any method callers have to check nsresult return value (both directly or
+ *    with simple class like EditActionResult) whether the value is
+ *    NS_ERROR_EDITOR_DESTROYED at least.
+ * 5. Callers of methods of other classes such as TextEditor, have to check
+ *    CanHandleEditAction() before checking its result and if the result is
+ *    false, the method have to return NS_ERROR_EDITOR_DESTROYED.  In other
+ *    words, any methods which may change Selection or the DOM tree have to
+ *    return nsresult directly or with simple class like EditActionResult.
+ *    And such methods should be marked as MOZ_MUST_USE.
  */
 class TextEditRules : public nsITimerCallback
                     , public nsINamed
 {
 public:
   typedef dom::Element Element;
   typedef dom::Selection Selection;
   typedef dom::Text Text;
@@ -70,17 +82,24 @@ public:
                              nsIEditor::EDirection aDirection);
   virtual nsresult WillDoAction(Selection* aSelection,
                                 RulesInfo* aInfo,
                                 bool* aCancel,
                                 bool* aHandled);
   virtual nsresult DidDoAction(Selection* aSelection,
                                RulesInfo* aInfo,
                                nsresult aResult);
+
+  /**
+   * Return false if the editor has non-empty text nodes or non-text
+   * nodes.  Otherwise, i.e., there is no meaningful content,
+   * return true.
+   */
   virtual bool DocumentIsEmpty();
+
   virtual nsresult DocumentModified();
 
 protected:
   virtual ~TextEditRules();
 
 public:
   void ResetIMETextPWBuf();