Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 // vim:cindent:tabstop=4:expandtab:shiftwidth=4:
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsLayoutDebuggingTools.h"
9 #include "nsIDocShell.h"
10 #include "nsPIDOMWindow.h"
11 #include "nsIContentViewer.h"
13 #include "nsIServiceManager.h"
14 #include "nsIAtom.h"
15 #include "nsQuickSort.h"
17 #include "nsIContent.h"
18 #include "nsIDocument.h"
19 #include "nsIDOMDocument.h"
21 #include "nsIPresShell.h"
22 #include "nsViewManager.h"
23 #include "nsIFrame.h"
25 #include "nsILayoutDebugger.h"
26 #include "nsLayoutCID.h"
27 static NS_DEFINE_CID(kLayoutDebuggerCID, NS_LAYOUT_DEBUGGER_CID);
29 #include "nsISelectionController.h"
30 #include "mozilla/dom/Element.h"
31 #include "mozilla/Preferences.h"
33 using namespace mozilla;
35 static already_AddRefed<nsIContentViewer>
36 doc_viewer(nsIDocShell *aDocShell)
37 {
38 if (!aDocShell)
39 return nullptr;
40 nsCOMPtr<nsIContentViewer> result;
41 aDocShell->GetContentViewer(getter_AddRefs(result));
42 return result.forget();
43 }
45 static already_AddRefed<nsIPresShell>
46 pres_shell(nsIDocShell *aDocShell)
47 {
48 nsCOMPtr<nsIContentViewer> cv = doc_viewer(aDocShell);
49 if (!cv)
50 return nullptr;
51 nsCOMPtr<nsIPresShell> result;
52 cv->GetPresShell(getter_AddRefs(result));
53 return result.forget();
54 }
56 static nsViewManager*
57 view_manager(nsIDocShell *aDocShell)
58 {
59 nsCOMPtr<nsIPresShell> shell(pres_shell(aDocShell));
60 if (!shell)
61 return nullptr;
62 return shell->GetViewManager();
63 }
65 #ifdef DEBUG
66 static already_AddRefed<nsIDocument>
67 document(nsIDocShell *aDocShell)
68 {
69 nsCOMPtr<nsIContentViewer> cv(doc_viewer(aDocShell));
70 if (!cv)
71 return nullptr;
72 nsCOMPtr<nsIDOMDocument> domDoc;
73 cv->GetDOMDocument(getter_AddRefs(domDoc));
74 if (!domDoc)
75 return nullptr;
76 nsCOMPtr<nsIDocument> result = do_QueryInterface(domDoc);
77 return result.forget();
78 }
79 #endif
81 nsLayoutDebuggingTools::nsLayoutDebuggingTools()
82 : mPaintFlashing(false),
83 mPaintDumping(false),
84 mInvalidateDumping(false),
85 mEventDumping(false),
86 mMotionEventDumping(false),
87 mCrossingEventDumping(false),
88 mReflowCounts(false)
89 {
90 NewURILoaded();
91 }
93 nsLayoutDebuggingTools::~nsLayoutDebuggingTools()
94 {
95 }
97 NS_IMPL_ISUPPORTS(nsLayoutDebuggingTools, nsILayoutDebuggingTools)
99 NS_IMETHODIMP
100 nsLayoutDebuggingTools::Init(nsIDOMWindow *aWin)
101 {
102 if (!Preferences::GetService()) {
103 return NS_ERROR_UNEXPECTED;
104 }
106 {
107 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWin);
108 if (!window)
109 return NS_ERROR_UNEXPECTED;
110 mDocShell = window->GetDocShell();
111 }
112 NS_ENSURE_TRUE(mDocShell, NS_ERROR_UNEXPECTED);
114 mPaintFlashing =
115 Preferences::GetBool("nglayout.debug.paint_flashing", mPaintFlashing);
116 mPaintDumping =
117 Preferences::GetBool("nglayout.debug.paint_dumping", mPaintDumping);
118 mInvalidateDumping =
119 Preferences::GetBool("nglayout.debug.invalidate_dumping", mInvalidateDumping);
120 mEventDumping =
121 Preferences::GetBool("nglayout.debug.event_dumping", mEventDumping);
122 mMotionEventDumping =
123 Preferences::GetBool("nglayout.debug.motion_event_dumping",
124 mMotionEventDumping);
125 mCrossingEventDumping =
126 Preferences::GetBool("nglayout.debug.crossing_event_dumping",
127 mCrossingEventDumping);
128 mReflowCounts =
129 Preferences::GetBool("layout.reflow.showframecounts", mReflowCounts);
131 {
132 nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID);
133 if (ld) {
134 ld->GetShowFrameBorders(&mVisualDebugging);
135 ld->GetShowEventTargetFrameBorder(&mVisualEventDebugging);
136 }
137 }
139 return NS_OK;
140 }
142 NS_IMETHODIMP
143 nsLayoutDebuggingTools::NewURILoaded()
144 {
145 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
146 // Reset all the state that should be reset between pages.
148 // XXX Some of these should instead be transferred between pages!
149 mEditorMode = false;
150 mVisualDebugging = false;
151 mVisualEventDebugging = false;
153 mReflowCounts = false;
155 ForceRefresh();
156 return NS_OK;
157 }
159 NS_IMETHODIMP
160 nsLayoutDebuggingTools::GetVisualDebugging(bool *aVisualDebugging)
161 {
162 *aVisualDebugging = mVisualDebugging;
163 return NS_OK;
164 }
166 NS_IMETHODIMP
167 nsLayoutDebuggingTools::SetVisualDebugging(bool aVisualDebugging)
168 {
169 nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID);
170 if (!ld)
171 return NS_ERROR_UNEXPECTED;
172 mVisualDebugging = aVisualDebugging;
173 ld->SetShowFrameBorders(aVisualDebugging);
174 ForceRefresh();
175 return NS_OK;
176 }
178 NS_IMETHODIMP
179 nsLayoutDebuggingTools::GetVisualEventDebugging(bool *aVisualEventDebugging)
180 {
181 *aVisualEventDebugging = mVisualEventDebugging;
182 return NS_OK;
183 }
185 NS_IMETHODIMP
186 nsLayoutDebuggingTools::SetVisualEventDebugging(bool aVisualEventDebugging)
187 {
188 nsCOMPtr<nsILayoutDebugger> ld = do_GetService(kLayoutDebuggerCID);
189 if (!ld)
190 return NS_ERROR_UNEXPECTED;
191 mVisualEventDebugging = aVisualEventDebugging;
192 ld->SetShowEventTargetFrameBorder(aVisualEventDebugging);
193 ForceRefresh();
194 return NS_OK;
195 }
197 NS_IMETHODIMP
198 nsLayoutDebuggingTools::GetPaintFlashing(bool *aPaintFlashing)
199 {
200 *aPaintFlashing = mPaintFlashing;
201 return NS_OK;
202 }
204 NS_IMETHODIMP
205 nsLayoutDebuggingTools::SetPaintFlashing(bool aPaintFlashing)
206 {
207 mPaintFlashing = aPaintFlashing;
208 return SetBoolPrefAndRefresh("nglayout.debug.paint_flashing", mPaintFlashing);
209 }
211 NS_IMETHODIMP
212 nsLayoutDebuggingTools::GetPaintDumping(bool *aPaintDumping)
213 {
214 *aPaintDumping = mPaintDumping;
215 return NS_OK;
216 }
218 NS_IMETHODIMP
219 nsLayoutDebuggingTools::SetPaintDumping(bool aPaintDumping)
220 {
221 mPaintDumping = aPaintDumping;
222 return SetBoolPrefAndRefresh("nglayout.debug.paint_dumping", mPaintDumping);
223 }
225 NS_IMETHODIMP
226 nsLayoutDebuggingTools::GetInvalidateDumping(bool *aInvalidateDumping)
227 {
228 *aInvalidateDumping = mInvalidateDumping;
229 return NS_OK;
230 }
232 NS_IMETHODIMP
233 nsLayoutDebuggingTools::SetInvalidateDumping(bool aInvalidateDumping)
234 {
235 mInvalidateDumping = aInvalidateDumping;
236 return SetBoolPrefAndRefresh("nglayout.debug.invalidate_dumping", mInvalidateDumping);
237 }
239 NS_IMETHODIMP
240 nsLayoutDebuggingTools::GetEventDumping(bool *aEventDumping)
241 {
242 *aEventDumping = mEventDumping;
243 return NS_OK;
244 }
246 NS_IMETHODIMP
247 nsLayoutDebuggingTools::SetEventDumping(bool aEventDumping)
248 {
249 mEventDumping = aEventDumping;
250 return SetBoolPrefAndRefresh("nglayout.debug.event_dumping", mEventDumping);
251 }
253 NS_IMETHODIMP
254 nsLayoutDebuggingTools::GetMotionEventDumping(bool *aMotionEventDumping)
255 {
256 *aMotionEventDumping = mMotionEventDumping;
257 return NS_OK;
258 }
260 NS_IMETHODIMP
261 nsLayoutDebuggingTools::SetMotionEventDumping(bool aMotionEventDumping)
262 {
263 mMotionEventDumping = aMotionEventDumping;
264 return SetBoolPrefAndRefresh("nglayout.debug.motion_event_dumping", mMotionEventDumping);
265 }
267 NS_IMETHODIMP
268 nsLayoutDebuggingTools::GetCrossingEventDumping(bool *aCrossingEventDumping)
269 {
270 *aCrossingEventDumping = mCrossingEventDumping;
271 return NS_OK;
272 }
274 NS_IMETHODIMP
275 nsLayoutDebuggingTools::SetCrossingEventDumping(bool aCrossingEventDumping)
276 {
277 mCrossingEventDumping = aCrossingEventDumping;
278 return SetBoolPrefAndRefresh("nglayout.debug.crossing_event_dumping", mCrossingEventDumping);
279 }
281 NS_IMETHODIMP
282 nsLayoutDebuggingTools::GetReflowCounts(bool* aShow)
283 {
284 *aShow = mReflowCounts;
285 return NS_OK;
286 }
288 NS_IMETHODIMP
289 nsLayoutDebuggingTools::SetReflowCounts(bool aShow)
290 {
291 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
292 nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell));
293 if (shell) {
294 #ifdef MOZ_REFLOW_PERF
295 shell->SetPaintFrameCount(aShow);
296 SetBoolPrefAndRefresh("layout.reflow.showframecounts", aShow);
297 mReflowCounts = aShow;
298 #else
299 printf("************************************************\n");
300 printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
301 printf("************************************************\n");
302 #endif
303 }
304 return NS_OK;
305 }
307 static void DumpAWebShell(nsIDocShellTreeItem* aShellItem, FILE* out, int32_t aIndent)
308 {
309 nsString name;
310 nsCOMPtr<nsIDocShellTreeItem> parent;
311 int32_t i, n;
313 for (i = aIndent; --i >= 0; )
314 fprintf(out, " ");
316 fprintf(out, "%p '", static_cast<void*>(aShellItem));
317 aShellItem->GetName(name);
318 aShellItem->GetSameTypeParent(getter_AddRefs(parent));
319 fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
320 fprintf(out, "' parent=%p <\n", static_cast<void*>(parent));
322 ++aIndent;
323 aShellItem->GetChildCount(&n);
324 for (i = 0; i < n; ++i) {
325 nsCOMPtr<nsIDocShellTreeItem> child;
326 aShellItem->GetChildAt(i, getter_AddRefs(child));
327 if (child) {
328 DumpAWebShell(child, out, aIndent);
329 }
330 }
331 --aIndent;
332 for (i = aIndent; --i >= 0; )
333 fprintf(out, " ");
334 fputs(">\n", out);
335 }
337 NS_IMETHODIMP
338 nsLayoutDebuggingTools::DumpWebShells()
339 {
340 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
341 DumpAWebShell(mDocShell, stdout, 0);
342 return NS_OK;
343 }
345 static
346 void
347 DumpContentRecur(nsIDocShell* aDocShell, FILE* out)
348 {
349 #ifdef DEBUG
350 if (nullptr != aDocShell) {
351 fprintf(out, "docshell=%p \n", static_cast<void*>(aDocShell));
352 nsCOMPtr<nsIDocument> doc(document(aDocShell));
353 if (doc) {
354 dom::Element *root = doc->GetRootElement();
355 if (root) {
356 root->List(out);
357 }
358 }
359 else {
360 fputs("no document\n", out);
361 }
362 // dump the frames of the sub documents
363 int32_t i, n;
364 aDocShell->GetChildCount(&n);
365 for (i = 0; i < n; ++i) {
366 nsCOMPtr<nsIDocShellTreeItem> child;
367 aDocShell->GetChildAt(i, getter_AddRefs(child));
368 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
369 if (child) {
370 DumpContentRecur(childAsShell, out);
371 }
372 }
373 }
374 #endif
375 }
377 NS_IMETHODIMP
378 nsLayoutDebuggingTools::DumpContent()
379 {
380 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
381 DumpContentRecur(mDocShell, stdout);
382 return NS_OK;
383 }
385 static void
386 DumpFramesRecur(nsIDocShell* aDocShell, FILE* out)
387 {
388 #ifdef DEBUG
389 fprintf(out, "webshell=%p \n", static_cast<void*>(aDocShell));
390 nsCOMPtr<nsIPresShell> shell(pres_shell(aDocShell));
391 if (shell) {
392 nsIFrame* root = shell->GetRootFrame();
393 if (root) {
394 root->List(out);
395 }
396 }
397 else {
398 fputs("null pres shell\n", out);
399 }
401 // dump the frames of the sub documents
402 int32_t i, n;
403 aDocShell->GetChildCount(&n);
404 for (i = 0; i < n; ++i) {
405 nsCOMPtr<nsIDocShellTreeItem> child;
406 aDocShell->GetChildAt(i, getter_AddRefs(child));
407 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
408 if (childAsShell) {
409 DumpFramesRecur(childAsShell, out);
410 }
411 }
412 #endif
413 }
415 NS_IMETHODIMP
416 nsLayoutDebuggingTools::DumpFrames()
417 {
418 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
419 DumpFramesRecur(mDocShell, stdout);
420 return NS_OK;
421 }
423 static
424 void
425 DumpViewsRecur(nsIDocShell* aDocShell, FILE* out)
426 {
427 #ifdef DEBUG
428 fprintf(out, "docshell=%p \n", static_cast<void*>(aDocShell));
429 nsRefPtr<nsViewManager> vm(view_manager(aDocShell));
430 if (vm) {
431 nsView* root = vm->GetRootView();
432 if (root) {
433 root->List(out);
434 }
435 }
436 else {
437 fputs("null view manager\n", out);
438 }
440 // dump the views of the sub documents
441 int32_t i, n;
442 aDocShell->GetChildCount(&n);
443 for (i = 0; i < n; i++) {
444 nsCOMPtr<nsIDocShellTreeItem> child;
445 aDocShell->GetChildAt(i, getter_AddRefs(child));
446 nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
447 if (childAsShell) {
448 DumpViewsRecur(childAsShell, out);
449 }
450 }
451 #endif // DEBUG
452 }
454 NS_IMETHODIMP
455 nsLayoutDebuggingTools::DumpViews()
456 {
457 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
458 DumpViewsRecur(mDocShell, stdout);
459 return NS_OK;
460 }
462 NS_IMETHODIMP
463 nsLayoutDebuggingTools::DumpStyleSheets()
464 {
465 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
466 #ifdef DEBUG
467 FILE *out = stdout;
468 nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell));
469 if (shell)
470 shell->ListStyleSheets(out);
471 else
472 fputs("null pres shell\n", out);
473 #endif
474 return NS_OK;
475 }
477 NS_IMETHODIMP
478 nsLayoutDebuggingTools::DumpStyleContexts()
479 {
480 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
481 #ifdef DEBUG
482 FILE *out = stdout;
483 nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell));
484 if (shell) {
485 nsIFrame* root = shell->GetRootFrame();
486 if (!root) {
487 fputs("null root frame\n", out);
488 } else {
489 shell->ListStyleContexts(root, out);
490 }
491 } else {
492 fputs("null pres shell\n", out);
493 }
494 #endif
495 return NS_OK;
496 }
498 NS_IMETHODIMP
499 nsLayoutDebuggingTools::DumpReflowStats()
500 {
501 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
502 #ifdef DEBUG
503 nsCOMPtr<nsIPresShell> shell(pres_shell(mDocShell));
504 if (shell) {
505 #ifdef MOZ_REFLOW_PERF
506 shell->DumpReflows();
507 #else
508 printf("************************************************\n");
509 printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
510 printf("************************************************\n");
511 #endif
512 }
513 #endif
514 return NS_OK;
515 }
517 void nsLayoutDebuggingTools::ForceRefresh()
518 {
519 nsRefPtr<nsViewManager> vm(view_manager(mDocShell));
520 if (!vm)
521 return;
522 nsView* root = vm->GetRootView();
523 if (root) {
524 vm->InvalidateView(root);
525 }
526 }
528 nsresult
529 nsLayoutDebuggingTools::SetBoolPrefAndRefresh(const char * aPrefName,
530 bool aNewVal)
531 {
532 NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
534 nsIPrefService* prefService = Preferences::GetService();
535 NS_ENSURE_TRUE(prefService && aPrefName, NS_OK);
537 Preferences::SetBool(aPrefName, aNewVal);
538 prefService->SavePrefFile(nullptr);
540 ForceRefresh();
542 return NS_OK;
543 }