Bug 1167189: Add an infallible version of nsContentUtils::GetNodeTextContent. r=jst
authorDavid Major <dmajor@mozilla.com>
Fri, 22 May 2015 14:16:20 -0400
changeset 245225 bd2239b9df33324430c609bd0cec7467b7d202d1
parent 245224 351d94c3ca27c873d924bf43a0fa0006cbecc65a
child 245226 6cf58656d6fb28c8ea79ae0b139a905aa8900bdf
push id28799
push userphilringnalda@gmail.com
push dateSat, 23 May 2015 20:31:44 +0000
treeherdermozilla-central@c3c0928c3cde [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs1167189
milestone41.0a1
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
Bug 1167189: Add an infallible version of nsContentUtils::GetNodeTextContent. r=jst
dom/base/FragmentOrElement.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDocument.cpp
dom/base/nsStyleLinkElement.cpp
dom/base/nsTreeSanitizer.cpp
dom/html/HTMLAnchorElement.cpp
dom/html/HTMLElement.cpp
dom/html/HTMLMenuItemElement.cpp
dom/html/HTMLOutputElement.cpp
dom/html/HTMLScriptElement.cpp
dom/html/HTMLStyleElement.cpp
dom/html/HTMLTextAreaElement.cpp
dom/html/HTMLTitleElement.cpp
dom/svg/SVGScriptElement.cpp
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp
layout/generic/nsRubyBaseContainerFrame.cpp
layout/mathml/nsMathMLTokenFrame.cpp
layout/mathml/nsMathMLmoFrame.cpp
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1152,17 +1152,17 @@ FragmentOrElement::RemoveChildAt(uint32_
     doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
   }
 }
 
 void
 FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
                                           ErrorResult& aError)
 {
-  if(!nsContentUtils::GetNodeTextContent(this, true, aTextContent)) {
+  if(!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
     aError.Throw(NS_ERROR_OUT_OF_MEMORY);
   }
 }
 
 void
 FragmentOrElement::SetTextContentInternal(const nsAString& aTextContent,
                                           ErrorResult& aError)
 {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7052,20 +7052,29 @@ nsContentUtils::DOMWindowDumpEnabled()
   // enabled.
   return nsContentUtils::sDOMWindowDumpEnabled;
 #else
   return true;
 #endif
 }
 
 bool
-nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
+nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult,
+                                   const fallible_t& aFallible)
 {
   aResult.Truncate();
-  return AppendNodeTextContent(aNode, aDeep, aResult, fallible);
+  return AppendNodeTextContent(aNode, aDeep, aResult, aFallible);
+}
+
+void
+nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
+{
+  if (!GetNodeTextContent(aNode, aDeep, aResult, fallible)) {
+    NS_ABORT_OOM(0); // Unfortunately we don't know the allocation size
+  }
 }
 
 void
 nsContentUtils::DestroyMatchString(void* aData)
 {
   if (aData) {
     nsString* matchString = static_cast<nsString*>(aData);
     delete matchString;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1274,16 +1274,19 @@ public:
    * @param aNode Node to get textual contents of.
    * @param aDeep If true child elements of aNode are recursivly descended
    *              into to find text children.
    * @param aResult the result. Out param.
    * @return false on out of memory errors, true otherwise.
    */
   MOZ_WARN_UNUSED_RESULT
   static bool GetNodeTextContent(nsINode* aNode, bool aDeep,
+                                 nsAString& aResult, const mozilla::fallible_t&);
+
+  static void GetNodeTextContent(nsINode* aNode, bool aDeep,
                                  nsAString& aResult);
 
   /**
    * Same as GetNodeTextContents but appends the result rather than sets it.
    */
   static bool AppendNodeTextContent(nsINode* aNode, bool aDeep,
                                     nsAString& aResult, const mozilla::fallible_t&);
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7081,18 +7081,17 @@ nsDocument::GetTitleContent(uint32_t aNa
 }
 
 void
 nsDocument::GetTitleFromElement(uint32_t aNamespace, nsAString& aTitle)
 {
   nsIContent* title = GetTitleContent(aNamespace);
   if (!title)
     return;
-  if(!nsContentUtils::GetNodeTextContent(title, false, aTitle))
-    NS_RUNTIMEABORT("OOM");
+  nsContentUtils::GetNodeTextContent(title, false, aTitle);
 }
 
 NS_IMETHODIMP
 nsDocument::GetTitle(nsAString& aTitle)
 {
   nsString title;
   GetTitle(title);
   aTitle = title;
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -399,17 +399,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
     NS_ASSERTION(isInline, "non-inline style must not have scope element");
     scopeElement->SetIsElementInStyleScopeFlagOnSubtree(true);
   }
 
   bool doneLoading = false;
   nsresult rv = NS_OK;
   if (isInline) {
     nsAutoString text;
-    if (!nsContentUtils::GetNodeTextContent(thisContent, false, text)) {
+    if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
                "<link> is not 'inline', and needs different CSP checks");
     if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
                                            thisContent->NodePrincipal(),
                                            doc->GetDocumentURI(),
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -1391,19 +1391,18 @@ nsTreeSanitizer::SanitizeChildren(nsINod
       }
       if (nsGkAtoms::style == localName) {
         // If styles aren't allowed, style elements got pruned above. Even
         // if styles are allowed, non-HTML, non-SVG style elements got pruned
         // above.
         NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG,
             "Should have only HTML or SVG here!");
         nsAutoString styleText;
-        if (!nsContentUtils::GetNodeTextContent(node, false, styleText)) {
-          NS_RUNTIMEABORT("OOM");
-        }
+        nsContentUtils::GetNodeTextContent(node, false, styleText);
+
         nsAutoString sanitizedStyle;
         nsCOMPtr<nsIURI> baseURI = node->GetBaseURI();
         if (SanitizeStyleSheet(styleText,
                                sanitizedStyle,
                                aRoot->OwnerDoc(),
                                baseURI)) {
           nsContentUtils::SetNodeTextContent(node, sanitizedStyle, true);
         } else {
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -339,17 +339,17 @@ IMPL_URI_PART(Search)
 IMPL_URI_PART(Port)
 IMPL_URI_PART(Hash)
 
 #undef IMPL_URI_PART
 
 NS_IMETHODIMP    
 HTMLAnchorElement::GetText(nsAString& aText)
 {
-  if(!nsContentUtils::GetNodeTextContent(this, true, aText)) {
+  if(!nsContentUtils::GetNodeTextContent(this, true, aText, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP    
 HTMLAnchorElement::SetText(const nsAString& aText)
 {
--- a/dom/html/HTMLElement.cpp
+++ b/dom/html/HTMLElement.cpp
@@ -44,17 +44,17 @@ HTMLElement::GetInnerHTML(nsAString& aIn
    * nsGenericHTMLElement::GetInnerHTML escapes < and > characters (at least).
    * .innerHTML should return the HTML code for xmp and plaintext element.
    *
    * This code is a workaround until we implement a HTML5 Serializer
    * with this behavior.
    */
   if (mNodeInfo->Equals(nsGkAtoms::xmp) ||
       mNodeInfo->Equals(nsGkAtoms::plaintext)) {
-    if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML)) {
+    if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     return NS_OK;
   }
 
   return nsGenericHTMLElement::GetInnerHTML(aInnerHTML);
 }
 
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -367,19 +367,17 @@ HTMLMenuItemElement::DoneCreatingElement
     mShouldInitChecked = false;
   }
 }
 
 void
 HTMLMenuItemElement::GetText(nsAString& aText)
 {
   nsAutoString text;
-  if (!nsContentUtils::GetNodeTextContent(this, false, text)) {
-    NS_RUNTIMEABORT("OOM");
-  }
+  nsContentUtils::GetNodeTextContent(this, false, text);
 
   text.CompressWhitespace(true, true);
   aText = text;
 }
 
 nsresult
 HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                   const nsAttrValue* aValue, bool aNotify)
--- a/dom/html/HTMLOutputElement.cpp
+++ b/dom/html/HTMLOutputElement.cpp
@@ -142,19 +142,17 @@ HTMLOutputElement::BindToTree(nsIDocumen
   UpdateState(false);
 
   return rv;
 }
 
 void
 HTMLOutputElement::GetValue(nsAString& aValue)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, true, aValue)) {
-    NS_RUNTIMEABORT("OOM");
-  }
+  nsContentUtils::GetNodeTextContent(this, true, aValue);
 }
 
 void
 HTMLOutputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
 {
   mValueModeFlag = eModeValue;
   aRv = nsContentUtils::SetNodeTextContent(this, aValue, true);
 }
@@ -175,19 +173,17 @@ HTMLOutputElement::HtmlFor()
     mTokenList = new nsDOMSettableTokenList(this, nsGkAtoms::_for);
   }
   return mTokenList;
 }
 
 void HTMLOutputElement::DescendantsChanged()
 {
   if (mIsDoneAddingChildren && mValueModeFlag == eModeDefault) {
-    if (!nsContentUtils::GetNodeTextContent(this, true, mDefaultValue)) {
-      NS_RUNTIMEABORT("OOM");
-    }
+    nsContentUtils::GetNodeTextContent(this, true, mDefaultValue);
   }
 }
 
 // nsIMutationObserver
 
 void HTMLOutputElement::CharacterDataChanged(nsIDocument* aDocument,
                                              nsIContent* aContent,
                                              CharacterDataChangeInfo* aInfo)
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -105,17 +105,17 @@ HTMLScriptElement::Clone(mozilla::dom::N
   kungFuDeathGrip.swap(*aResult);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLScriptElement::GetText(nsAString& aValue)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, aValue)) {
+  if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLScriptElement::SetText(const nsAString& aValue)
 {
@@ -217,17 +217,17 @@ HTMLScriptElement::AfterSetAttr(int32_t 
   }
   return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
                                             aNotify);
 }
 
 NS_IMETHODIMP
 HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML)) {
+  if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 void
 HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
                                 ErrorResult& aError)
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -209,17 +209,17 @@ HTMLStyleElement::UnsetAttr(int32_t aNam
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML)) {
+  if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 void
 HTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML,
                                ErrorResult& aError)
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -357,17 +357,17 @@ HTMLTextAreaElement::SetValueChanged(boo
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::GetDefaultValue(nsAString& aDefaultValue)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, aDefaultValue)) {
+  if (!nsContentUtils::GetNodeTextContent(this, false, aDefaultValue, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }  
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue)
 {
--- a/dom/html/HTMLTitleElement.cpp
+++ b/dom/html/HTMLTitleElement.cpp
@@ -37,17 +37,17 @@ JSObject*
 HTMLTitleElement::WrapNode(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLTitleElementBinding::Wrap(cx, this, aGivenProto);
 }
 
 void
 HTMLTitleElement::GetText(DOMString& aText, ErrorResult& aError)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, aText)) {
+  if (!nsContentUtils::GetNodeTextContent(this, false, aText, fallible)) {
     aError = NS_ERROR_OUT_OF_MEMORY;
   }
 }
 
 void
 HTMLTitleElement::SetText(const nsAString& aText, ErrorResult& aError)
 {
   aError = nsContentUtils::SetNodeTextContent(this, aText, true);
--- a/dom/svg/SVGScriptElement.cpp
+++ b/dom/svg/SVGScriptElement.cpp
@@ -119,19 +119,17 @@ void
 SVGScriptElement::GetScriptType(nsAString& type)
 {
   GetType(type);
 }
 
 void
 SVGScriptElement::GetScriptText(nsAString& text)
 {
-  if (!nsContentUtils::GetNodeTextContent(this, false, text)) {
-    NS_RUNTIMEABORT("OOM");
-  }
+  nsContentUtils::GetNodeTextContent(this, false, text);
 }
 
 void
 SVGScriptElement::GetScriptCharset(nsAString& charset)
 {
   charset.Truncate();
 }
 
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -356,19 +356,17 @@ nsXBLPrototypeBinding::AttributeChanged(
       if (aRemoveFlag)
         realElement->UnsetAttr(dstNs, dstAttr, aNotify);
       else {
         bool attrPresent = true;
         nsAutoString value;
         // Check to see if the src attribute is xbl:text.  If so, then we need to obtain the
         // children of the real element and get the text nodes' values.
         if (aAttribute == nsGkAtoms::text && aNameSpaceID == kNameSpaceID_XBL) {
-          if (!nsContentUtils::GetNodeTextContent(aChangedElement, false, value)) {
-            NS_RUNTIMEABORT("OOM");
-          }
+          nsContentUtils::GetNodeTextContent(aChangedElement, false, value);
           value.StripChar(char16_t('\n'));
           value.StripChar(char16_t('\r'));
           nsAutoString stripVal(value);
           stripVal.StripWhitespace();
           if (stripVal.IsEmpty()) 
             attrPresent = false;
         }
         else {
@@ -509,20 +507,18 @@ SetAttrs(nsISupports* aKey, nsXBLAttribu
   nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
 
   nsIAtom* src = aEntry->GetSrcAttribute();
   int32_t srcNs = changeData->mSrcNamespace;
   nsAutoString value;
   bool attrPresent = true;
 
   if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
-    if (!nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
-                                       value)) {
-      NS_RUNTIMEABORT("OOM");
-    }
+    nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
+                                       value);
     value.StripChar(char16_t('\n'));
     value.StripChar(char16_t('\r'));
     nsAutoString stripVal(value);
     stripVal.StripWhitespace();
 
     if (stripVal.IsEmpty()) 
       attrPresent = false;
   }
--- a/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp
+++ b/dom/xul/templates/nsXULTemplateQueryProcessorStorage.cpp
@@ -285,17 +285,17 @@ nsXULTemplateQueryProcessorStorage::Comp
     uint32_t length;
     childNodes->GetLength(&length);
 
     nsCOMPtr<mozIStorageStatement> statement;
     nsCOMPtr<nsIContent> queryContent = do_QueryInterface(aQueryNode);
     nsAutoString sqlQuery;
 
     // Let's get all text nodes (which should be the query) 
-    if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery)) {
+    if (!nsContentUtils::GetNodeTextContent(queryContent, false, sqlQuery, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsresult rv = mStorageConnection->CreateStatement(NS_ConvertUTF16toUTF8(sqlQuery),
                                                               getter_AddRefs(statement));
     if (NS_FAILED(rv)) {
         nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_STORAGE_BAD_QUERY);
         return rv;
@@ -303,17 +303,17 @@ nsXULTemplateQueryProcessorStorage::Comp
 
     uint32_t parameterCount = 0;
     for (nsIContent* child = queryContent->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
 
         if (child->NodeInfo()->Equals(nsGkAtoms::param, kNameSpaceID_XUL)) {
             nsAutoString value;
-            if (!nsContentUtils::GetNodeTextContent(child, false, value)) {
+            if (!nsContentUtils::GetNodeTextContent(child, false, value, fallible)) {
               return NS_ERROR_OUT_OF_MEMORY;
             }
 
             uint32_t index = parameterCount;
             nsAutoString name, indexValue;
 
             if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
                 rv = statement->GetParameterIndex(NS_ConvertUTF16toUTF8(name),
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -576,31 +576,28 @@ nsRubyBaseContainerFrame::ReflowOneColum
 
   const uint32_t rtcCount = aReflowState.mTextContainers.Length();
   MOZ_ASSERT(aColumn.mTextFrames.Length() == rtcCount);
   MOZ_ASSERT(textReflowStates.Length() == rtcCount);
   nscoord columnISize = 0;
 
   nsAutoString baseText;
   if (aColumn.mBaseFrame) {
-    if (!nsContentUtils::GetNodeTextContent(aColumn.mBaseFrame->GetContent(),
-                                            true, baseText)) {
-      NS_RUNTIMEABORT("OOM");
-    }
+    nsContentUtils::GetNodeTextContent(aColumn.mBaseFrame->GetContent(),
+                                       true, baseText);
   }
 
   // Reflow text frames
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsRubyTextFrame* textFrame = aColumn.mTextFrames[i];
     if (textFrame) {
       nsAutoString annotationText;
-      if (!nsContentUtils::GetNodeTextContent(textFrame->GetContent(),
-                                              true, annotationText)) {
-        NS_RUNTIMEABORT("OOM");
-      }
+      nsContentUtils::GetNodeTextContent(textFrame->GetContent(),
+                                         true, annotationText);
+
       // Per CSS Ruby spec, the content comparison for auto-hiding
       // takes place prior to white spaces collapsing (white-space)
       // and text transformation (text-transform), and ignores elements
       // (considers only the textContent of the boxes). Which means
       // using the content tree text comparison is correct.
       if (annotationText.Equals(baseText)) {
         textFrame->AddStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE);
       } else {
--- a/layout/mathml/nsMathMLTokenFrame.cpp
+++ b/layout/mathml/nsMathMLTokenFrame.cpp
@@ -72,19 +72,17 @@ nsMathMLTokenFrame::MarkTextFramesAsToke
         childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
         child = childFrame2;
         childCount++;
       }
     }
   }
   if (mContent->IsMathMLElement(nsGkAtoms::mi_) && childCount == 1) {
     nsAutoString data;
-    if (!nsContentUtils::GetNodeTextContent(mContent, false, data)) {
-      NS_RUNTIMEABORT("OOM");
-    }
+    nsContentUtils::GetNodeTextContent(mContent, false, data);
 
     data.CompressWhitespace();
     int32_t length = data.Length();
 
     bool isSingleCharacter = length == 1 ||
       (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
 
     if (isSingleCharacter) {
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -110,19 +110,17 @@ nsMathMLmoFrame::BuildDisplayList(nsDisp
 
 // get the text that we enclose and setup our nsMathMLChar
 void
 nsMathMLmoFrame::ProcessTextData()
 {
   mFlags = 0;
 
   nsAutoString data;
-  if (!nsContentUtils::GetNodeTextContent(mContent, false, data)) {
-    NS_RUNTIMEABORT("OOM");
-  }
+  nsContentUtils::GetNodeTextContent(mContent, false, data);
 
   data.CompressWhitespace();
   int32_t length = data.Length();
   char16_t ch = (length == 0) ? char16_t('\0') : data[0];
 
   if ((length == 1) && 
       (ch == kApplyFunction  ||
        ch == kInvisibleSeparator ||