tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsLayoutDebuggingTools.cpp (10423B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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/. */
      6 
      7 #include "nsLayoutDebuggingTools.h"
      8 
      9 #include "ErrorList.h"
     10 #include "RetainedDisplayListBuilder.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/PresShell.h"
     13 #include "mozilla/dom/ChildIterator.h"
     14 #include "mozilla/dom/Document.h"
     15 #include "mozilla/dom/Element.h"
     16 #include "mozilla/dom/TreeIterator.h"
     17 #include "nsAtom.h"
     18 #include "nsCSSFrameConstructor.h"
     19 #include "nsCounterManager.h"
     20 #include "nsDisplayList.h"
     21 #include "nsIContent.h"
     22 #include "nsIDocShell.h"
     23 #include "nsIDocumentViewer.h"
     24 #include "nsIFrame.h"
     25 #include "nsIPrintSettings.h"
     26 #include "nsIPrintSettingsService.h"
     27 #include "nsLayoutUtils.h"
     28 #include "nsPIDOMWindow.h"
     29 
     30 using namespace mozilla;
     31 using mozilla::dom::Document;
     32 
     33 static already_AddRefed<nsIDocumentViewer> doc_viewer(nsIDocShell* aDocShell) {
     34  if (!aDocShell) {
     35    return nullptr;
     36  }
     37  nsCOMPtr<nsIDocumentViewer> viewer;
     38  aDocShell->GetDocViewer(getter_AddRefs(viewer));
     39  return viewer.forget();
     40 }
     41 
     42 static PresShell* GetPresShell(nsIDocShell* aDocShell) {
     43  nsCOMPtr<nsIDocumentViewer> viewer = doc_viewer(aDocShell);
     44  if (!viewer) {
     45    return nullptr;
     46  }
     47  return viewer->GetPresShell();
     48 }
     49 
     50 #ifdef DEBUG
     51 static already_AddRefed<Document> document(nsIDocShell* aDocShell) {
     52  nsCOMPtr<nsIDocumentViewer> viewer(doc_viewer(aDocShell));
     53  if (!viewer) {
     54    return nullptr;
     55  }
     56  return do_AddRef(viewer->GetDocument());
     57 }
     58 #endif
     59 
     60 nsLayoutDebuggingTools::nsLayoutDebuggingTools() { ForceRefresh(); }
     61 
     62 nsLayoutDebuggingTools::~nsLayoutDebuggingTools() = default;
     63 
     64 NS_IMPL_ISUPPORTS(nsLayoutDebuggingTools, nsILayoutDebuggingTools)
     65 
     66 NS_IMETHODIMP
     67 nsLayoutDebuggingTools::Init(mozIDOMWindow* aWin) {
     68  if (!Preferences::GetService()) {
     69    return NS_ERROR_UNEXPECTED;
     70  }
     71 
     72  {
     73    if (!aWin) {
     74      return NS_ERROR_UNEXPECTED;
     75    }
     76    auto* window = nsPIDOMWindowInner::From(aWin);
     77    mDocShell = window->GetDocShell();
     78  }
     79  NS_ENSURE_TRUE(mDocShell, NS_ERROR_UNEXPECTED);
     80 
     81  return NS_OK;
     82 }
     83 
     84 NS_IMETHODIMP
     85 nsLayoutDebuggingTools::SetReflowCounts(bool aShow) {
     86  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
     87 #ifdef MOZ_REFLOW_PERF
     88  if (PresShell* presShell = GetPresShell(mDocShell)) {
     89    presShell->SetPaintFrameCount(aShow);
     90  }
     91 #else
     92  printf("************************************************\n");
     93  printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
     94  printf("************************************************\n");
     95 #endif
     96  return NS_OK;
     97 }
     98 
     99 NS_IMETHODIMP
    100 nsLayoutDebuggingTools::SetPagedMode(bool aPagedMode) {
    101  nsCOMPtr<nsIPrintSettingsService> printSettingsService =
    102      do_GetService("@mozilla.org/gfx/printsettings-service;1");
    103  nsCOMPtr<nsIPrintSettings> printSettings;
    104 
    105  printSettingsService->CreateNewPrintSettings(getter_AddRefs(printSettings));
    106 
    107  // Use the same setup as setupPrintMode() in reftest-content.js.
    108  printSettings->SetPaperWidth(5);
    109  printSettings->SetPaperHeight(3);
    110 
    111  nsIntMargin unwriteableMargin(0, 0, 0, 0);
    112  printSettings->SetUnwriteableMarginInTwips(unwriteableMargin);
    113 
    114  printSettings->SetHeaderStrLeft(u""_ns);
    115  printSettings->SetHeaderStrCenter(u""_ns);
    116  printSettings->SetHeaderStrRight(u""_ns);
    117 
    118  printSettings->SetFooterStrLeft(u""_ns);
    119  printSettings->SetFooterStrCenter(u""_ns);
    120  printSettings->SetFooterStrRight(u""_ns);
    121 
    122  printSettings->SetPrintBGColors(true);
    123  printSettings->SetPrintBGImages(true);
    124 
    125  nsCOMPtr<nsIDocumentViewer> docViewer(doc_viewer(mDocShell));
    126  docViewer->SetPageModeForTesting(aPagedMode, printSettings);
    127 
    128  ForceRefresh();
    129  return NS_OK;
    130 }
    131 
    132 static void DumpContentRecur(nsIDocShell* aDocShell, FILE* out,
    133                             bool aAnonymousSubtrees) {
    134 #ifdef DEBUG
    135  if (!aDocShell) {
    136    return;
    137  }
    138 
    139  fprintf(out, "docshell=%p \n", static_cast<void*>(aDocShell));
    140  RefPtr<Document> doc(document(aDocShell));
    141  if (!doc) {
    142    fputs("no document\n", out);
    143    return;
    144  }
    145 
    146  dom::Element* root = doc->GetRootElement();
    147  if (!root) {
    148    fputs("no root element\n", out);
    149    return;
    150  }
    151 
    152  // The content tree (without anonymous subtrees).
    153  root->List(out);
    154 
    155  // The anonymous subtrees.
    156  if (aAnonymousSubtrees) {
    157    dom::TreeIterator<dom::StyleChildrenIterator> iter(*root);
    158    while (nsIContent* current = iter.GetNext()) {
    159      if (!current->IsRootOfNativeAnonymousSubtree()) {
    160        continue;
    161      }
    162 
    163      fputs("--\n", out);
    164      if (current->IsElement() &&
    165          current->AsElement()->GetPseudoElementType() ==
    166              PseudoStyleType::mozSnapshotContainingBlock) {
    167        fprintf(out,
    168                "View Transition Tree "
    169                "[parent=%p][active-view-transition=%p]:\n",
    170                (void*)current->GetParent(),
    171                (void*)doc->GetActiveViewTransition());
    172      } else {
    173        fprintf(out, "Anonymous Subtree [parent=%p]:\n",
    174                (void*)current->GetParent());
    175      }
    176      current->List(out);
    177    }
    178  }
    179 #endif
    180 }
    181 
    182 NS_IMETHODIMP
    183 nsLayoutDebuggingTools::DumpContent(bool aAnonymousSubtrees) {
    184  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    185  DumpContentRecur(mDocShell, stdout, aAnonymousSubtrees);
    186  return NS_OK;
    187 }
    188 
    189 static void DumpFramesRecur(
    190    nsIDocShell* aDocShell, FILE* out,
    191    nsIFrame::ListFlags aFlags = nsIFrame::ListFlags()) {
    192  if (aFlags.contains(nsIFrame::ListFlag::DisplayInCSSPixels)) {
    193    fprintf(out, "Frame tree in CSS pixels:\n");
    194  } else {
    195    fprintf(out, "Frame tree in app units:\n");
    196  }
    197 
    198  fprintf(out, "docshell=%p \n", aDocShell);
    199  if (PresShell* presShell = GetPresShell(aDocShell)) {
    200    nsIFrame* root = presShell->GetRootFrame();
    201    if (root) {
    202      root->List(out, "", aFlags);
    203    }
    204  } else {
    205    fputs("null pres shell\n", out);
    206  }
    207 }
    208 
    209 static void DumpTextRunsRecur(nsIDocShell* aDocShell, FILE* out) {
    210  fprintf(out, "Text runs:\n");
    211 
    212  fprintf(out, "docshell=%p \n", aDocShell);
    213  if (PresShell* presShell = GetPresShell(aDocShell)) {
    214    nsIFrame* root = presShell->GetRootFrame();
    215    if (root) {
    216      root->ListTextRuns(out);
    217    }
    218  } else {
    219    fputs("null pres shell\n", out);
    220  }
    221 }
    222 
    223 NS_IMETHODIMP
    224 nsLayoutDebuggingTools::DumpFrames(uint8_t aFlags) {
    225  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    226  nsIFrame::ListFlags flags{};
    227  if (aFlags & nsILayoutDebuggingTools::DUMP_FRAME_FLAGS_CSS_PIXELS) {
    228    flags += nsIFrame::ListFlag::DisplayInCSSPixels;
    229  }
    230  if (aFlags & nsILayoutDebuggingTools::DUMP_FRAME_FLAGS_DETERMINISTIC) {
    231    flags += nsIFrame::ListFlag::OnlyListDeterministicInfo;
    232  }
    233  DumpFramesRecur(mDocShell, stdout, flags);
    234  return NS_OK;
    235 }
    236 
    237 NS_IMETHODIMP
    238 nsLayoutDebuggingTools::DumpTextRuns() {
    239  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    240  DumpTextRunsRecur(mDocShell, stdout);
    241  return NS_OK;
    242 }
    243 
    244 NS_IMETHODIMP
    245 nsLayoutDebuggingTools::DumpCounterManager() {
    246  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    247  if (PresShell* presShell = GetPresShell(mDocShell)) {
    248    presShell->FrameConstructor()->GetContainStyleScopeManager().DumpCounters();
    249  }
    250  return NS_OK;
    251 }
    252 
    253 NS_IMETHODIMP
    254 nsLayoutDebuggingTools::DumpRetainedDisplayList() {
    255  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    256  PresShell* presShell = GetPresShell(mDocShell);
    257  if (!presShell) {
    258    fputs("null pres shell\n", stdout);
    259    return NS_OK;
    260  }
    261 
    262  if (!nsLayoutUtils::AreRetainedDisplayListsEnabled()) {
    263    fputs("Retained display list is not enabled\n", stdout);
    264    return NS_OK;
    265  }
    266 
    267  nsIFrame* root = presShell->GetRootFrame();
    268  auto* RDLBuilder = nsLayoutUtils::GetRetainedDisplayListBuilder(root);
    269  if (!RDLBuilder) {
    270    fputs("no retained display list\n", stdout);
    271    return NS_OK;
    272  }
    273  nsDisplayListBuilder* builder = RDLBuilder->Builder();
    274  const nsDisplayList* list = RDLBuilder->List();
    275  if (!builder || !list) {
    276    fputs("no retained display list\n", stdout);
    277    return NS_OK;
    278  }
    279 
    280  fprintf(stdout, "Retained Display List (rootframe=%p) visible=%s:\n",
    281          nsLayoutUtils::GetDisplayRootFrame(root),
    282          ToString(builder->GetVisibleRect()).c_str());
    283  fputs("<\n", stdout);
    284  nsIFrame::PrintDisplayList(builder, *list, 1, false);
    285  fputs(">\n", stdout);
    286  return NS_OK;
    287 }
    288 
    289 NS_IMETHODIMP
    290 nsLayoutDebuggingTools::DumpStyleSheets() {
    291  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    292 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
    293  FILE* out = stdout;
    294  if (PresShell* presShell = GetPresShell(mDocShell)) {
    295    presShell->ListStyleSheets(out);
    296  } else {
    297    fputs("null pres shell\n", out);
    298  }
    299 #endif
    300  return NS_OK;
    301 }
    302 
    303 NS_IMETHODIMP nsLayoutDebuggingTools::DumpMatchedRules() {
    304  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    305  FILE* out = stdout;
    306  if (PresShell* presShell = GetPresShell(mDocShell)) {
    307    nsIFrame* root = presShell->GetRootFrame();
    308    if (root) {
    309      root->ListWithMatchedRules(out);
    310    }
    311  } else {
    312    fputs("null pres shell\n", out);
    313  }
    314  return NS_OK;
    315 }
    316 
    317 NS_IMETHODIMP
    318 nsLayoutDebuggingTools::DumpComputedStyles() {
    319  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    320 #ifdef DEBUG
    321  FILE* out = stdout;
    322  if (PresShell* presShell = GetPresShell(mDocShell)) {
    323    presShell->ListComputedStyles(out);
    324  } else {
    325    fputs("null pres shell\n", out);
    326  }
    327 #endif
    328  return NS_OK;
    329 }
    330 
    331 NS_IMETHODIMP
    332 nsLayoutDebuggingTools::DumpReflowStats() {
    333  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    334 #ifdef DEBUG
    335  if (RefPtr<PresShell> presShell = GetPresShell(mDocShell)) {
    336 #  ifdef MOZ_REFLOW_PERF
    337    presShell->DumpReflows();
    338 #  else
    339    printf("************************************************\n");
    340    printf("Sorry, you have not built with MOZ_REFLOW_PERF=1\n");
    341    printf("************************************************\n");
    342 #  endif
    343  }
    344 #endif
    345  return NS_OK;
    346 }
    347 
    348 nsresult nsLayoutDebuggingTools::ForceRefresh() {
    349  return NS_ERROR_NOT_IMPLEMENTED;
    350 }
    351 
    352 nsresult nsLayoutDebuggingTools::SetBoolPrefAndRefresh(const char* aPrefName,
    353                                                       bool aNewVal) {
    354  NS_ENSURE_TRUE(mDocShell, NS_ERROR_NOT_INITIALIZED);
    355 
    356  nsIPrefService* prefService = Preferences::GetService();
    357  NS_ENSURE_TRUE(prefService && aPrefName, NS_OK);
    358 
    359  Preferences::SetBool(aPrefName, aNewVal);
    360  prefService->SavePrefFile(nullptr);
    361 
    362  ForceRefresh();
    363 
    364  return NS_OK;
    365 }