1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 // vim:cindent:tabstop=4:expandtab:shiftwidth=4:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is layout debugging code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2002
21 * the Initial Developer. All Rights Reserved.
24 * L. David Baron <dbaron@dbaron.org> (original author)
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsLayoutDebuggingTools.h"
42 #include "nsIDocShell.h"
43 #include "nsIDocShellTreeNode.h"
44 #include "nsIDocShellTreeItem.h"
45 #include "nsPIDOMWindow.h"
46 #include "nsIDocumentViewer.h"
48 #include "nsIServiceManager.h"
50 #include "nsQuickSort.h"
51 #include "nsIPrefBranch.h"
52 #include "nsIPrefService.h"
54 #include "nsIContent.h"
55 #include "nsIDocument.h"
56 #include "nsIDOMDocument.h"
58 #include "nsIPresShell.h"
59 #include "nsIViewManager.h"
61 #include "nsIFrameDebug.h"
63 #include "nsILayoutDebugger.h"
64 #include "nsLayoutCID.h"
65 static NS_DEFINE_CID(kLayoutDebuggerCID
, NS_LAYOUT_DEBUGGER_CID
);
67 #include "nsISelectionController.h"
69 static already_AddRefed
<nsIContentViewer
>
70 doc_viewer(nsIDocShell
*aDocShell
)
74 nsIContentViewer
*result
= nsnull
;
75 aDocShell
->GetContentViewer(&result
);
79 static already_AddRefed
<nsIPresShell
>
80 pres_shell(nsIDocShell
*aDocShell
)
82 nsCOMPtr
<nsIDocumentViewer
> dv
=
83 do_QueryInterface(nsCOMPtr
<nsIContentViewer
>(doc_viewer(aDocShell
)));
86 nsIPresShell
*result
= nsnull
;
87 dv
->GetPresShell(&result
);
91 #if 0 // not currently needed
92 static already_AddRefed
<nsPresContext
>
93 pres_context(nsIDocShell
*aDocShell
)
95 nsCOMPtr
<nsIDocumentViewer
> dv
=
96 do_QueryInterface(nsCOMPtr
<nsIContentViewer
>(doc_viewer(aDocShell
)));
99 nsPresContext
*result
= nsnull
;
100 dv
->GetPresContext(result
);
105 static nsIViewManager
*
106 view_manager(nsIDocShell
*aDocShell
)
108 nsCOMPtr
<nsIPresShell
> shell(pres_shell(aDocShell
));
111 return shell
->GetViewManager();
115 static already_AddRefed
<nsIDocument
>
116 document(nsIDocShell
*aDocShell
)
118 nsCOMPtr
<nsIContentViewer
> cv(doc_viewer(aDocShell
));
121 nsCOMPtr
<nsIDOMDocument
> domDoc
;
122 cv
->GetDOMDocument(getter_AddRefs(domDoc
));
125 nsIDocument
*result
= nsnull
;
126 CallQueryInterface(domDoc
, &result
);
131 nsLayoutDebuggingTools::nsLayoutDebuggingTools()
132 : mPaintFlashing(PR_FALSE
),
133 mPaintDumping(PR_FALSE
),
134 mInvalidateDumping(PR_FALSE
),
135 mEventDumping(PR_FALSE
),
136 mMotionEventDumping(PR_FALSE
),
137 mCrossingEventDumping(PR_FALSE
),
138 mReflowCounts(PR_FALSE
)
143 nsLayoutDebuggingTools::~nsLayoutDebuggingTools()
147 NS_IMPL_ISUPPORTS1(nsLayoutDebuggingTools
, nsILayoutDebuggingTools
)
150 nsLayoutDebuggingTools::Init(nsIDOMWindow
*aWin
)
152 mPrefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
154 return NS_ERROR_UNEXPECTED
;
157 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(aWin
);
159 return NS_ERROR_UNEXPECTED
;
160 mDocShell
= window
->GetDocShell();
162 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_UNEXPECTED
);
164 GetBoolPref("nglayout.debug.paint_flashing", &mPaintFlashing
);
165 GetBoolPref("nglayout.debug.paint_dumping", &mPaintDumping
);
166 GetBoolPref("nglayout.debug.invalidate_dumping", &mInvalidateDumping
);
167 GetBoolPref("nglayout.debug.event_dumping", &mEventDumping
);
168 GetBoolPref("nglayout.debug.motion_event_dumping", &mMotionEventDumping
);
169 GetBoolPref("nglayout.debug.crossing_event_dumping", &mCrossingEventDumping
);
170 GetBoolPref("layout.reflow.showframecounts", &mReflowCounts
);
173 nsCOMPtr
<nsILayoutDebugger
> ld
= do_GetService(kLayoutDebuggerCID
);
175 ld
->GetShowFrameBorders(&mVisualDebugging
);
176 ld
->GetShowEventTargetFrameBorder(&mVisualEventDebugging
);
184 nsLayoutDebuggingTools::NewURILoaded()
186 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
187 // Reset all the state that should be reset between pages.
189 // XXX Some of these should instead be transferred between pages!
190 mEditorMode
= PR_FALSE
;
191 mVisualDebugging
= PR_FALSE
;
192 mVisualEventDebugging
= PR_FALSE
;
194 mReflowCounts
= PR_FALSE
;
201 nsLayoutDebuggingTools::GetVisualDebugging(PRBool
*aVisualDebugging
)
203 *aVisualDebugging
= mVisualDebugging
;
208 nsLayoutDebuggingTools::SetVisualDebugging(PRBool aVisualDebugging
)
210 nsCOMPtr
<nsILayoutDebugger
> ld
= do_GetService(kLayoutDebuggerCID
);
212 return NS_ERROR_UNEXPECTED
;
213 mVisualDebugging
= aVisualDebugging
;
214 ld
->SetShowFrameBorders(aVisualDebugging
);
220 nsLayoutDebuggingTools::GetVisualEventDebugging(PRBool
*aVisualEventDebugging
)
222 *aVisualEventDebugging
= mVisualEventDebugging
;
227 nsLayoutDebuggingTools::SetVisualEventDebugging(PRBool aVisualEventDebugging
)
229 nsCOMPtr
<nsILayoutDebugger
> ld
= do_GetService(kLayoutDebuggerCID
);
231 return NS_ERROR_UNEXPECTED
;
232 mVisualEventDebugging
= aVisualEventDebugging
;
233 ld
->SetShowEventTargetFrameBorder(aVisualEventDebugging
);
239 nsLayoutDebuggingTools::GetPaintFlashing(PRBool
*aPaintFlashing
)
241 *aPaintFlashing
= mPaintFlashing
;
246 nsLayoutDebuggingTools::SetPaintFlashing(PRBool aPaintFlashing
)
248 mPaintFlashing
= aPaintFlashing
;
249 return SetBoolPrefAndRefresh("nglayout.debug.paint_flashing", mPaintFlashing
);
253 nsLayoutDebuggingTools::GetPaintDumping(PRBool
*aPaintDumping
)
255 *aPaintDumping
= mPaintDumping
;
260 nsLayoutDebuggingTools::SetPaintDumping(PRBool aPaintDumping
)
262 mPaintDumping
= aPaintDumping
;
263 return SetBoolPrefAndRefresh("nglayout.debug.paint_dumping", mPaintDumping
);
267 nsLayoutDebuggingTools::GetInvalidateDumping(PRBool
*aInvalidateDumping
)
269 *aInvalidateDumping
= mInvalidateDumping
;
274 nsLayoutDebuggingTools::SetInvalidateDumping(PRBool aInvalidateDumping
)
276 mInvalidateDumping
= aInvalidateDumping
;
277 return SetBoolPrefAndRefresh("nglayout.debug.invalidate_dumping", mInvalidateDumping
);
281 nsLayoutDebuggingTools::GetEventDumping(PRBool
*aEventDumping
)
283 *aEventDumping
= mEventDumping
;
288 nsLayoutDebuggingTools::SetEventDumping(PRBool aEventDumping
)
290 mEventDumping
= aEventDumping
;
291 return SetBoolPrefAndRefresh("nglayout.debug.event_dumping", mEventDumping
);
295 nsLayoutDebuggingTools::GetMotionEventDumping(PRBool
*aMotionEventDumping
)
297 *aMotionEventDumping
= mMotionEventDumping
;
302 nsLayoutDebuggingTools::SetMotionEventDumping(PRBool aMotionEventDumping
)
304 mMotionEventDumping
= aMotionEventDumping
;
305 return SetBoolPrefAndRefresh("nglayout.debug.motion_event_dumping", mMotionEventDumping
);
309 nsLayoutDebuggingTools::GetCrossingEventDumping(PRBool
*aCrossingEventDumping
)
311 *aCrossingEventDumping
= mCrossingEventDumping
;
316 nsLayoutDebuggingTools::SetCrossingEventDumping(PRBool aCrossingEventDumping
)
318 mCrossingEventDumping
= aCrossingEventDumping
;
319 return SetBoolPrefAndRefresh("nglayout.debug.crossing_event_dumping", mCrossingEventDumping
);
323 nsLayoutDebuggingTools::GetReflowCounts(PRBool
* aShow
)
325 *aShow
= mReflowCounts
;
330 nsLayoutDebuggingTools::SetReflowCounts(PRBool aShow
)
332 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
333 nsCOMPtr
<nsIPresShell
> shell(pres_shell(mDocShell
));
335 #ifdef MOZ_REFLOW_PERF
336 shell
->SetPaintFrameCount(aShow
);
337 SetBoolPrefAndRefresh("layout.reflow.showframecounts", aShow
);
338 mReflowCounts
= aShow
;
340 printf("************************************************\n");
341 printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
342 printf("************************************************\n");
348 static void DumpAWebShell(nsIDocShellTreeItem
* aShellItem
, FILE* out
, PRInt32 aIndent
)
351 nsCOMPtr
<nsIDocShellTreeItem
> parent
;
354 for (i
= aIndent
; --i
>= 0; )
357 fprintf(out
, "%p '", static_cast<void*>(aShellItem
));
358 aShellItem
->GetName(getter_Copies(name
));
359 aShellItem
->GetSameTypeParent(getter_AddRefs(parent
));
360 fputs(NS_LossyConvertUTF16toASCII(name
).get(), out
);
361 fprintf(out
, "' parent=%p <\n", static_cast<void*>(parent
));
364 nsCOMPtr
<nsIDocShellTreeNode
> shellAsNode(do_QueryInterface(aShellItem
));
365 shellAsNode
->GetChildCount(&n
);
366 for (i
= 0; i
< n
; ++i
) {
367 nsCOMPtr
<nsIDocShellTreeItem
> child
;
368 shellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
370 DumpAWebShell(child
, out
, aIndent
);
374 for (i
= aIndent
; --i
>= 0; )
380 nsLayoutDebuggingTools::DumpWebShells()
382 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
383 nsCOMPtr
<nsIDocShellTreeItem
> shellAsItem(do_QueryInterface(mDocShell
));
384 DumpAWebShell(shellAsItem
, stdout
, 0);
390 DumpContentRecur(nsIDocShell
* aDocShell
, FILE* out
)
393 if (nsnull
!= aDocShell
) {
394 fprintf(out
, "docshell=%p \n", static_cast<void*>(aDocShell
));
395 nsCOMPtr
<nsIDocument
> doc(document(aDocShell
));
397 nsIContent
*root
= doc
->GetRootContent();
403 fputs("no document\n", out
);
405 // dump the frames of the sub documents
407 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
408 docShellAsNode
->GetChildCount(&n
);
409 for (i
= 0; i
< n
; ++i
) {
410 nsCOMPtr
<nsIDocShellTreeItem
> child
;
411 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
412 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
414 DumpContentRecur(childAsShell
, out
);
422 nsLayoutDebuggingTools::DumpContent()
424 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
425 DumpContentRecur(mDocShell
, stdout
);
430 DumpFramesRecur(nsIDocShell
* aDocShell
, FILE* out
)
432 fprintf(out
, "webshell=%p \n", static_cast<void*>(aDocShell
));
433 nsCOMPtr
<nsIPresShell
> shell(pres_shell(aDocShell
));
435 nsIFrame
* root
= shell
->GetRootFrame();
437 nsIFrameDebug
* fdbg
= do_QueryFrame(root
);
444 fputs("null pres shell\n", out
);
447 // dump the frames of the sub documents
449 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
450 docShellAsNode
->GetChildCount(&n
);
451 for (i
= 0; i
< n
; ++i
) {
452 nsCOMPtr
<nsIDocShellTreeItem
> child
;
453 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
454 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
456 DumpFramesRecur(childAsShell
, out
);
462 nsLayoutDebuggingTools::DumpFrames()
464 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
465 DumpFramesRecur(mDocShell
, stdout
);
471 DumpViewsRecur(nsIDocShell
* aDocShell
, FILE* out
)
474 fprintf(out
, "docshell=%p \n", static_cast<void*>(aDocShell
));
475 nsCOMPtr
<nsIViewManager
> vm(view_manager(aDocShell
));
478 vm
->GetRootView(root
);
479 if (nsnull
!= root
) {
484 fputs("null view manager\n", out
);
487 // dump the views of the sub documents
489 nsCOMPtr
<nsIDocShellTreeNode
> docShellAsNode(do_QueryInterface(aDocShell
));
490 docShellAsNode
->GetChildCount(&n
);
491 for (i
= 0; i
< n
; i
++) {
492 nsCOMPtr
<nsIDocShellTreeItem
> child
;
493 docShellAsNode
->GetChildAt(i
, getter_AddRefs(child
));
494 nsCOMPtr
<nsIDocShell
> childAsShell(do_QueryInterface(child
));
496 DumpViewsRecur(childAsShell
, out
);
503 nsLayoutDebuggingTools::DumpViews()
505 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
506 DumpViewsRecur(mDocShell
, stdout
);
511 nsLayoutDebuggingTools::DumpStyleSheets()
513 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
516 nsCOMPtr
<nsIPresShell
> shell(pres_shell(mDocShell
));
518 shell
->ListStyleSheets(out
);
520 fputs("null pres shell\n", out
);
526 nsLayoutDebuggingTools::DumpStyleContexts()
528 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
531 nsCOMPtr
<nsIPresShell
> shell(pres_shell(mDocShell
));
533 nsIFrame
* root
= shell
->GetRootFrame();
535 fputs("null root frame\n", out
);
537 shell
->ListStyleContexts(root
, out
);
540 fputs("null pres shell\n", out
);
547 nsLayoutDebuggingTools::DumpReflowStats()
549 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
551 nsCOMPtr
<nsIPresShell
> shell(pres_shell(mDocShell
));
553 #ifdef MOZ_REFLOW_PERF
554 shell
->DumpReflows();
556 printf("************************************************\n");
557 printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
558 printf("************************************************\n");
565 void nsLayoutDebuggingTools::ForceRefresh()
567 nsCOMPtr
<nsIViewManager
> vm(view_manager(mDocShell
));
570 nsIView
* root
= nsnull
;
571 vm
->GetRootView(root
);
573 vm
->UpdateView(root
, NS_VMREFRESH_IMMEDIATE
);
578 nsLayoutDebuggingTools::SetBoolPrefAndRefresh(const char * aPrefName
,
581 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_NOT_INITIALIZED
);
582 NS_ENSURE_TRUE(mPrefs
&& aPrefName
, NS_OK
);
584 mPrefs
->SetBoolPref(aPrefName
, aNewVal
);
585 nsCOMPtr
<nsIPrefService
> prefService
= do_QueryInterface(mPrefs
);
586 NS_ENSURE_STATE(prefService
);
587 prefService
->SavePrefFile(nsnull
);
595 nsLayoutDebuggingTools::GetBoolPref(const char * aPrefName
,
598 NS_ENSURE_TRUE(mPrefs
&& aPrefName
, NS_OK
);
600 mPrefs
->GetBoolPref(aPrefName
, aValue
);