Bug 962443. Make layout frame tree dumping code work better for Fennec and b2g. r=mats
authorTimothy Nikkel <tnikkel@gmail.com>
Sun, 26 Jan 2014 16:07:02 -0600
changeset 181281 bafd46bb640c94a89b55cb716adaf7cd442c7a78
parent 181280 d25dbecf3769d8df80fdb247c041ada00af1c02e
child 181282 b7f02d5459888e5c1d8c7c958c591f5e5e8fb1d5
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs962443
milestone29.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 962443. Make layout frame tree dumping code work better for Fennec and b2g. r=mats
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsFloatManager.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrameList.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/generic/nsLineBox.cpp
layout/generic/nsLineBox.h
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsPlaceholderFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/generic/nsTextFrame.cpp
layout/generic/nsTextFrame.h
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -323,69 +323,70 @@ NS_QUERYFRAME_TAIL_INHERITING(nsBlockFra
 nsSplittableType
 nsBlockFrame::GetSplittableType() const
 {
   return NS_FRAME_SPLITTABLE_NON_RECTANGULAR;
 }
 
 #ifdef DEBUG_FRAME_DUMP
 void
-nsBlockFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
-{
-  ListGeneric(out, aIndent, aFlags);
-
-  fputs("<\n", out);
-
-  aIndent++;
+nsBlockFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
+{
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
+
+  fprintf_stderr(out, "%s<\n", str.get());
+
+  nsCString pfx(aPrefix);
+  pfx += "  ";
 
   // Output the lines
   if (!mLines.empty()) {
     const_line_iterator line = begin_lines(), line_end = end_lines();
     for ( ; line != line_end; ++line) {
-      line->List(out, aIndent, aFlags);
+      line->List(out, pfx.get(), aFlags);
     }
   }
 
   // Output the overflow lines.
   const FrameLines* overflowLines = GetOverflowLines();
   if (overflowLines && !overflowLines->mLines.empty()) {
-    IndentBy(out, aIndent);
-    fprintf(out, "Overflow-lines %p/%p <\n", overflowLines, &overflowLines->mFrames);
+    fprintf_stderr(out, "%sOverflow-lines %p/%p <\n", pfx.get(), overflowLines, &overflowLines->mFrames);
+    nsCString nestedPfx(pfx);
+    nestedPfx += "  ";
     const_line_iterator line = overflowLines->mLines.begin(),
                         line_end = overflowLines->mLines.end();
     for ( ; line != line_end; ++line) {
-      line->List(out, aIndent + 1, aFlags);
-    }
-    IndentBy(out, aIndent);
-    fputs(">\n", out);
+      line->List(out, nestedPfx.get(), aFlags);
+    }
+    fprintf_stderr(out, "%s>\n", pfx.get());
   }
 
   // skip the principal list - we printed the lines above
   // skip the overflow list - we printed the overflow lines above
   ChildListIterator lists(this);
   ChildListIDs skip(kPrincipalList | kOverflowList);
   for (; !lists.IsDone(); lists.Next()) {
     if (skip.Contains(lists.CurrentID())) {
       continue;
     }
-    IndentBy(out, aIndent);
-    fprintf(out, "%s %p <\n", mozilla::layout::ChildListName(lists.CurrentID()),
-            &GetChildList(lists.CurrentID()));
+    fprintf_stderr(out, "%s%s %p <\n", pfx.get(),
+      mozilla::layout::ChildListName(lists.CurrentID()),
+      &GetChildList(lists.CurrentID()));
+    nsCString nestedPfx(pfx);
+    nestedPfx += "  ";
     nsFrameList::Enumerator childFrames(lists.CurrentList());
     for (; !childFrames.AtEnd(); childFrames.Next()) {
       nsIFrame* kid = childFrames.get();
-      kid->List(out, aIndent + 1, aFlags);
-    }
-    IndentBy(out, aIndent);
-    fputs(">\n", out);
-  }
-
-  aIndent--;
-  IndentBy(out, aIndent);
-  fputs(">\n", out);
+      kid->List(out, nestedPfx.get(), aFlags);
+    }
+    fprintf_stderr(out, "%s>\n", pfx.get());
+  }
+
+  fprintf_stderr(out, "%s>\n", aPrefix);
 }
 
 NS_IMETHODIMP
 nsBlockFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Block"), aResult);
 }
 #endif
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -167,17 +167,17 @@ public:
              ~(nsIFrame::eCanContainOverflowContainers |
                nsIFrame::eBlockFrame));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 #ifdef DEBUG
   NS_IMETHOD_(nsFrameState) GetDebugStateBits() const MOZ_OVERRIDE;
 #endif
 
 #ifdef ACCESSIBILITY
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -24,16 +24,17 @@
 #include "nsError.h"
 #include "nsDisplayList.h"
 #include "nsIBaseWindow.h"
 #include "nsBoxLayoutState.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsBlockFrame.h"
 #include "mozilla/AutoRestore.h"
 #include "nsIFrameInlines.h"
+#include "nsPrintfCString.h"
 #include <algorithm>
 
 #ifdef DEBUG
 #undef NOISY
 #else
 #undef NOISY
 #endif
 
@@ -1816,47 +1817,50 @@ nsOverflowContinuationTracker::EndFinish
   }
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Debugging
 
 #ifdef DEBUG_FRAME_DUMP
 void
-nsContainerFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
+nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
 {
-  ListGeneric(out, aIndent, aFlags);
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
 
   // Output the children
   bool outputOneList = false;
   ChildListIterator lists(this);
   for (; !lists.IsDone(); lists.Next()) {
     if (outputOneList) {
-      IndentBy(out, aIndent);
+      str += aPrefix;
     }
     if (lists.CurrentID() != kPrincipalList) {
       if (!outputOneList) {
-        fputs("\n", out);
-        IndentBy(out, aIndent);
+        str += "\n";
+        str += aPrefix;
       }
-      fputs(mozilla::layout::ChildListName(lists.CurrentID()), out);
-      fprintf(out, " %p ", &GetChildList(lists.CurrentID()));
+      str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
+                             &GetChildList(lists.CurrentID()));
     }
-    fputs("<\n", out);
+    fprintf_stderr(out, "%s<\n", str.get());
+    str = "";
     nsFrameList::Enumerator childFrames(lists.CurrentList());
     for (; !childFrames.AtEnd(); childFrames.Next()) {
       nsIFrame* kid = childFrames.get();
       // Verify the child frame's parent frame pointer is correct
       NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
 
       // Have the child frame list
-      kid->List(out, aIndent + 1, aFlags);
+      nsCString pfx(aPrefix);
+      pfx += "  ";
+      kid->List(out, pfx.get(), aFlags);
     }
-    IndentBy(out, aIndent);
-    fputs(">\n", out);
+    fprintf_stderr(out, "%s>\n", aPrefix);
     outputOneList = true;
   }
 
   if (!outputOneList) {
-    fputs("<>\n", out);
+    fprintf_stderr(out, "%s<>\n", str.get());
   }
 }
 #endif
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -71,17 +71,17 @@ public:
   virtual void ChildIsDirty(nsIFrame* aChild) MOZ_OVERRIDE;
 
   virtual bool IsLeaf() const MOZ_OVERRIDE;
   virtual bool PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE;
   virtual bool PeekOffsetCharacter(bool aForward, int32_t* aOffset,
                                      bool aRespectClusters = true) MOZ_OVERRIDE;
   
 #ifdef DEBUG_FRAME_DUMP
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
 #endif  
 
   // nsContainerFrame methods
 
   /**
    * Helper method to create next-in-flows if necessary. If aFrame
    * already has a next-in-flow then this method does
    * nothing. Otherwise, a new continuation frame is created and
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -426,20 +426,20 @@ DebugListFloatManager(const nsFloatManag
 nsresult
 nsFloatManager::List(FILE* out) const
 {
   if (!HasAnyFloats())
     return NS_OK;
 
   for (uint32_t i = 0; i < mFloats.Length(); ++i) {
     const FloatInfo &fi = mFloats[i];
-    printf("Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
-           i, static_cast<void*>(fi.mFrame),
-           fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
-           fi.mLeftYMost, fi.mRightYMost);
+    fprintf_stderr(out, "Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
+                   i, static_cast<void*>(fi.mFrame),
+                   fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
+                   fi.mLeftYMost, fi.mRightYMost);
   }
   return NS_OK;
 }
 #endif
 
 nscoord
 nsFloatManager::ClearFloats(nscoord aY, uint8_t aBreakType,
                             uint32_t aFlags) const
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -79,16 +79,17 @@
 #include "nsIFrameInlines.h"
 #include "nsEventListenerManager.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/gfx/Tools.h"
+#include "nsPrintfCString.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 
 // Struct containing cached metrics for box-wrapped frames.
@@ -5260,100 +5261,115 @@ int32_t nsFrame::ContentIndexInContainer
 }
 
 /**
  * List a frame tree to stdout. Meant to be called from gdb.
  */
 void
 DebugListFrameTree(nsIFrame* aFrame)
 {
-  ((nsFrame*)aFrame)->List(stdout, 0);
-}
-
+  ((nsFrame*)aFrame)->List(stdout);
+}
+
+void
+nsIFrame::ListTag(nsACString& aTo) const
+{
+  ListTag(aTo, this);
+}
+
+/* static */
+void
+nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
+  nsAutoString tmp;
+  aFrame->GetFrameName(tmp);
+  aTo += NS_ConvertUTF16toUTF8(tmp).get();
+  aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
+}
 
 // Debugging
 void
-nsIFrame::ListGeneric(FILE* out, int32_t aIndent, uint32_t aFlags) const
-{
-  IndentBy(out, aIndent);
-  ListTag(out);
+nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
+{
+  aTo =+ aPrefix;
+  ListTag(aTo);
   if (HasView()) {
-    fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
+    aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
   }
   if (GetNextSibling()) {
-    fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
+    aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
   }
   if (GetPrevContinuation()) {
     bool fluid = GetPrevInFlow() == GetPrevContinuation();
-    fprintf(out, " prev-%s=%p", fluid?"in-flow":"continuation",
+    aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
             static_cast<void*>(GetPrevContinuation()));
   }
   if (GetNextContinuation()) {
     bool fluid = GetNextInFlow() == GetNextContinuation();
-    fprintf(out, " next-%s=%p", fluid?"in-flow":"continuation",
+    aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
             static_cast<void*>(GetNextContinuation()));
   }
   void* IBsibling = Properties().Get(IBSplitSpecialSibling());
   if (IBsibling) {
-    fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
+    aTo += nsPrintfCString(" IBSplitSpecialSibling=%p", IBsibling);
   }
   void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
   if (IBprevsibling) {
-    fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
-  }
-  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
+    aTo += nsPrintfCString(" IBSplitSpecialPrevSibling=%p", IBprevsibling);
+  }
+  aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   nsIFrame* f = const_cast<nsIFrame*>(this);
   if (f->HasOverflowAreas()) {
     nsRect vo = f->GetVisualOverflowRect();
     if (!vo.IsEqualEdges(mRect)) {
-      fprintf(out, " vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
+      aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
     }
     nsRect so = f->GetScrollableOverflowRect();
     if (!so.IsEqualEdges(mRect)) {
-      fprintf(out, " scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
+      aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
     }
   }
   if (0 != mState) {
-    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
+    aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
   }
   if (IsTransformed()) {
-    fprintf(out, " transformed");
+    aTo += nsPrintfCString(" transformed");
   }
   if (ChildrenHavePerspective()) {
-    fprintf(out, " perspective");
+    aTo += nsPrintfCString(" perspective");
   }
   if (Preserves3DChildren()) {
-    fprintf(out, " preserves-3d-children");
+    aTo += nsPrintfCString(" preserves-3d-children");
   }
   if (Preserves3D()) {
-    fprintf(out, " preserves-3d");
+    aTo += nsPrintfCString(" preserves-3d");
   }
   if (mContent) {
-    fprintf(out, " [content=%p]", static_cast<void*>(mContent));
-  }
-  fprintf(out, " [sc=%p", static_cast<void*>(mStyleContext));
+    aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
+  }
+  aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
   if (mStyleContext) {
     nsIAtom* pseudoTag = mStyleContext->GetPseudo();
     if (pseudoTag) {
       nsAutoString atomString;
       pseudoTag->ToString(atomString);
-      fprintf(out, "%s", NS_LossyConvertUTF16toASCII(atomString).get());
+      aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
     }
     if (mParent && mStyleContext->GetParent() != mParent->StyleContext()) {
-      fprintf(out, ",parent=%p", mStyleContext->GetParent());
-    }
-  }
-  fputs("]", out);
+      aTo += nsPrintfCString(",parent=%p", mStyleContext->GetParent());
+    }
+  }
+  aTo += "]";
 }
 
 void
-nsIFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
-{
-  ListGeneric(out, aIndent, aFlags);
-  fputs("\n", out);
+nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
+{
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
+  fprintf_stderr(out, "%s\n", str.get());
 }
 
 NS_IMETHODIMP
 nsFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
 }
 
@@ -5375,36 +5391,36 @@ nsFrame::MakeFrameName(const nsAString& 
   PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
   AppendASCIItoUTF16(buf, aResult);
   return NS_OK;
 }
 
 void
 nsIFrame::DumpFrameTree()
 {
-  RootFrameList(PresContext(), stdout, 0);
+  RootFrameList(PresContext(), stdout);
 }
 
 void
 nsIFrame::DumpFrameTreeLimited()
 {
-  List(stdout, 0);
+  List(stdout);
 }
 
 void
-nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
+nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
 {
   if (!aPresContext || !out)
     return;
 
   nsIPresShell *shell = aPresContext->GetPresShell();
   if (shell) {
     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
     if(frame) {
-      frame->List(out, aIndent);
+      frame->List(out, aPrefix);
     }
   }
 }
 #endif
 
 #ifdef DEBUG
 NS_IMETHODIMP_(nsFrameState)
 nsFrame::GetDebugStateBits() const
--- a/layout/generic/nsFrameList.cpp
+++ b/layout/generic/nsFrameList.cpp
@@ -330,22 +330,22 @@ nsFrameList::UnhookFrameFromSiblings(nsI
   prevSibling->SetNextSibling(nextSibling);
   MOZ_ASSERT(!aFrame->GetPrevSibling() && !aFrame->GetNextSibling());
 }
 
 #ifdef DEBUG_FRAME_DUMP
 void
 nsFrameList::List(FILE* out) const
 {
-  fputs("<\n", out);
+  fprintf_stderr(out, "<\n");
   for (nsIFrame* frame = mFirstChild; frame;
        frame = frame->GetNextSibling()) {
-    frame->List(out, 1);
+    frame->List(out, "  ");
   }
-  fputs(">\n", out);
+  fprintf_stderr(out, ">\n");
 }
 #endif
 
 #ifdef IBMBIDI
 nsIFrame*
 nsFrameList::GetPrevVisualFor(nsIFrame* aFrame) const
 {
   if (!mFirstChild)
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3247,32 +3247,33 @@ private:
 public:
   static void IndentBy(FILE* out, int32_t aIndent) {
     while (--aIndent >= 0) fputs("  ", out);
   }
   void ListTag(FILE* out) const {
     ListTag(out, this);
   }
   static void ListTag(FILE* out, const nsIFrame* aFrame) {
-    nsAutoString tmp;
-    aFrame->GetFrameName(tmp);
-    fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
-    fprintf(out, "@%p", static_cast<const void*>(aFrame));
+    nsAutoCString t;
+    ListTag(t, aFrame);
+    fputs(t.get(), out);
   }
-  void ListGeneric(FILE* out, int32_t aIndent, uint32_t aFlags) const;
+  void ListTag(nsACString& aTo) const;
+  static void ListTag(nsACString& aTo, const nsIFrame* aFrame);
+  void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const;
   enum {
     TRAVERSE_SUBDOCUMENT_FRAMES = 0x01
   };
-  virtual void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
+  virtual void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
   /**
    * lists the frames beginning from the root frame
    * - calls root frame's List(...)
    */
   static void RootFrameList(nsPresContext* aPresContext,
-                            FILE* out, int32_t aIndent);
+                            FILE* out = stderr, const char* aPrefix = "");
   virtual void DumpFrameTree();
   void DumpFrameTreeLimited();
 
   NS_IMETHOD  GetFrameName(nsAString& aResult) const = 0;
 #endif
 
 #ifdef DEBUG
 public:
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1748,35 +1748,36 @@ nsImageFrame::GetType() const
 #ifdef DEBUG_FRAME_DUMP
 NS_IMETHODIMP
 nsImageFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("ImageFrame"), aResult);
 }
 
 void
-nsImageFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
+nsImageFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
 {
-  ListGeneric(out, aIndent, aFlags);
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
 
   // output the img src url
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (imageLoader) {
     nsCOMPtr<imgIRequest> currentRequest;
     imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                             getter_AddRefs(currentRequest));
     if (currentRequest) {
       nsCOMPtr<nsIURI> uri;
       currentRequest->GetURI(getter_AddRefs(uri));
       nsAutoCString uristr;
       uri->GetAsciiSpec(uristr);
-      fprintf(out, " [src=%s]", uristr.get());
+      str += nsPrintfCString(" [src=%s]", uristr.get());
     }
   }
-  fputs("\n", out);
+  fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 int
 nsImageFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
 {
   int skip = 0;
   if (nullptr != GetPrevInFlow()) {
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -108,17 +108,17 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const
   {
     return ImageFrameSuper::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   NS_IMETHOD GetFrameName(nsAString& aResult) const;
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
 #endif
 
   virtual int GetSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE;
 
   nsresult GetIntrinsicImageSize(nsSize& aSize);
 
   static void ReleaseGlobals() {
     if (gIconLoad) {
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -11,16 +11,17 @@
 #include "nsFrame.h"
 #include "nsPresArena.h"
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif
 #include "nsIFrameInlines.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Likely.h"
+#include "nsPrintfCString.h"
 
 #ifdef DEBUG
 static int32_t ctorCount;
 int32_t nsLineBox::GetCtorCount() { return ctorCount; }
 #endif
 
 #ifndef _MSC_VER
 // static nsLineBox constant; initialized in the header file.
@@ -164,32 +165,32 @@ nsLineBox::Cleanup()
       delete mInlineData;
     }
     mData = nullptr;
   }
 }
 
 #ifdef DEBUG_FRAME_DUMP
 static void
-ListFloats(FILE* out, int32_t aIndent, const nsFloatCacheList& aFloats)
+ListFloats(FILE* out, const char* aPrefix, const nsFloatCacheList& aFloats)
 {
   nsFloatCache* fc = aFloats.Head();
   while (fc) {
-    nsFrame::IndentBy(out, aIndent);
+    nsCString str(aPrefix);
     nsIFrame* frame = fc->mFloat;
-    fprintf(out, "floatframe@%p ", static_cast<void*>(frame));
+    str += nsPrintfCString("floatframe@%p ", static_cast<void*>(frame));
     if (frame) {
       nsAutoString frameName;
       frame->GetFrameName(frameName);
-      fputs(NS_LossyConvertUTF16toASCII(frameName).get(), out);
+      str += NS_ConvertUTF16toUTF8(frameName).get();
     }
     else {
-      fputs("\n###!!! NULL out-of-flow frame", out);
+      str += "\n###!!! NULL out-of-flow frame";
     }
-    fprintf(out, "\n");
+    fprintf_stderr(out, "%s\n", str.get());
     fc = fc->Next();
   }
 }
 
 const char *
 BreakTypeToString(uint8_t aBreakType)
 {
   switch (aBreakType) {
@@ -217,55 +218,65 @@ nsLineBox::StateToString(char* aBuf, int
               BreakTypeToString(GetBreakTypeAfter()),
               mAllFlags);
   return aBuf;
 }
 
 void
 nsLineBox::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
 {
-  nsFrame::IndentBy(out, aIndent);
+  nsCString str;
+  while (aIndent-- > 0) {
+    str += "  ";
+  }
+  List(out, str.get(), aFlags);
+}
+
+void
+nsLineBox::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
+{
+  nsCString str(aPrefix);
   char cbuf[100];
-  fprintf(out, "line %p: count=%d state=%s ",
+  str += nsPrintfCString("line %p: count=%d state=%s ",
           static_cast<const void*>(this), GetChildCount(),
           StateToString(cbuf, sizeof(cbuf)));
   if (IsBlock() && !GetCarriedOutBottomMargin().IsZero()) {
-    fprintf(out, "bm=%d ", GetCarriedOutBottomMargin().get());
+    str += nsPrintfCString("bm=%d ", GetCarriedOutBottomMargin().get());
   }
-  fprintf(out, "{%d,%d,%d,%d} ",
+  str += nsPrintfCString("{%d,%d,%d,%d} ",
           mBounds.x, mBounds.y, mBounds.width, mBounds.height);
   if (mData &&
       (!mData->mOverflowAreas.VisualOverflow().IsEqualEdges(mBounds) ||
        !mData->mOverflowAreas.ScrollableOverflow().IsEqualEdges(mBounds))) {
-    fprintf(out, "vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ",
+    str += nsPrintfCString("vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ",
             mData->mOverflowAreas.VisualOverflow().x,
             mData->mOverflowAreas.VisualOverflow().y,
             mData->mOverflowAreas.VisualOverflow().width,
             mData->mOverflowAreas.VisualOverflow().height,
             mData->mOverflowAreas.ScrollableOverflow().x,
             mData->mOverflowAreas.ScrollableOverflow().y,
             mData->mOverflowAreas.ScrollableOverflow().width,
             mData->mOverflowAreas.ScrollableOverflow().height);
   }
-  fprintf(out, "<\n");
+  fprintf_stderr(out, "%s<\n", str.get());
 
   nsIFrame* frame = mFirstChild;
   int32_t n = GetChildCount();
+  nsCString pfx(aPrefix);
+  pfx += "  ";
   while (--n >= 0) {
-    frame->List(out, aIndent + 1, aFlags);
+    frame->List(out, pfx.get(), aFlags);
     frame = frame->GetNextSibling();
   }
 
   if (HasFloats()) {
-    nsFrame::IndentBy(out, aIndent);
-    fputs("> floats <\n", out);
-    ListFloats(out, aIndent + 1, mInlineData->mFloats);
+    fprintf_stderr(out, "%s> floats <\n", aPrefix);
+    ListFloats(out, pfx.get(), mInlineData->mFloats);
   }
-  nsFrame::IndentBy(out, aIndent);
-  fputs(">\n", out);
+  fprintf_stderr(out, "%s>\n", aPrefix);
 }
 #endif
 
 #ifdef DEBUG
 nsIFrame*
 nsLineBox::LastChild() const
 {
   nsIFrame* frame = mFirstChild;
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -495,16 +495,17 @@ public:
                                     nsLineList_iterator& aEnd,
                                     nsIFrame* aLastFrameBeforeEnd,
                                     int32_t* aFrameIndexInLine);
 
 #ifdef DEBUG_FRAME_DUMP
   char* StateToString(char* aBuf, int32_t aBufSize) const;
 
   void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
   nsIFrame* LastChild() const;
 #endif
 
 private:
   int32_t IndexOf(nsIFrame* aFrame) const;
 public:
 
   bool Contains(nsIFrame* aFrame) const {
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -232,19 +232,20 @@ nsPlaceholderFrame::BuildDisplayList(nsD
 #ifdef DEBUG_FRAME_DUMP
 NS_IMETHODIMP
 nsPlaceholderFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Placeholder"), aResult);
 }
 
 void
-nsPlaceholderFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
+nsPlaceholderFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
 {
-  ListGeneric(out, aIndent, aFlags);
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
 
   if (mOutOfFlowFrame) {
-    fprintf(out, " outOfFlowFrame=");
-    nsFrame::ListTag(out, mOutOfFlowFrame);
+    str += " outOfFlowFrame=";
+    nsFrame::ListTag(str, mOutOfFlowFrame);
   }
-  fputs("\n", out);
+  fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
--- a/layout/generic/nsPlaceholderFrame.h
+++ b/layout/generic/nsPlaceholderFrame.h
@@ -107,17 +107,17 @@ public:
 
 #if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF))
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 #endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF)
   
 #ifdef DEBUG_FRAME_DUMP
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif // DEBUG
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::placeholderFrame
    */
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -523,26 +523,29 @@ nsSubDocumentFrame::GetIntrinsicHeight()
                "Intrinsic height should come from the embedded document.");
 
   // Use 150px, for compatibility with IE, and per CSS2.1 draft.
   return nsPresContext::CSSPixelsToAppUnits(150);
 }
 
 #ifdef DEBUG_FRAME_DUMP
 void
-nsSubDocumentFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
+nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
 {
-  ListGeneric(out, aIndent, aFlags);
-  fputs("\n", out);
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
+  fprintf_stderr(out, "%s\n", str.get());
 
-  nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
   if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
+    nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
     nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
     if (subdocRootFrame) {
-      subdocRootFrame->List(out, aIndent + 1);
+      nsCString pfx(aPrefix);
+      pfx += "  ";
+      subdocRootFrame->List(out, pfx.get(), aFlags);
     }
   }
 }
 
 NS_IMETHODIMP nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
 }
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -19,17 +19,17 @@ class nsSubDocumentFrame : public nsLeaf
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSubDocumentFrame)
   NS_DECL_FRAMEARENA_HELPERS
 
   nsSubDocumentFrame(nsStyleContext* aContext);
 
 #ifdef DEBUG_FRAME_DUMP
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
   NS_DECL_QUERYFRAME
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8498,31 +8498,32 @@ nsTextFrame::GetFrameName(nsAString& aRe
   nsAutoCString tmp;
   ToCString(tmp, &totalContentLength);
   tmp.SetLength(std::min(tmp.Length(), 50u));
   aResult += NS_LITERAL_STRING("\"") + NS_ConvertASCIItoUTF16(tmp) + NS_LITERAL_STRING("\"");
   return NS_OK;
 }
 
 void
-nsTextFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
-{
-  ListGeneric(out, aIndent, aFlags);
-
-  fprintf(out, " [run=%p]", static_cast<void*>(mTextRun));
+nsTextFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
+{
+  nsCString str;
+  ListGeneric(str, aPrefix, aFlags);
+
+  str += nsPrintfCString(" [run=%p]", static_cast<void*>(mTextRun));
 
   // Output the first/last content offset and prev/next in flow info
   bool isComplete = uint32_t(GetContentEnd()) == GetContent()->TextLength();
-  fprintf(out, "[%d,%d,%c] ", GetContentOffset(), GetContentLength(),
+  str += nsPrintfCString("[%d,%d,%c] ", GetContentOffset(), GetContentLength(),
           isComplete ? 'T':'F');
   
   if (IsSelected()) {
-    fprintf(out, " SELECTED");
-  }
-  fputs("\n", out);
+    str += " SELECTED";
+  }
+  fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 #ifdef DEBUG
 NS_IMETHODIMP_(nsFrameState)
 nsTextFrame::GetDebugStateBits() const
 {
   // mask out our emptystate flags; those are just caches
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -120,17 +120,17 @@ public:
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced |
                                              nsIFrame::eLineParticipant));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
-  void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
+  void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
   void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const;
 #endif
 
 #ifdef DEBUG
   NS_IMETHOD_(nsFrameState) GetDebugStateBits() const MOZ_OVERRIDE;
 #endif