Bug 1113238 - Part 2: Only maintain the pre level status which can be potentially expensive if we may end up using it. r=bzbarsky, a=lmandel
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 12 Jan 2015 11:41:10 -0500
changeset 249609 27b2f1bb01e609f2d06ad2edbc9ea12e8daf31bc
parent 249608 fac2be3ae18f25bc9c9d98e4e0d74e24d0d1add9
child 249610 074e4205c39991a09c021dcd58ae2c9a930af37b
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, lmandel
bugs1113238
milestone37.0a2
Bug 1113238 - Part 2: Only maintain the pre level status which can be potentially expensive if we may end up using it. r=bzbarsky, a=lmandel This patch ensures that we check ShouldMaintainPreLevel() before attempting to modify or read mPreLevel in order to avoid wasting time to compute mPreLevel for elements without frames needlessly. Computing this value for such elements can incur expensive style calculations.
dom/base/nsHTMLContentSerializer.cpp
dom/base/nsXHTMLContentSerializer.cpp
dom/base/nsXMLContentSerializer.cpp
dom/base/nsXMLContentSerializer.h
--- a/dom/base/nsHTMLContentSerializer.cpp
+++ b/dom/base/nsHTMLContentSerializer.cpp
@@ -187,17 +187,17 @@ nsHTMLContentSerializer::AppendElementSt
     return NS_OK;
   }
 
   nsIAtom *name = content->Tag();
   int32_t ns = content->GetNameSpaceID();
 
   bool lineBreakBeforeOpen = LineBreakBeforeOpen(ns, name);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     if (mColPos && lineBreakBeforeOpen) {
       AppendNewLineToString(aStr);
     }
     else {
       MaybeAddNewlineForRootNode(aStr);
     }
     if (!mColPos) {
       AppendIndentation(aStr);
@@ -220,17 +220,17 @@ nsHTMLContentSerializer::AppendElementSt
   
   AppendToString(kLessThan, aStr);
 
   AppendToString(nsDependentAtomString(name), aStr);
 
   MaybeEnterInPreContent(content);
 
   // for block elements, we increase the indentation
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw)
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel())
     IncrIndentation(name);
 
   // Need to keep track of OL and LI elements in order to get ordinal number 
   // for the LI.
   if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML){
     // We are copying and current node is an OL;
     // Store its start attribute value in olState->startVal.
     nsAutoString start;
@@ -275,18 +275,18 @@ nsHTMLContentSerializer::AppendElementSt
   if (ns == kNameSpaceID_XHTML &&
       (name == nsGkAtoms::script ||
        name == nsGkAtoms::style ||
        name == nsGkAtoms::noscript ||
        name == nsGkAtoms::noframes)) {
     ++mDisableEntityEncoding;
   }
 
-  if ((mDoFormat || forceFormat) && !mPreLevel &&
-    !mDoRaw && LineBreakAfterOpen(ns, name)) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel() &&
+    LineBreakAfterOpen(ns, name)) {
     AppendNewLineToString(aStr);
   }
 
   AfterElementStart(content, aOriginalElement, aStr);
 
   return NS_OK;
 }
   
@@ -307,28 +307,28 @@ nsHTMLContentSerializer::AppendElementEn
        name == nsGkAtoms::noscript ||
        name == nsGkAtoms::noframes)) {
     --mDisableEntityEncoding;
   }
 
   bool forceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
                      content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     DecrIndentation(name);
   }
 
   if (name == nsGkAtoms::script) {
     nsCOMPtr<nsIScriptElement> script = do_QueryInterface(aElement);
 
-    if (script && script->IsMalformed()) {
+    if (ShouldMaintainPreLevel() && script && script->IsMalformed()) {
       // We're looking at a malformed script tag. This means that the end tag
       // was missing in the source. Imitate that here by not serializing the end
       // tag.
-      --mPreLevel;
+      --PreLevel();
       return NS_OK;
     }
   }
   else if (mIsCopying && name == nsGkAtoms::ol && ns == kNameSpaceID_XHTML) {
     NS_ASSERTION((!mOLStateStack.IsEmpty()), "Cannot have an empty OL Stack");
     /* Though at this point we must always have an state to be deleted as all 
     the OL opening tags are supposed to push an olState object to the stack*/
     if (!mOLStateStack.IsEmpty()) {
@@ -346,17 +346,17 @@ nsHTMLContentSerializer::AppendElementEn
         IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
                     isContainer);
       if (!isContainer) {
         return NS_OK;
       }
     }
   }
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
 
     bool lineBreakBeforeClose = LineBreakBeforeClose(ns, name);
 
     if (mColPos && lineBreakBeforeClose) {
       AppendNewLineToString(aStr);
     }
     if (!mColPos) {
       AppendIndentation(aStr);
@@ -372,18 +372,18 @@ nsHTMLContentSerializer::AppendElementEn
   }
 
   AppendToString(kEndTag, aStr);
   AppendToString(nsDependentAtomString(name), aStr);
   AppendToString(kGreaterThan, aStr);
 
   MaybeLeaveFromPreContent(content);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel
-      && !mDoRaw && LineBreakAfterClose(ns, name)) {
+  if ((mDoFormat || forceFormat)&& !mDoRaw  && !PreLevel()
+      && LineBreakAfterClose(ns, name)) {
     AppendNewLineToString(aStr);
   }
   else {
     MaybeFlagNewlineForRootNode(aElement);
   }
 
   if (name == nsGkAtoms::body && ns == kNameSpaceID_XHTML) {
     --mInBody;
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -128,17 +128,17 @@ nsXHTMLContentSerializer::AppendText(nsI
 
   nsAutoString data;
   nsresult rv;
 
   rv = AppendTextData(aText, aStartOffset, aEndOffset, data, true);
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToStringConvertLF(data, aStr);
   }
   else if (mDoFormat) {
     AppendToStringFormatedWrapped(data, aStr);
   }
   else if (mDoWrap) {
     AppendToStringWrapped(data, aStr);
   }
@@ -532,18 +532,19 @@ nsXHTMLContentSerializer::CheckElementSt
   // even if we're not in pretty printing mode
   aForceFormat = !(mFlags & nsIDocumentEncoder::OutputIgnoreMozDirty) &&
                  aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdirty);
 
   nsIAtom *name = aContent->Tag();
   int32_t namespaceID = aContent->GetNameSpaceID();
 
   if (namespaceID == kNameSpaceID_XHTML) {
-    if (name == nsGkAtoms::br && mPreLevel > 0 && 
-        (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre)) {
+    if (name == nsGkAtoms::br &&
+        (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre) &&
+        PreLevel() > 0) {
       AppendNewLineToString(aStr);
       return false;
     }
 
     if (name == nsGkAtoms::body) {
       ++mInBody;
     }
   }
@@ -840,54 +841,57 @@ nsXHTMLContentSerializer::LineBreakAfter
 
   return false;
 }
 
 
 void
 nsXHTMLContentSerializer::MaybeEnterInPreContent(nsIContent* aNode)
 {
-
-  if (aNode->GetNameSpaceID() != kNameSpaceID_XHTML) {
+  if (!ShouldMaintainPreLevel() ||
+      aNode->GetNameSpaceID() != kNameSpaceID_XHTML) {
     return;
   }
 
   nsIAtom *name = aNode->Tag();
 
   if (IsElementPreformatted(aNode) ||
       name == nsGkAtoms::script ||
       name == nsGkAtoms::style ||
       name == nsGkAtoms::noscript ||
       name == nsGkAtoms::noframes
       ) {
-    mPreLevel++;
+    PreLevel()++;
   }
 }
 
 void
 nsXHTMLContentSerializer::MaybeLeaveFromPreContent(nsIContent* aNode)
 {
-  if (aNode->GetNameSpaceID() != kNameSpaceID_XHTML) {
+  if (!ShouldMaintainPreLevel() ||
+      aNode->GetNameSpaceID() != kNameSpaceID_XHTML) {
     return;
   }
 
   nsIAtom *name = aNode->Tag();
   if (IsElementPreformatted(aNode) ||
       name == nsGkAtoms::script ||
       name == nsGkAtoms::style ||
       name == nsGkAtoms::noscript ||
       name == nsGkAtoms::noframes
     ) {
-    --mPreLevel;
+    --PreLevel();
   }
 }
 
 bool
 nsXHTMLContentSerializer::IsElementPreformatted(nsIContent* aNode)
 {
+  MOZ_ASSERT(ShouldMaintainPreLevel(), "We should not be calling this needlessly");
+
   if (!aNode->IsElement()) {
     return false;
   }
   nsRefPtr<nsStyleContext> styleContext =
     nsComputedDOMStyle::GetStyleContextForElementNoFlush(aNode->AsElement(),
                                                          nullptr, nullptr);
   if (styleContext) {
     const nsStyleText* textStyle = styleContext->StyleText();
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -182,17 +182,17 @@ nsXMLContentSerializer::AppendText(nsICo
 
   nsAutoString data;
   nsresult rv;
 
   rv = AppendTextData(aText, aStartOffset, aEndOffset, data, true);
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToStringConvertLF(data, aStr);
   }
   else if (mDoFormat) {
     AppendToStringFormatedWrapped(data, aStr);
   }
   else if (mDoWrap) {
     AppendToStringWrapped(data, aStr);
   }
@@ -209,17 +209,17 @@ nsXMLContentSerializer::AppendCDATASecti
                                            int32_t aEndOffset,
                                            nsAString& aStr)
 {
   NS_ENSURE_ARG(aCDATASection);
   nsresult rv;
 
   NS_NAMED_LITERAL_STRING(cdata , "<![CDATA[");
 
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToString(cdata, aStr);
   }
   else if (mDoFormat) {
     AppendToStringFormatedWrapped(cdata, aStr);
   }
   else if (mDoWrap) {
     AppendToStringWrapped(cdata, aStr);
   }
@@ -255,17 +255,17 @@ nsXMLContentSerializer::AppendProcessing
   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
 
   rv = pi->GetData(data);
   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
 
   start.AppendLiteral("<?");
   start.Append(target);
 
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToString(start, aStr);
   }
   else if (mDoFormat) {
     if (mAddSpace) {
       AppendNewLineToString(aStr);
     }
     AppendToStringFormatedWrapped(start, aStr);
   }
@@ -313,17 +313,17 @@ nsXMLContentSerializer::AppendComment(ns
     }
     data.Assign(frag);
   }
 
   MaybeAddNewlineForRootNode(aStr);
 
   NS_NAMED_LITERAL_STRING(startComment, "<!--");
 
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToString(startComment, aStr);
   }
   else if (mDoFormat) {
     if (mAddSpace) {
       AppendNewLineToString(aStr);
     }
     AppendToStringFormatedWrapped(startComment, aStr);
   }
@@ -688,17 +688,17 @@ nsXMLContentSerializer::SerializeAttr(co
                             NS_LITERAL_STRING("&amp;"));
     if (bIncludesDouble && bIncludesSingle) {
       sValue.ReplaceSubstring(NS_LITERAL_STRING("\""),
                               NS_LITERAL_STRING("&quot;"));
     }
     attrString.Append(sValue);
     attrString.Append(cDelimiter);
   }
-  if (mPreLevel > 0 || mDoRaw) {
+  if (mDoRaw || PreLevel() > 0) {
     AppendToStringConvertLF(attrString, aStr);
   }
   else if (mDoFormat) {
     AppendToStringFormatedWrapped(attrString, aStr);
   }
   else if (mDoWrap) {
     AppendToStringWrapped(attrString, aStr);
   }
@@ -893,17 +893,17 @@ nsXMLContentSerializer::AppendElementSta
   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
 
   uint32_t skipAttr = ScanNamespaceDeclarations(content,
                           aOriginalElement, tagNamespaceURI);
 
   nsIAtom *name = content->Tag();
   bool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     if (mColPos && lineBreakBeforeOpen) {
       AppendNewLineToString(aStr);
     }
     else {
       MaybeAddNewlineForRootNode(aStr);
     }
     if (!mColPos) {
       AppendIndentation(aStr);
@@ -934,28 +934,28 @@ nsXMLContentSerializer::AppendElementSta
   if (!tagPrefix.IsEmpty()) {
     AppendToString(tagPrefix, aStr);
     AppendToString(NS_LITERAL_STRING(":"), aStr);
   }
   AppendToString(tagLocalName, aStr);
 
   MaybeEnterInPreContent(content);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     IncrIndentation(name);
   }
 
   SerializeAttributes(content, aOriginalElement, tagPrefix, tagNamespaceURI,
                       name, aStr, skipAttr, addNSAttr);
 
   AppendEndOfElementStart(aOriginalElement, name, content->GetNameSpaceID(),
                           aStr);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel 
-    && !mDoRaw && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
+    && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
     AppendNewLineToString(aStr);
   }
 
   AfterElementStart(content, aOriginalElement, aStr);
 
   return NS_OK;
 }
 
@@ -982,17 +982,17 @@ nsXMLContentSerializer::AppendElementEnd
 
   nsIContent* content = aElement;
 
   bool forceFormat = false, outputElementEnd;
   outputElementEnd = CheckElementEnd(content, forceFormat, aStr);
 
   nsIAtom *name = content->Tag();
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
     DecrIndentation(name);
   }
 
   if (!outputElementEnd) {
     PopNameSpaceDeclsFor(aElement);
     MaybeFlagNewlineForRootNode(aElement);
     return NS_OK;
   }
@@ -1004,17 +1004,17 @@ nsXMLContentSerializer::AppendElementEnd
   aElement->NodeInfo()->GetNamespaceURI(tagNamespaceURI);
 
 #ifdef DEBUG
   bool debugNeedToPushNamespace =
 #endif
   ConfirmPrefix(tagPrefix, tagNamespaceURI, aElement, false);
   NS_ASSERTION(!debugNeedToPushNamespace, "Can't push namespaces in closing tag!");
 
-  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()) {
 
     bool lineBreakBeforeClose = LineBreakBeforeClose(content->GetNameSpaceID(), name);
 
     if (mColPos && lineBreakBeforeClose) {
       AppendNewLineToString(aStr);
     }
     if (!mColPos) {
       AppendIndentation(aStr);
@@ -1036,18 +1036,18 @@ nsXMLContentSerializer::AppendElementEnd
   }
   AppendToString(tagLocalName, aStr);
   AppendToString(kGreaterThan, aStr);
 
   PopNameSpaceDeclsFor(aElement);
 
   MaybeLeaveFromPreContent(content);
 
-  if ((mDoFormat || forceFormat) && !mPreLevel
-      && !mDoRaw && LineBreakAfterClose(content->GetNameSpaceID(), name)) {
+  if ((mDoFormat || forceFormat) && !mDoRaw && !PreLevel()
+      && LineBreakAfterClose(content->GetNameSpaceID(), name)) {
     AppendNewLineToString(aStr);
   }
   else {
     MaybeFlagNewlineForRootNode(aElement);
   }
 
   AfterElementEnd(content, aStr);
 
@@ -1212,33 +1212,35 @@ nsXMLContentSerializer::MaybeFlagNewline
     mAddNewlineForRootNode = parent->IsNodeOfType(nsINode::eDOCUMENT);
   }
 }
 
 void
 nsXMLContentSerializer::MaybeEnterInPreContent(nsIContent* aNode)
 {
   // support of the xml:space attribute
-  if (aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
+  if (ShouldMaintainPreLevel() &&
+      aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
     nsAutoString space;
     aNode->GetAttr(kNameSpaceID_XML, nsGkAtoms::space, space);
     if (space.EqualsLiteral("preserve"))
-      ++mPreLevel;
+      ++PreLevel();
   }
 }
 
 void
 nsXMLContentSerializer::MaybeLeaveFromPreContent(nsIContent* aNode)
 {
   // support of the xml:space attribute
-  if (aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
+  if (ShouldMaintainPreLevel() &&
+      aNode->HasAttr(kNameSpaceID_XML, nsGkAtoms::space)) {
     nsAutoString space;
     aNode->GetAttr(kNameSpaceID_XML, nsGkAtoms::space, space);
     if (space.EqualsLiteral("preserve"))
-      --mPreLevel;
+      --PreLevel();
   }
 }
 
 void
 nsXMLContentSerializer::AppendNewLineToString(nsAString& aStr)
 {
   AppendToString(mLineBreak, aStr);
   mMayIgnoreLineBreakSequence = true;
@@ -1437,17 +1439,17 @@ nsXMLContentSerializer::AppendWrapped_No
   uint32_t length, colPos;
 
   do {
 
     if (mColPos) {
       colPos = mColPos;
     }
     else {
-      if (mDoFormat && !mPreLevel && !onceAgainBecauseWeAddedBreakInFront) {
+      if (mDoFormat && !mDoRaw && !PreLevel() && !onceAgainBecauseWeAddedBreakInFront) {
         colPos = mIndent.Length();
       }
       else
         colPos = 0;
     }
     foundWhitespaceInLoop = false;
     length = 0;
     // we iterate until the next whitespace character
@@ -1706,8 +1708,15 @@ nsXMLContentSerializer::AppendToStringWr
       AppendWrapped_WhitespaceSequence(pos, end, sequenceStart, aOutputStr);
     }
     else { // any other non-whitespace char
       AppendWrapped_NonWhitespaceSequence(pos, end, sequenceStart,
         mayIgnoreStartOfLineWhitespaceSequence, sequenceStartAfterAWhitespace, aOutputStr);
     }
   }
 }
+
+bool
+nsXMLContentSerializer::ShouldMaintainPreLevel() const
+{
+  // Only attempt to maintain the pre level for consumers who care about it.
+  return !mDoRaw || (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre);
+}
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -289,16 +289,26 @@ class nsXMLContentSerializer : public ns
   // the root of a document. See mAddNewlineForRootNode
   void MaybeAddNewlineForRootNode(nsAString& aStr);
   void MaybeFlagNewlineForRootNode(nsINode* aNode);
 
   // Functions to check if we enter in or leave from a preformated content
   virtual void MaybeEnterInPreContent(nsIContent* aNode);
   virtual void MaybeLeaveFromPreContent(nsIContent* aNode);
 
+  bool ShouldMaintainPreLevel() const;
+  int32_t PreLevel() const {
+    MOZ_ASSERT(ShouldMaintainPreLevel());
+    return mPreLevel;
+  }
+  int32_t& PreLevel() {
+    MOZ_ASSERT(ShouldMaintainPreLevel());
+    return mPreLevel;
+  }
+
   int32_t mPrefixIndex;
 
   struct NameSpaceDecl {
     nsString mPrefix;
     nsString mURI;
     nsIContent* mOwner;
   };
 
@@ -356,16 +366,17 @@ class nsXMLContentSerializer : public ns
   // says that if the next string to add contains a newline character at the
   // begining, then this newline character should be ignored, because a
   // such character has already been added into the output string
   bool          mMayIgnoreLineBreakSequence;
 
   bool          mBodyOnly;
   int32_t       mInBody;
 
+private:
   // number of nested elements which have preformated content
   int32_t       mPreLevel;
 };
 
 nsresult
 NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);
 
 #endif