Bug 960899 - Add debug function and lldb command to print frame state symbolically. r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Sat, 18 Jan 2014 18:08:22 +1100
changeset 164128 1f72556326bedd015ed0c411ba1697b069b289be
parent 164127 8600c8ad593f1876d399f74de0b2f78e9365a7ff
child 164129 334a63e35b745f724b9d5f89316966a38d536dd4
push id26026
push userphilringnalda@gmail.com
push dateSat, 18 Jan 2014 23:17:27 +0000
treeherdermozilla-central@61fd0f987cf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs960899
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 960899 - Add debug function and lldb command to print frame state symbolically. r=dbaron
layout/generic/moz.build
layout/generic/nsBulletFrame.cpp
layout/generic/nsBulletFrame.h
layout/generic/nsFrameState.cpp
layout/generic/nsFrameState.h
layout/generic/nsFrameStateBits.h
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsPlaceholderFrame.h
layout/xul/nsBoxFrame.cpp
layout/xul/nsBoxFrame.h
python/lldbutils/README.txt
python/lldbutils/lldbutils/layout.py
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -58,16 +58,17 @@ UNIFIED_SOURCES += [
     'nsContainerFrame.cpp',
     'nsFirstLetterFrame.cpp',
     'nsFlexContainerFrame.cpp',
     'nsFloatManager.cpp',
     'nsFontInflationData.cpp',
     'nsFrame.cpp',
     'nsFrameList.cpp',
     'nsFrameSetFrame.cpp',
+    'nsFrameState.cpp',
     'nsFrameUtil.cpp',
     'nsGfxScrollFrame.cpp',
     'nsHTMLCanvasFrame.cpp',
     'nsHTMLReflowMetrics.cpp',
     'nsHTMLReflowState.cpp',
     'nsImageFrame.cpp',
     'nsImageMap.cpp',
     'nsInlineFrame.cpp',
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -30,16 +30,22 @@
 #endif
 
 using namespace mozilla;
 
 NS_DECLARE_FRAME_PROPERTY(FontSizeInflationProperty, nullptr)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsBulletFrame)
 
+#ifdef DEBUG
+NS_QUERYFRAME_HEAD(nsBulletFrame)
+  NS_QUERYFRAME_ENTRY(nsBulletFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
+#endif
+
 nsBulletFrame::~nsBulletFrame()
 {
 }
 
 void
 nsBulletFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   // Stop image loading first
--- a/layout/generic/nsBulletFrame.h
+++ b/layout/generic/nsBulletFrame.h
@@ -35,16 +35,20 @@ private:
 
 /**
  * A simple class that manages the layout and rendering of html bullets.
  * This class also supports the CSS list-style properties.
  */
 class nsBulletFrame : public nsFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
+#ifdef DEBUG
+  NS_DECL_QUERYFRAME_TARGET(nsBulletFrame)
+  NS_DECL_QUERYFRAME
+#endif
 
   nsBulletFrame(nsStyleContext* aContext)
     : nsFrame(aContext)
   {
   }
   virtual ~nsBulletFrame();
 
   NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsFrameState.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* constants for frame state bits and a type to store them in a uint64_t */
+
+#include "nsFrameState.h"
+
+#include "nsBlockFrame.h"
+#include "nsBoxFrame.h"
+#include "nsBulletFrame.h"
+#include "nsGfxScrollFrame.h"
+#include "nsIFrame.h"
+#include "nsISVGChildFrame.h"
+#include "nsImageFrame.h"
+#include "nsInlineFrame.h"
+#include "nsPlaceholderFrame.h"
+#include "nsSVGContainerFrame.h"
+#include "nsTableCellFrame.h"
+#include "nsTableRowFrame.h"
+#include "nsTableRowGroupFrame.h"
+#include "nsTextFrame.h"
+
+namespace mozilla {
+
+#ifdef DEBUG
+nsCString
+GetFrameState(nsIFrame* aFrame)
+{
+  nsCString result;
+  nsAutoTArray<const char*,3> groups;
+
+  nsFrameState state = aFrame->GetStateBits();
+
+  if (state == nsFrameState(0)) {
+    result.AssignLiteral("0");
+    return result;
+  }
+
+#define FRAME_STATE_GROUP(name_, class_)                                      \
+  {                                                                           \
+    class_* frame = do_QueryFrame(aFrame);                                    \
+    if (frame && (groups.IsEmpty() || strcmp(groups.LastElement(), #name_))) {\
+      groups.AppendElement(#name_);                                           \
+    }                                                                         \
+  }
+#define FRAME_STATE_BIT(group_, value_, name_)                                \
+  if ((state & NS_FRAME_STATE_BIT(value_)) && groups.Contains(#group_)) {     \
+    if (!result.IsEmpty()) {                                                  \
+      result.Insert(" | ", 0);                                                \
+    }                                                                         \
+    result.Insert(#name_, 0);                                                 \
+    state = state & ~NS_FRAME_STATE_BIT(value_);                              \
+  }
+#include "nsFrameStateBits.h"
+#undef FRAME_STATE_GROUP
+#undef FRAME_STATE_BIT
+
+  if (state) {
+    result.AppendPrintf(" | 0x%0llx", state);
+  }
+
+  return result;
+}
+
+void
+PrintFrameState(nsIFrame* aFrame)
+{
+  printf("%s\n", GetFrameState(aFrame).get());
+}
+#endif
+
+} // namespace mozilla
--- a/layout/generic/nsFrameState.h
+++ b/layout/generic/nsFrameState.h
@@ -58,9 +58,16 @@ inline nsFrameState& operator^=(nsFrameS
   aLeft = aLeft ^ aRight;
   return aLeft;
 }
 
 // Bits 20-31 and 60-63 of the frame state are reserved for implementations.
 #define NS_FRAME_IMPL_RESERVED                      nsFrameState(0xF0000000FFF00000)
 #define NS_FRAME_RESERVED                           ~NS_FRAME_IMPL_RESERVED
 
+namespace mozilla {
+#ifdef DEBUG
+nsCString GetFrameState(nsIFrame* aFrame);
+void PrintFrameState(nsIFrame* aFrame);
+#endif
+}
+
 #endif /* nsFrameState_h_ */ 
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -25,16 +25,21 @@
     frame state bits -- bits 0..19 and 32..59 -- are in this group.
 
   FRAME_STATE_BIT(group_, value_, name_)
 
     This denotes the existence of a frame state bit.  group_ indicates
     which group the bit belongs to, value_ is the bit number (0..63),
     and name_ is the name of the frame state bit constant.
 
+  Note that if you add a new frame state group, you'll need to #include
+  the header for its frame classes in nsFrameState.cpp and, if they don't
+  already, add nsQueryFrame implementations (which can be DEBUG-only) to
+  the frame classes.
+
  ******/
 
 #ifndef FRAME_STATE_GROUP
 #define FRAME_STATE_GROUP(name_, class_) /* nothing */
 #define DEFINED_FRAME_STATE_GROUP
 #endif
 
 #ifndef FRAME_STATE_BIT
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -21,16 +21,22 @@ nsIFrame*
 NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
                        nsFrameState aTypeBit)
 {
   return new (aPresShell) nsPlaceholderFrame(aContext, aTypeBit);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsPlaceholderFrame)
 
+#ifdef DEBUG
+NS_QUERYFRAME_HEAD(nsPlaceholderFrame)
+  NS_QUERYFRAME_ENTRY(nsPlaceholderFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
+#endif
+
 /* virtual */ nsSize
 nsPlaceholderFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
 {
   nsSize size(0, 0);
   DISPLAY_MIN_SIZE(this, size);
   return size;
 }
 
--- a/layout/generic/nsPlaceholderFrame.h
+++ b/layout/generic/nsPlaceholderFrame.h
@@ -49,16 +49,20 @@ nsIFrame* NS_NewPlaceholderFrame(nsIPres
 
 /**
  * Implementation of a frame that's used as a placeholder for a frame that
  * has been moved out of the flow.
  */
 class nsPlaceholderFrame MOZ_FINAL : public nsFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
+#ifdef DEBUG
+  NS_DECL_QUERYFRAME_TARGET(nsPlaceholderFrame)
+  NS_DECL_QUERYFRAME
+#endif
 
   /**
    * Create a new placeholder frame.  aTypeBit must be one of the
    * PLACEHOLDER_FOR_* constants above.
    */
   friend nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell,
                                           nsStyleContext* aContext,
                                           nsFrameState aTypeBit);
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -99,16 +99,22 @@ NS_NewBoxFrame(nsIPresShell* aPresShell,
 nsIFrame*
 NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsBoxFrame(aPresShell, aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
 
+#ifdef DEBUG
+NS_QUERYFRAME_HEAD(nsBoxFrame)
+  NS_QUERYFRAME_ENTRY(nsBoxFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
+#endif
+
 nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell,
                        nsStyleContext* aContext,
                        bool aIsRoot,
                        nsBoxLayout* aLayoutManager) :
   nsContainerFrame(aContext)
 {
   mState |= NS_STATE_IS_HORIZONTAL;
   mState |= NS_STATE_AUTO_STRETCH;
--- a/layout/xul/nsBoxFrame.h
+++ b/layout/xul/nsBoxFrame.h
@@ -27,16 +27,20 @@ nsIFrame* NS_NewBoxFrame(nsIPresShell* a
                          nsBoxLayout* aLayoutManager);
 nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell,
                          nsStyleContext* aContext);
 
 class nsBoxFrame : public nsContainerFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
+#ifdef DEBUG
+  NS_DECL_QUERYFRAME_TARGET(nsBoxFrame)
+  NS_DECL_QUERYFRAME
+#endif
 
   friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, 
                                   nsStyleContext* aContext,
                                   bool aIsRoot,
                                   nsBoxLayout* aLayoutManager);
   friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
--- a/python/lldbutils/README.txt
+++ b/python/lldbutils/README.txt
@@ -79,16 +79,29 @@ called with a smart pointer like nsRefPt
   (lldb) p mDocumentURI
   (nsCOMPtr<nsIURI>) $3 = {
     mRawPtr = 0x0000000117163e50
   }
   (lldb) prefcnt mDocumentURI
   11
 
 
+* pstate EXPR
+
+  Shows the frame state bits (using their symbolic names) of a given frame.
+  EXPR is an expression that is evaluated, and must be an nsIFrame*.
+
+  (lldb) p this
+  (nsTextFrame *) $1 = 0x000000011f470b10
+  (lldb) p/x mState
+  (nsFrameState) $2 = 0x0000004080604000
+  (lldb) pstate this
+  TEXT_HAS_NONCOLLAPSED_CHARACTERS | TEXT_END_OF_LINE | TEXT_START_OF_LINE | NS_FRAME_PAINTED_THEBES | NS_FRAME_INDEPENDENT_SELECTION
+
+
 * ptag EXPR
 
   Shows the DOM tag name of a node.  EXPR is an expression that is
   evaluated, and can be either an nsINode pointer or a concrete DOM
   object.
 
   (lldb) p this
   (nsHTMLDocument *) $0 = 0x0000000116e9d800
--- a/python/lldbutils/lldbutils/layout.py
+++ b/python/lldbutils/lldbutils/layout.py
@@ -3,13 +3,18 @@ import lldb
 def frametree(debugger, command, result, dict):
     """Dumps the frame tree containing the given nsIFrame*."""
     debugger.HandleCommand('expr (' + command + ')->DumpFrameTree()')
 
 def frametreelimited(debugger, command, result, dict):
     """Dumps the subtree of a frame tree rooted at the given nsIFrame*."""
     debugger.HandleCommand('expr (' + command + ')->DumpFrameTreeLimited()')
 
+def pstate(debugger, command, result, dict):
+    """Displays a frame's state bits symbolically."""
+    debugger.HandleCommand('expr mozilla::PrintFrameState(' + command + ')')
+
 def init(debugger):
     debugger.HandleCommand('command script add -f lldbutils.layout.frametree frametree')
     debugger.HandleCommand('command script add -f lldbutils.layout.frametreelimited frametreelimited')
     debugger.HandleCommand('command alias ft frametree')
     debugger.HandleCommand('command alias ftl frametreelimited')
+    debugger.HandleCommand('command script add -f lldbutils.layout.pstate pstate');