Bug 1113238 - Part 2: Only maintain the pre level status which can be potentially expensive if we may end up using it; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 12 Jan 2015 11:41:10 -0500
changeset 253102 139457679fc77c4cf7fc4b34686f0c77036caf57
parent 253101 183898a49db1cb21949510481a4a35da2f81a2e0
child 253103 f3df1027b8b246f695872fffa737e7b8b463cd50
push id721
push userjlund@mozilla.com
push dateTue, 21 Apr 2015 23:03:33 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1113238
milestone38.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 1113238 - Part 2: Only maintain the pre level status which can be potentially expensive if we may end up using it; r=bzbarsky 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