Bug 950076 - Add a fallible form of nsAString::Append and Replace and use it in nsTextFragment::AppendTo. r=bsmedberg, r=jst
authorAlessio Placitelli <alessio.placitelli@gmail.com>
Wed, 19 Mar 2014 13:05:02 -0400
changeset 175104 9fc71a41bee5c261b4650b06dc0ff2b694dbb32d
parent 175103 569ab9f8ff191e78b6e27c27f3fdd37c13fa8c85
child 175105 b7da9111c2e9607ed96fd3c3c95df25f04fe3e5b
push id271
push userpvanderbeken@mozilla.com
push dateMon, 24 Mar 2014 22:43:42 +0000
reviewersbsmedberg, jst
bugs950076
milestone31.0a1
Bug 950076 - Add a fallible form of nsAString::Append and Replace and use it in nsTextFragment::AppendTo. r=bsmedberg, r=jst
content/base/public/FragmentOrElement.h
content/base/public/nsContentUtils.h
content/base/public/nsIContent.h
content/base/src/FragmentOrElement.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericDOMDataNode.h
content/base/src/nsTextFragment.h
dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
xpcom/string/public/nsTSubstring.h
xpcom/string/src/nsTSubstring.cpp
--- a/content/base/public/FragmentOrElement.h
+++ b/content/base/public/FragmentOrElement.h
@@ -196,16 +196,18 @@ public:
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) MOZ_OVERRIDE;
   virtual bool TextIsOnlyWhitespace() MOZ_OVERRIDE;
   virtual void AppendTextTo(nsAString& aResult) MOZ_OVERRIDE;
+  virtual bool AppendTextTo(nsAString& aResult,
+                            const mozilla::fallible_t&) MOZ_OVERRIDE NS_WARN_UNUSED_RESULT; 
   virtual nsIContent *GetBindingParent() const MOZ_OVERRIDE;
   virtual nsXBLBinding *GetXBLBinding() const MOZ_OVERRIDE;
   virtual void SetXBLBinding(nsXBLBinding* aBinding,
                              nsBindingManager* aOldBindingManager = nullptr) MOZ_OVERRIDE;
   virtual ShadowRoot *GetShadowRoot() const MOZ_OVERRIDE;
   virtual ShadowRoot *GetContainingShadow() const MOZ_OVERRIDE;
   virtual void SetShadowRoot(ShadowRoot* aBinding) MOZ_OVERRIDE;
   virtual nsIContent *GetXBLInsertionParent() const MOZ_OVERRIDE;
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1242,18 +1242,18 @@ public:
    * @param aResult the result. Out param.
    */
   static void GetNodeTextContent(nsINode* aNode, bool aDeep,
                                  nsAString& aResult);
 
   /**
    * Same as GetNodeTextContents but appends the result rather than sets it.
    */
-  static void AppendNodeTextContent(nsINode* aNode, bool aDeep,
-                                    nsAString& aResult);
+  static bool AppendNodeTextContent(nsINode* aNode, bool aDeep,
+                                    nsAString& aResult, const mozilla::fallible_t&);
 
   /**
    * Utility method that checks if a given node has any non-empty
    * children.
    * NOTE! This method does not descend recursivly into elements.
    * Though it would be easy to make it so if needed
    */
   static bool HasNonEmptyTextContent(nsINode* aNode);
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -535,16 +535,23 @@ public:
 
   /**
    * Append the text content to aResult.
    * NOTE: This asserts and returns for elements
    */
   virtual void AppendTextTo(nsAString& aResult) = 0;
 
   /**
+   * Append the text content to aResult.
+   * NOTE: This asserts and returns for elements
+   */
+  virtual bool AppendTextTo(nsAString& aResult,
+                            const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT = 0;
+
+  /**
    * Check if this content is focusable and in the current tab order.
    * Note: most callers should use nsIFrame::IsFocusable() instead as it 
    *       checks visibility and other layout factors as well.
    * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
    * For example, only the selected radio button in a group is in the 
    * tab order, unless the radio group has no selection in which case
    * all of the visible, non-disabled radio buttons in the group are 
    * in the tab order. On the other hand, all of the visible, non-disabled 
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -1922,16 +1922,26 @@ FragmentOrElement::TextIsOnlyWhitespace(
 void
 FragmentOrElement::AppendTextTo(nsAString& aResult)
 {
   // We can remove this assertion if it turns out to be useful to be able
   // to depend on this appending nothing.
   NS_NOTREACHED("called FragmentOrElement::TextLength");
 }
 
+bool
+FragmentOrElement::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
+{
+  // We can remove this assertion if it turns out to be useful to be able
+  // to depend on this appending nothing.
+  NS_NOTREACHED("called FragmentOrElement::TextLength");
+
+  return false;
+}
+
 uint32_t
 FragmentOrElement::GetChildCount() const
 {
   return mAttrsAndChildren.ChildCount();
 }
 
 nsIContent *
 FragmentOrElement::GetChildAt(uint32_t aIndex) const
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4186,50 +4186,68 @@ nsContentUtils::SetNodeTextContent(nsICo
 
   textContent->SetText(aValue, true);
 
   nsresult rv = aContent->AppendChildTo(textContent, true);
   mb.NodesAdded();
   return rv;
 }
 
-static void AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult)
+static bool
+AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult,
+                              const mozilla::fallible_t&)
 {
   for (nsIContent* child = aNode->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     if (child->IsElement()) {
-      AppendNodeTextContentsRecurse(child, aResult);
+      bool ok = AppendNodeTextContentsRecurse(child, aResult,
+                                              mozilla::fallible_t());
+      if (!ok) {
+        return false;
+      }
     }
     else if (child->IsNodeOfType(nsINode::eTEXT)) {
-      child->AppendTextTo(aResult);
+      bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
+      if (!ok) {
+        return false;
+      }
     }
   }
+
+  return true;
 }
 
 /* static */
-void
+bool
 nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep,
-                                      nsAString& aResult)
+                                      nsAString& aResult,
+                                      const mozilla::fallible_t&)
 {
   if (aNode->IsNodeOfType(nsINode::eTEXT)) {
-    static_cast<nsIContent*>(aNode)->AppendTextTo(aResult);
+    return static_cast<nsIContent*>(aNode)->AppendTextTo(aResult,
+                                                         mozilla::fallible_t());
   }
   else if (aDeep) {
-    AppendNodeTextContentsRecurse(aNode, aResult);
+    return AppendNodeTextContentsRecurse(aNode, aResult, mozilla::fallible_t());
   }
   else {
     for (nsIContent* child = aNode->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
       if (child->IsNodeOfType(nsINode::eTEXT)) {
-        child->AppendTextTo(aResult);
+        bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
+        if (!ok) {
+            return false;
+        }
       }
     }
   }
+
+  return true;
 }
 
 bool
 nsContentUtils::HasNonEmptyTextContent(nsINode* aNode)
 {
   for (nsIContent* child = aNode->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
@@ -6568,17 +6586,17 @@ nsContentUtils::DOMWindowDumpEnabled()
   return true;
 #endif
 }
 
 void
 nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
 {
   aResult.Truncate();
-  AppendNodeTextContent(aNode, aDeep, aResult);
+  AppendNodeTextContent(aNode, aDeep, aResult, mozilla::fallible_t());
 }
 
 void
 nsContentUtils::DestroyMatchString(void* aData)
 {
   if (aData) {
     nsString* matchString = static_cast<nsString*>(aData);
     delete matchString;
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -991,16 +991,22 @@ nsGenericDOMDataNode::TextIsOnlyWhitespa
 }
 
 void
 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
 {
   mText.AppendTo(aResult);
 }
 
+bool
+nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
+{
+  return mText.AppendTo(aResult, mozilla::fallible_t());
+}
+
 already_AddRefed<nsIAtom>
 nsGenericDOMDataNode::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
   return NS_NewAtom(val);
 }
 
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -141,16 +141,18 @@ public:
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) MOZ_OVERRIDE;
   virtual bool TextIsOnlyWhitespace() MOZ_OVERRIDE;
   virtual void AppendTextTo(nsAString& aResult) MOZ_OVERRIDE;
+  virtual bool AppendTextTo(nsAString& aResult,
+                            const mozilla::fallible_t&) MOZ_OVERRIDE NS_WARN_UNUSED_RESULT;
   virtual void DestroyContent() MOZ_OVERRIDE;
   virtual void SaveSubtreeState() MOZ_OVERRIDE;
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const MOZ_OVERRIDE;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const MOZ_OVERRIDE;
 #endif
 
--- a/content/base/src/nsTextFragment.h
+++ b/content/base/src/nsTextFragment.h
@@ -120,33 +120,71 @@ public:
    * it includes any Bidi characters.
    */
   bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi);
 
   /**
    * Append the contents of this string fragment to aString
    */
   void AppendTo(nsAString& aString) const {
+    if (!AppendTo(aString, mozilla::fallible_t())) {
+      NS_ABORT_OOM(GetLength());
+    }
+  }
+
+  /**
+   * Append the contents of this string fragment to aString
+   * @return false if an out of memory condition is detected, true otherwise
+   */
+  bool AppendTo(nsAString& aString,
+                const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT {
     if (mState.mIs2b) {
-      aString.Append(m2b, mState.mLength);
+      bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t());
+      if (!ok) {
+        return false;
+      }
+
+      return true;
     } else {
-      AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString);
+      return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
+                                mozilla::fallible_t());
     }
   }
 
   /**
    * Append a substring of the contents of this string fragment to aString.
    * @param aOffset where to start the substring in this text fragment
    * @param aLength the length of the substring
    */
   void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
+    if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) {
+      NS_ABORT_OOM(aLength);
+    }
+  }
+
+  /**
+   * Append a substring of the contents of this string fragment to aString.
+   * @param aString the string in which to append
+   * @param aOffset where to start the substring in this text fragment
+   * @param aLength the length of the substring
+   * @return false if an out of memory condition is detected, true otherwise
+   */
+  bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
+                const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT
+  {
     if (mState.mIs2b) {
-      aString.Append(m2b + aOffset, aLength);
+      bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t());
+      if (!ok) {
+        return false;
+      }
+
+      return true;
     } else {
-      AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString);
+      return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString,
+                                mozilla::fallible_t());
     }
   }
 
   /**
    * Make a copy of the fragments contents starting at offset for
    * count characters. The offset and count will be adjusted to
    * lie within the fragments data. The fragments data is converted if
    * necessary.
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -509,17 +509,18 @@ txXPathNodeUtils::appendNodeValue(const 
         }
 
         return;
     }
 
     if (aNode.isDocument() ||
         aNode.mNode->IsElement() ||
         aNode.mNode->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
-        nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult);
+        nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult,
+                                              mozilla::fallible_t());
 
         return;
     }
 
     aNode.Content()->AppendTextTo(aResult);
 }
 
 /* static */
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -563,24 +563,31 @@ mozInlineSpellWordUtil::BuildSoftText()
           if (IsDOMWordSeparator(textFragment->CharAt(i))) {
             exit = true;
             // stop at the first separator after the soft end point
             lastOffsetInNode = i;
             break;
           }
         }
       }
-      
+
       if (firstOffsetInNode < lastOffsetInNode) {
         int32_t len = lastOffsetInNode - firstOffsetInNode;
         mSoftTextDOMMapping.AppendElement(
           DOMTextMapping(NodeOffset(node, firstOffsetInNode), mSoftText.Length(), len));
-        textFragment->AppendTo(mSoftText, firstOffsetInNode, len);
+
+        bool ok = textFragment->AppendTo(mSoftText, firstOffsetInNode, len,
+                                         mozilla::fallible_t());
+        if (!ok) {
+            // probably out of memory, remove from mSoftTextDOMMapping
+            mSoftTextDOMMapping.RemoveElementAt(mSoftTextDOMMapping.Length() - 1);
+            exit = true;
+        }
       }
-      
+
       firstOffsetInNode = 0;
     }
 
     if (exit)
       break;
 
     CheckLeavingBreakElementClosure closure = { false };
     node = FindNextNode(node, mRootNode, CheckLeavingBreakElement, &closure);
--- a/xpcom/string/public/nsTSubstring.h
+++ b/xpcom/string/public/nsTSubstring.h
@@ -410,30 +410,37 @@ class nsTSubstring_CharT
       void NS_FASTCALL Adopt( char_type* data, size_type length = size_type(-1) );
 
 
         /**
          * buffer manipulation
          */
 
       void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c );
+      bool NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT;
       void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) );
+      bool NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT;
       void Replace( index_type cutStart, size_type cutLength, const self_type& str )      { Replace(cutStart, cutLength, str.Data(), str.Length()); }
+      bool Replace( index_type cutStart, size_type cutLength, const self_type& str, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT
+                 { return Replace(cutStart, cutLength, str.Data(), str.Length(), mozilla::fallible_t()); }
       void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple );
 
       void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) );
 
     // ReplaceLiteral must ONLY be applied to an actual literal string.
     // Do not attempt to use it with a regular char* pointer, or with a char
     // array variable. Use Replace or ReplaceASCII for those.
       template<int N>
       void ReplaceLiteral( index_type cutStart, size_type cutLength, const char_type (&str)[N] ) { ReplaceLiteral(cutStart, cutLength, str, N - 1); }
 
       void Append( char_type c )                                                                 { Replace(mLength, 0, c); }
+      bool Append( char_type c, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT                { return Replace(mLength, 0, c, mozilla::fallible_t()); }
       void Append( const char_type* data, size_type length = size_type(-1) )                     { Replace(mLength, 0, data, length); }
+      bool Append( const char_type* data, size_type length, const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT
+                 { return Replace(mLength, 0, data, length, mozilla::fallible_t()); }
 
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
     void Append( char16ptr_t data, size_type length = size_type(-1) )                            { Append(static_cast<const char16_t*>(data), length); }
 #endif
 
       void Append( const self_type& str )                                                        { Replace(mLength, 0, str); }
       void Append( const substring_tuple_type& tuple )                                           { Replace(mLength, 0, tuple); }
 
--- a/xpcom/string/src/nsTSubstring.cpp
+++ b/xpcom/string/src/nsTSubstring.cpp
@@ -479,50 +479,76 @@ void
 nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, char_type c )
   {
     cutStart = XPCOM_MIN(cutStart, Length());
 
     if (ReplacePrep(cutStart, cutLength, 1))
       mData[cutStart] = c;
   }
 
+bool
+nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, char_type c, const mozilla::fallible_t& )
+  {
+    cutStart = XPCOM_MIN(cutStart, Length());
+
+    if (!ReplacePrep(cutStart, cutLength, 1))
+      return false;
+
+    mData[cutStart] = c;
+
+    return true;
+  }
 
 void
 nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length )
   {
+    if (!Replace(cutStart, cutLength, data, length, mozilla::fallible_t()))
+      {
+        NS_ABORT_OOM(Length() - cutLength + 1);
+      }
+  }
+
+bool
+nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length, const mozilla::fallible_t& )
+  {
       // unfortunately, some callers pass null :-(
     if (!data)
       {
         length = 0;
       }
     else
       {
         if (length == size_type(-1))
           length = char_traits::length(data);
 
         if (IsDependentOn(data, data + length))
           {
             nsTAutoString_CharT temp(data, length);
-            Replace(cutStart, cutLength, temp);
-            return;
+            return Replace(cutStart, cutLength, temp, mozilla::fallible_t());
           }
       }
 
     cutStart = XPCOM_MIN(cutStart, Length());
 
-    if (ReplacePrep(cutStart, cutLength, length) && length > 0)
+    bool ok = ReplacePrep(cutStart, cutLength, length);
+    if (!ok)
+      return false;
+
+    if (length > 0)
       char_traits::copy(mData + cutStart, data, length);
+
+    return true;
   }
 
 void
 nsTSubstring_CharT::ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length )
   {
     if (length == size_type(-1))
       length = strlen(data);
-    
+
     // A Unicode string can't depend on an ASCII string buffer,
     // so this dependence check only applies to CStrings.
 #ifdef CharT_is_char
     if (IsDependentOn(data, data + length))
       {
         nsTAutoString_CharT temp(data, length);
         Replace(cutStart, cutLength, temp);
         return;