1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/tools/layout-debug/src/nsLayoutDebuggingTools.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,543 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +// vim:cindent:tabstop=4:expandtab:shiftwidth=4: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsLayoutDebuggingTools.h" 1.11 + 1.12 +#include "nsIDocShell.h" 1.13 +#include "nsPIDOMWindow.h" 1.14 +#include "nsIContentViewer.h" 1.15 + 1.16 +#include "nsIServiceManager.h" 1.17 +#include "nsIAtom.h" 1.18 +#include "nsQuickSort.h" 1.19 + 1.20 +#include "nsIContent.h" 1.21 +#include "nsIDocument.h" 1.22 +#include "nsIDOMDocument.h" 1.23 + 1.24 +#include "nsIPresShell.h" 1.25 +#include "nsViewManager.h" 1.26 +#include "nsIFrame.h" 1.27 + 1.28 +#include "nsILayoutDebugger.h" 1.29 +#include "nsLayoutCID.h" 1.30 +static NS_DEFINE_CID(kLayoutDebuggerCID, NS_LAYOUT_DEBUGGER_CID); 1.31 + 1.32 +#include "nsISelectionController.h" 1.33 +#include "mozilla/dom/Element.h" 1.34 +#include "mozilla/Preferences.h" 1.35 + 1.36 +using namespace mozilla; 1.37 + 1.38 +static already_AddRefed<nsIContentViewer> 1.39 +doc_viewer(nsIDocShell *aDocShell) 1.40 +{ 1.41 + if (!aDocShell) 1.42 + return nullptr; 1.43 + nsCOMPtr<nsIContentViewer> result; 1.44 + aDocShell->GetContentViewer(getter_AddRefs(result)); 1.45 + return result.forget(); 1.46 +} 1.47 + 1.48 +static already_AddRefed<nsIPresShell> 1.49 +pres_shell(nsIDocShell *aDocShell) 1.50 +{ 1.51 + nsCOMPtr<nsIContentViewer> cv = doc_viewer(aDocShell); 1.52 + if (!cv) 1.53 + return nullptr; 1.54 + nsCOMPtr<nsIPresShell> result; 1.55 + cv->GetPresShell(getter_AddRefs(result)); 1.56 + return result.forget(); 1.57 +} 1.58 + 1.59 +static nsViewManager* 1.60 +view_manager(nsIDocShell *aDocShell) 1.61 +{ 1.62 + nsCOMPtr<nsIPresShell> shell(pres_shell(aDocShell)); 1.63 + if (!shell) 1.64 + return nullptr; 1.65 + return shell->GetViewManager(); 1.66 +} 1.67 + 1.68 +#ifdef DEBUG 1.69 +static already_AddRefed<nsIDocument> 1.70 +document(nsIDocShell *aDocShell) 1.71 +{ 1.72 + nsCOMPtr<nsIContentViewer> cv(doc_viewer(aDocShell)); 1.73 + if (!cv) 1.74 + return nullptr; 1.75 + nsCOMPtr<nsIDOMDocument> domDoc; 1.76 + cv->GetDOMDocument(getter_AddRefs(domDoc)); 1.77 + if (!domDoc) 1.78 + return nullptr; 1.79 + nsCOMPtr<nsIDocument> result = do_QueryInterface(domDoc); 1.80 + return result.forget(); 1.81 +} 1.82 +#endif 1.83 + 1.84 +nsLayoutDebuggingTools::nsLayoutDebuggingTools() 1.85 + : mPaintFlashing(false), 1.86 + mPaintDumping(false), 1.87 + mInvalidateDumping(false), 1.88 + mEventDumping(false), 1.89 + mMotionEventDumping(false), 1.90 + mCrossingEventDumping(false), 1.91 + mReflowCounts(false) 1.92 +{ 1.93 + NewURILoaded(); 1.94 +} 1.95 + 1.96 +nsLayoutDebuggingTools::~nsLayoutDebuggingTools() 1.97 +{ 1.98 +} 1.99 + 1.100 +NS_IMPL_ISUPPORTS(nsLayoutDebuggingTools, nsILayoutDebuggingTools) 1.101 + 1.102 +NS_IMETHODIMP 1.103 +nsLayoutDebuggingTools::Init(nsIDOMWindow *aWin) 1.104 +{ 1.105 + if (!Preferences::GetService()) { 1.106 + return NS_ERROR_UNEXPECTED; 1.107 + } 1.108 + 1.109 + { 1.110 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWin); 1.111 + if (!window) 1.112 + return NS_ERROR_UNEXPECTED; 1.113 + mDocShell = window->GetDocShell(); 1.114 + } 1.115 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_UNEXPECTED); 1.116 + 1.117 + mPaintFlashing = 1.118 + Preferences::GetBool("nglayout.debug.paint_flashing", mPaintFlashing); 1.119 + mPaintDumping = 1.120 + Preferences::GetBool("nglayout.debug.paint_dumping", mPaintDumping); 1.121 + mInvalidateDumping = 1.122 + Preferences::GetBool("nglayout.debug.invalidate_dumping", mInvalidateDumping); 1.123 + mEventDumping = 1.124 + Preferences::GetBool("nglayout.debug.event_dumping", mEventDumping); 1.125 + mMotionEventDumping = 1.126 + Preferences::GetBool("nglayout.debug.motion_event_dumping", 1.127 + mMotionEventDumping); 1.128 + mCrossingEventDumping = 1.129 + Preferences::GetBool("nglayout.debug.crossing_event_dumping", 1.130 + mCrossingEventDumping); 1.131 + mReflowCounts = 1.132 + Preferences::GetBool("layout.reflow.showframecounts", mReflowCounts); 1.133 + 1.134 + { 1.135 + nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID); 1.136 + if (ld) { 1.137 + ld->GetShowFrameBorders(&mVisualDebugging); 1.138 + ld->GetShowEventTargetFrameBorder(&mVisualEventDebugging); 1.139 + } 1.140 + } 1.141 + 1.142 + return NS_OK; 1.143 +} 1.144 + 1.145 +NS_IMETHODIMP 1.146 +nsLayoutDebuggingTools::NewURILoaded() 1.147 +{ 1.148 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.149 + // Reset all the state that should be reset between pages. 1.150 + 1.151 + // XXX Some of these should instead be transferred between pages! 1.152 + mEditorMode = false; 1.153 + mVisualDebugging = false; 1.154 + mVisualEventDebugging = false; 1.155 + 1.156 + mReflowCounts = false; 1.157 + 1.158 + ForceRefresh(); 1.159 + return NS_OK; 1.160 +} 1.161 + 1.162 +NS_IMETHODIMP 1.163 +nsLayoutDebuggingTools::GetVisualDebugging(bool *aVisualDebugging) 1.164 +{ 1.165 + *aVisualDebugging = mVisualDebugging; 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +NS_IMETHODIMP 1.170 +nsLayoutDebuggingTools::SetVisualDebugging(bool aVisualDebugging) 1.171 +{ 1.172 + nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID); 1.173 + if (!ld) 1.174 + return NS_ERROR_UNEXPECTED; 1.175 + mVisualDebugging = aVisualDebugging; 1.176 + ld->SetShowFrameBorders(aVisualDebugging); 1.177 + ForceRefresh(); 1.178 + return NS_OK; 1.179 +} 1.180 + 1.181 +NS_IMETHODIMP 1.182 +nsLayoutDebuggingTools::GetVisualEventDebugging(bool *aVisualEventDebugging) 1.183 +{ 1.184 + *aVisualEventDebugging = mVisualEventDebugging; 1.185 + return NS_OK; 1.186 +} 1.187 + 1.188 +NS_IMETHODIMP 1.189 +nsLayoutDebuggingTools::SetVisualEventDebugging(bool aVisualEventDebugging) 1.190 +{ 1.191 + nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID); 1.192 + if (!ld) 1.193 + return NS_ERROR_UNEXPECTED; 1.194 + mVisualEventDebugging = aVisualEventDebugging; 1.195 + ld->SetShowEventTargetFrameBorder(aVisualEventDebugging); 1.196 + ForceRefresh(); 1.197 + return NS_OK; 1.198 +} 1.199 + 1.200 +NS_IMETHODIMP 1.201 +nsLayoutDebuggingTools::GetPaintFlashing(bool *aPaintFlashing) 1.202 +{ 1.203 + *aPaintFlashing = mPaintFlashing; 1.204 + return NS_OK; 1.205 +} 1.206 + 1.207 +NS_IMETHODIMP 1.208 +nsLayoutDebuggingTools::SetPaintFlashing(bool aPaintFlashing) 1.209 +{ 1.210 + mPaintFlashing = aPaintFlashing; 1.211 + return SetBoolPrefAndRefresh("nglayout.debug.paint_flashing", mPaintFlashing); 1.212 +} 1.213 + 1.214 +NS_IMETHODIMP 1.215 +nsLayoutDebuggingTools::GetPaintDumping(bool *aPaintDumping) 1.216 +{ 1.217 + *aPaintDumping = mPaintDumping; 1.218 + return NS_OK; 1.219 +} 1.220 + 1.221 +NS_IMETHODIMP 1.222 +nsLayoutDebuggingTools::SetPaintDumping(bool aPaintDumping) 1.223 +{ 1.224 + mPaintDumping = aPaintDumping; 1.225 + return SetBoolPrefAndRefresh("nglayout.debug.paint_dumping", mPaintDumping); 1.226 +} 1.227 + 1.228 +NS_IMETHODIMP 1.229 +nsLayoutDebuggingTools::GetInvalidateDumping(bool *aInvalidateDumping) 1.230 +{ 1.231 + *aInvalidateDumping = mInvalidateDumping; 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +NS_IMETHODIMP 1.236 +nsLayoutDebuggingTools::SetInvalidateDumping(bool aInvalidateDumping) 1.237 +{ 1.238 + mInvalidateDumping = aInvalidateDumping; 1.239 + return SetBoolPrefAndRefresh("nglayout.debug.invalidate_dumping", mInvalidateDumping); 1.240 +} 1.241 + 1.242 +NS_IMETHODIMP 1.243 +nsLayoutDebuggingTools::GetEventDumping(bool *aEventDumping) 1.244 +{ 1.245 + *aEventDumping = mEventDumping; 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +NS_IMETHODIMP 1.250 +nsLayoutDebuggingTools::SetEventDumping(bool aEventDumping) 1.251 +{ 1.252 + mEventDumping = aEventDumping; 1.253 + return SetBoolPrefAndRefresh("nglayout.debug.event_dumping", mEventDumping); 1.254 +} 1.255 + 1.256 +NS_IMETHODIMP 1.257 +nsLayoutDebuggingTools::GetMotionEventDumping(bool *aMotionEventDumping) 1.258 +{ 1.259 + *aMotionEventDumping = mMotionEventDumping; 1.260 + return NS_OK; 1.261 +} 1.262 + 1.263 +NS_IMETHODIMP 1.264 +nsLayoutDebuggingTools::SetMotionEventDumping(bool aMotionEventDumping) 1.265 +{ 1.266 + mMotionEventDumping = aMotionEventDumping; 1.267 + return SetBoolPrefAndRefresh("nglayout.debug.motion_event_dumping", mMotionEventDumping); 1.268 +} 1.269 + 1.270 +NS_IMETHODIMP 1.271 +nsLayoutDebuggingTools::GetCrossingEventDumping(bool *aCrossingEventDumping) 1.272 +{ 1.273 + *aCrossingEventDumping = mCrossingEventDumping; 1.274 + return NS_OK; 1.275 +} 1.276 + 1.277 +NS_IMETHODIMP 1.278 +nsLayoutDebuggingTools::SetCrossingEventDumping(bool aCrossingEventDumping) 1.279 +{ 1.280 + mCrossingEventDumping = aCrossingEventDumping; 1.281 + return SetBoolPrefAndRefresh("nglayout.debug.crossing_event_dumping", mCrossingEventDumping); 1.282 +} 1.283 + 1.284 +NS_IMETHODIMP 1.285 +nsLayoutDebuggingTools::GetReflowCounts(bool* aShow) 1.286 +{ 1.287 + *aShow = mReflowCounts; 1.288 + return NS_OK; 1.289 +} 1.290 + 1.291 +NS_IMETHODIMP 1.292 +nsLayoutDebuggingTools::SetReflowCounts(bool aShow) 1.293 +{ 1.294 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.295 + nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell)); 1.296 + if (shell) { 1.297 +#ifdef MOZ_REFLOW_PERF 1.298 + shell->SetPaintFrameCount(aShow); 1.299 + SetBoolPrefAndRefresh("layout.reflow.showframecounts", aShow); 1.300 + mReflowCounts = aShow; 1.301 +#else 1.302 + printf("************************************************\n"); 1.303 + printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n"); 1.304 + printf("************************************************\n"); 1.305 +#endif 1.306 + } 1.307 + return NS_OK; 1.308 +} 1.309 + 1.310 +static void DumpAWebShell(nsIDocShellTreeItem* aShellItem, FILE* out, int32_t aIndent) 1.311 +{ 1.312 + nsString name; 1.313 + nsCOMPtr<nsIDocShellTreeItem> parent; 1.314 + int32_t i, n; 1.315 + 1.316 + for (i = aIndent; --i >= 0; ) 1.317 + fprintf(out, " "); 1.318 + 1.319 + fprintf(out, "%p '", static_cast<void*>(aShellItem)); 1.320 + aShellItem->GetName(name); 1.321 + aShellItem->GetSameTypeParent(getter_AddRefs(parent)); 1.322 + fputs(NS_LossyConvertUTF16toASCII(name).get(), out); 1.323 + fprintf(out, "' parent=%p <\n", static_cast<void*>(parent)); 1.324 + 1.325 + ++aIndent; 1.326 + aShellItem->GetChildCount(&n); 1.327 + for (i = 0; i < n; ++i) { 1.328 + nsCOMPtr<nsIDocShellTreeItem> child; 1.329 + aShellItem->GetChildAt(i, getter_AddRefs(child)); 1.330 + if (child) { 1.331 + DumpAWebShell(child, out, aIndent); 1.332 + } 1.333 + } 1.334 + --aIndent; 1.335 + for (i = aIndent; --i >= 0; ) 1.336 + fprintf(out, " "); 1.337 + fputs(">\n", out); 1.338 +} 1.339 + 1.340 +NS_IMETHODIMP 1.341 +nsLayoutDebuggingTools::DumpWebShells() 1.342 +{ 1.343 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.344 + DumpAWebShell(mDocShell, stdout, 0); 1.345 + return NS_OK; 1.346 +} 1.347 + 1.348 +static 1.349 +void 1.350 +DumpContentRecur(nsIDocShell* aDocShell, FILE* out) 1.351 +{ 1.352 +#ifdef DEBUG 1.353 + if (nullptr != aDocShell) { 1.354 + fprintf(out, "docshell=%p \n", static_cast<void*>(aDocShell)); 1.355 + nsCOMPtr<nsIDocument> doc(document(aDocShell)); 1.356 + if (doc) { 1.357 + dom::Element *root = doc->GetRootElement(); 1.358 + if (root) { 1.359 + root->List(out); 1.360 + } 1.361 + } 1.362 + else { 1.363 + fputs("no document\n", out); 1.364 + } 1.365 + // dump the frames of the sub documents 1.366 + int32_t i, n; 1.367 + aDocShell->GetChildCount(&n); 1.368 + for (i = 0; i < n; ++i) { 1.369 + nsCOMPtr<nsIDocShellTreeItem> child; 1.370 + aDocShell->GetChildAt(i, getter_AddRefs(child)); 1.371 + nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); 1.372 + if (child) { 1.373 + DumpContentRecur(childAsShell, out); 1.374 + } 1.375 + } 1.376 + } 1.377 +#endif 1.378 +} 1.379 + 1.380 +NS_IMETHODIMP 1.381 +nsLayoutDebuggingTools::DumpContent() 1.382 +{ 1.383 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.384 + DumpContentRecur(mDocShell, stdout); 1.385 + return NS_OK; 1.386 +} 1.387 + 1.388 +static void 1.389 +DumpFramesRecur(nsIDocShell* aDocShell, FILE* out) 1.390 +{ 1.391 +#ifdef DEBUG 1.392 + fprintf(out, "webshell=%p \n", static_cast<void*>(aDocShell)); 1.393 + nsCOMPtr<nsIPresShell> shell(pres_shell(aDocShell)); 1.394 + if (shell) { 1.395 + nsIFrame* root = shell->GetRootFrame(); 1.396 + if (root) { 1.397 + root->List(out); 1.398 + } 1.399 + } 1.400 + else { 1.401 + fputs("null pres shell\n", out); 1.402 + } 1.403 + 1.404 + // dump the frames of the sub documents 1.405 + int32_t i, n; 1.406 + aDocShell->GetChildCount(&n); 1.407 + for (i = 0; i < n; ++i) { 1.408 + nsCOMPtr<nsIDocShellTreeItem> child; 1.409 + aDocShell->GetChildAt(i, getter_AddRefs(child)); 1.410 + nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); 1.411 + if (childAsShell) { 1.412 + DumpFramesRecur(childAsShell, out); 1.413 + } 1.414 + } 1.415 +#endif 1.416 +} 1.417 + 1.418 +NS_IMETHODIMP 1.419 +nsLayoutDebuggingTools::DumpFrames() 1.420 +{ 1.421 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.422 + DumpFramesRecur(mDocShell, stdout); 1.423 + return NS_OK; 1.424 +} 1.425 + 1.426 +static 1.427 +void 1.428 +DumpViewsRecur(nsIDocShell* aDocShell, FILE* out) 1.429 +{ 1.430 +#ifdef DEBUG 1.431 + fprintf(out, "docshell=%p \n", static_cast<void*>(aDocShell)); 1.432 + nsRefPtr<nsViewManager> vm(view_manager(aDocShell)); 1.433 + if (vm) { 1.434 + nsView* root = vm->GetRootView(); 1.435 + if (root) { 1.436 + root->List(out); 1.437 + } 1.438 + } 1.439 + else { 1.440 + fputs("null view manager\n", out); 1.441 + } 1.442 + 1.443 + // dump the views of the sub documents 1.444 + int32_t i, n; 1.445 + aDocShell->GetChildCount(&n); 1.446 + for (i = 0; i < n; i++) { 1.447 + nsCOMPtr<nsIDocShellTreeItem> child; 1.448 + aDocShell->GetChildAt(i, getter_AddRefs(child)); 1.449 + nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child)); 1.450 + if (childAsShell) { 1.451 + DumpViewsRecur(childAsShell, out); 1.452 + } 1.453 + } 1.454 +#endif // DEBUG 1.455 +} 1.456 + 1.457 +NS_IMETHODIMP 1.458 +nsLayoutDebuggingTools::DumpViews() 1.459 +{ 1.460 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.461 + DumpViewsRecur(mDocShell, stdout); 1.462 + return NS_OK; 1.463 +} 1.464 + 1.465 +NS_IMETHODIMP 1.466 +nsLayoutDebuggingTools::DumpStyleSheets() 1.467 +{ 1.468 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.469 +#ifdef DEBUG 1.470 + FILE *out = stdout; 1.471 + nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell)); 1.472 + if (shell) 1.473 + shell->ListStyleSheets(out); 1.474 + else 1.475 + fputs("null pres shell\n", out); 1.476 +#endif 1.477 + return NS_OK; 1.478 +} 1.479 + 1.480 +NS_IMETHODIMP 1.481 +nsLayoutDebuggingTools::DumpStyleContexts() 1.482 +{ 1.483 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.484 +#ifdef DEBUG 1.485 + FILE *out = stdout; 1.486 + nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell)); 1.487 + if (shell) { 1.488 + nsIFrame* root = shell->GetRootFrame(); 1.489 + if (!root) { 1.490 + fputs("null root frame\n", out); 1.491 + } else { 1.492 + shell->ListStyleContexts(root, out); 1.493 + } 1.494 + } else { 1.495 + fputs("null pres shell\n", out); 1.496 + } 1.497 +#endif 1.498 + return NS_OK; 1.499 +} 1.500 + 1.501 +NS_IMETHODIMP 1.502 +nsLayoutDebuggingTools::DumpReflowStats() 1.503 +{ 1.504 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.505 +#ifdef DEBUG 1.506 + nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell)); 1.507 + if (shell) { 1.508 +#ifdef MOZ_REFLOW_PERF 1.509 + shell->DumpReflows(); 1.510 +#else 1.511 + printf("************************************************\n"); 1.512 + printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n"); 1.513 + printf("************************************************\n"); 1.514 +#endif 1.515 + } 1.516 +#endif 1.517 + return NS_OK; 1.518 +} 1.519 + 1.520 +void nsLayoutDebuggingTools::ForceRefresh() 1.521 +{ 1.522 + nsRefPtr<nsViewManager> vm(view_manager(mDocShell)); 1.523 + if (!vm) 1.524 + return; 1.525 + nsView* root = vm->GetRootView(); 1.526 + if (root) { 1.527 + vm->InvalidateView(root); 1.528 + } 1.529 +} 1.530 + 1.531 +nsresult 1.532 +nsLayoutDebuggingTools::SetBoolPrefAndRefresh(const char * aPrefName, 1.533 + bool aNewVal) 1.534 +{ 1.535 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED); 1.536 + 1.537 + nsIPrefService* prefService = Preferences::GetService(); 1.538 + NS_ENSURE_TRUE(prefService && aPrefName, NS_OK); 1.539 + 1.540 + Preferences::SetBool(aPrefName, aNewVal); 1.541 + prefService->SavePrefFile(nullptr); 1.542 + 1.543 + ForceRefresh(); 1.544 + 1.545 + return NS_OK; 1.546 +}