Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/base/nsLayoutDebugger.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; 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
/*
8
 * implementation of interface that allows layout-debug extension access
9
 * to some internals of layout
10
 */
11
12
#include "nsILayoutDebugger.h"
13
14
#include "nsAttrValue.h"
15
#include "nsFrame.h"
16
#include "nsDisplayList.h"
17
#include "FrameLayerBuilder.h"
18
#include "nsPrintfCString.h"
19
20
#include <stdio.h>
21
22
using namespace mozilla;
23
using namespace mozilla::layers;
24
25
#ifdef DEBUG
26
class nsLayoutDebugger : public nsILayoutDebugger {
27
public:
28
  nsLayoutDebugger();
29
30
  NS_DECL_ISUPPORTS
31
32
  NS_IMETHOD SetShowFrameBorders(bool aEnable) override;
33
34
  NS_IMETHOD GetShowFrameBorders(bool* aResult) override;
35
36
  NS_IMETHOD SetShowEventTargetFrameBorder(bool aEnable) override;
37
38
  NS_IMETHOD GetShowEventTargetFrameBorder(bool* aResult) override;
39
40
protected:
41
  virtual ~nsLayoutDebugger();
42
};
43
44
nsresult
45
NS_NewLayoutDebugger(nsILayoutDebugger** aResult)
46
{
47
  MOZ_ASSERT(aResult, "null OUT ptr");
48
  if (!aResult) {
49
    return NS_ERROR_NULL_POINTER;
50
  }
51
  nsLayoutDebugger* it = new nsLayoutDebugger();
52
  return it->QueryInterface(NS_GET_IID(nsILayoutDebugger), (void**)aResult);
53
}
54
55
nsLayoutDebugger::nsLayoutDebugger()
56
{
57
}
58
59
nsLayoutDebugger::~nsLayoutDebugger()
60
{
61
}
62
63
NS_IMPL_ISUPPORTS(nsLayoutDebugger, nsILayoutDebugger)
64
65
NS_IMETHODIMP
66
nsLayoutDebugger::SetShowFrameBorders(bool aEnable)
67
{
68
  nsFrame::ShowFrameBorders(aEnable);
69
  return NS_OK;
70
}
71
72
NS_IMETHODIMP
73
nsLayoutDebugger::GetShowFrameBorders(bool* aResult)
74
{
75
  *aResult = nsFrame::GetShowFrameBorders();
76
  return NS_OK;
77
}
78
79
NS_IMETHODIMP
80
nsLayoutDebugger::SetShowEventTargetFrameBorder(bool aEnable)
81
{
82
  nsFrame::ShowEventTargetFrameBorder(aEnable);
83
  return NS_OK;
84
}
85
86
NS_IMETHODIMP
87
nsLayoutDebugger::GetShowEventTargetFrameBorder(bool* aResult)
88
{
89
  *aResult = nsFrame::GetShowEventTargetFrameBorder();
90
  return NS_OK;
91
}
92
93
#endif
94
95
static std::ostream&
96
operator<<(std::ostream& os, const nsPrintfCString& rhs)
97
0
{
98
0
  os << rhs.get();
99
0
  return os;
100
0
}
101
102
static void
103
PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
104
                   std::stringstream& aStream, uint32_t aIndent, bool aDumpHtml);
105
106
static void
107
PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
108
                   std::stringstream& aStream, uint32_t aIndent, bool aDumpSublist, bool aDumpHtml)
109
0
{
110
0
  std::stringstream ss;
111
0
112
0
  if (!aDumpHtml) {
113
0
    for (uint32_t indent = 0; indent < aIndent; indent++) {
114
0
      aStream << "  ";
115
0
    }
116
0
  }
117
0
  nsAutoString contentData;
118
0
  nsIFrame* f = aItem->Frame();
119
#ifdef DEBUG_FRAME_DUMP
120
  f->GetFrameName(contentData);
121
#endif
122
  nsIContent* content = f->GetContent();
123
0
  if (content) {
124
0
    nsString tmp;
125
0
    if (content->GetID()) {
126
0
      content->GetID()->ToString(tmp);
127
0
      contentData.AppendLiteral(" id:");
128
0
      contentData.Append(tmp);
129
0
    }
130
0
    const nsAttrValue* classes = content->IsElement() ?
131
0
      content->AsElement()->GetClasses() : nullptr;
132
0
    if (classes) {
133
0
      classes->ToString(tmp);
134
0
      contentData.AppendLiteral(" class:");
135
0
      contentData.Append(tmp);
136
0
    }
137
0
  }
138
0
  bool snap;
139
0
  nsRect rect = aItem->GetBounds(aBuilder, &snap);
140
0
  nsRect layerRect = rect - (*aItem->GetAnimatedGeometryRoot())->GetOffsetToCrossDoc(aItem->ReferenceFrame());
141
0
  nsRect vis = aItem->GetPaintRect();
142
0
  nsRect build = aItem->GetBuildingRect();
143
0
  nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
144
0
  nsDisplayList* list = aItem->GetChildren();
145
0
  const DisplayItemClip& clip = aItem->GetClip();
146
0
  nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
147
0
148
#ifdef MOZ_DUMP_PAINTING
149
  if (aDumpHtml && aItem->Painted()) {
150
    nsCString string(aItem->Name());
151
    string.Append('-');
152
    string.AppendInt((uint64_t)aItem);
153
    aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
154
  }
155
#endif
156
157
0
  aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) key=%d %sbounds(%d,%d,%d,%d) layerBounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) building(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) asr(%s) clipChain(%s)%s ref=0x%p agr=0x%p",
158
0
          aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(contentData).get(), aItem->GetPerFrameKey(),
159
0
          (aItem->ZIndex() ? nsPrintfCString("z=%d ", aItem->ZIndex()).get() : ""),
160
0
          rect.x, rect.y, rect.width, rect.height,
161
0
          layerRect.x, layerRect.y, layerRect.width, layerRect.height,
162
0
          vis.x, vis.y, vis.width, vis.height,
163
0
          build.x, build.y, build.width, build.height,
164
0
          component.x, component.y, component.width, component.height,
165
0
          clip.ToString().get(),
166
0
          ActiveScrolledRoot::ToString(aItem->GetActiveScrolledRoot()).get(),
167
0
          DisplayItemClipChain::ToString(aItem->GetClipChain()).get(),
168
0
          aItem->IsUniform(aBuilder) ? " uniform" : "",
169
0
          aItem->ReferenceFrame(), aItem->GetAnimatedGeometryRoot()->mFrame);
170
0
171
0
  for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
172
0
    const nsRect& r = iter.Get();
173
0
    aStream << nsPrintfCString(" (opaque %d,%d,%d,%d)", r.x, r.y, r.width, r.height);
174
0
  }
175
0
176
0
  const auto& willChange = aItem->Frame()->StyleDisplay()->mWillChange;
177
0
  if (!willChange.IsEmpty()) {
178
0
    aStream << " (will-change=";
179
0
    for (size_t i = 0; i < willChange.Length(); i++) {
180
0
      if (i > 0) {
181
0
        aStream << ",";
182
0
      }
183
0
      nsDependentAtomString buffer(willChange[i]);
184
0
      aStream << NS_LossyConvertUTF16toASCII(buffer).get();
185
0
    }
186
0
    aStream << ")";
187
0
  }
188
0
189
0
  // Display item specific debug info
190
0
  aItem->WriteDebugInfo(aStream);
191
0
192
#ifdef MOZ_DUMP_PAINTING
193
  if (aDumpHtml && aItem->Painted()) {
194
    aStream << "</a>";
195
  }
196
#endif
197
  DisplayItemData* data = mozilla::FrameLayerBuilder::GetOldDataFor(aItem);
198
0
  if (data && data->GetLayer()) {
199
0
    if (aDumpHtml) {
200
0
      aStream << nsPrintfCString(" <a href=\"#%p\">layer=%p</a>", data->GetLayer(), data->GetLayer());
201
0
    } else {
202
0
      aStream << nsPrintfCString(" layer=0x%p", data->GetLayer());
203
0
    }
204
0
  }
205
#ifdef MOZ_DUMP_PAINTING
206
  if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
207
    nsCString str;
208
    (static_cast<nsDisplayMask*>(aItem))->PrintEffects(str);
209
    aStream << str.get();
210
  }
211
212
  if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
213
    nsCString str;
214
    (static_cast<nsDisplayFilter*>(aItem))->PrintEffects(str);
215
    aStream << str.get();
216
  }
217
#endif
218
  aStream << "\n";
219
#ifdef MOZ_DUMP_PAINTING
220
  if (aDumpHtml && aItem->Painted()) {
221
    nsCString string(aItem->Name());
222
    string.Append('-');
223
    string.AppendInt((uint64_t)aItem);
224
    aStream << nsPrintfCString("<br><img id=\"%s\">\n", string.BeginReading());
225
  }
226
#endif
227
228
0
  if (aDumpSublist && list) {
229
0
    PrintDisplayListTo(aBuilder, *list, aStream, aIndent+1, aDumpHtml);
230
0
  }
231
0
}
232
233
static void
234
PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
235
                   std::stringstream& aStream, uint32_t aIndent, bool aDumpHtml)
236
0
{
237
0
  if (aDumpHtml) {
238
0
    aStream << "<ul>";
239
0
  }
240
0
241
0
  for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
242
0
    if (aDumpHtml) {
243
0
      aStream << "<li>";
244
0
    }
245
0
    PrintDisplayItemTo(aBuilder, i, aStream, aIndent, true, aDumpHtml);
246
0
    if (aDumpHtml) {
247
0
      aStream << "</li>";
248
0
    }
249
0
  }
250
0
251
0
  if (aDumpHtml) {
252
0
    aStream << "</ul>";
253
0
  }
254
0
}
255
256
void
257
nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
258
                          const nsDisplayList& aList,
259
                          std::stringstream& aStream,
260
                          bool aDumpHtml)
261
0
{
262
0
  PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml);
263
0
}
264
265
void
266
nsFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder,
267
                          nsDisplayItem* aItem,
268
                          std::stringstream& aStream,
269
                          uint32_t aIndent,
270
                          bool aDumpSublist,
271
                          bool aDumpHtml)
272
0
{
273
0
  PrintDisplayItemTo(aBuilder, aItem, aStream, aIndent, aDumpSublist, aDumpHtml);
274
0
}
275
276
/**
277
 * The two functions below are intended to be called from a debugger.
278
 */
279
void
280
PrintDisplayItemToStdout(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
281
0
{
282
0
  std::stringstream stream;
283
0
  PrintDisplayItemTo(aBuilder, aItem, stream, 0, true, false);
284
0
  puts(stream.str().c_str());
285
0
}
286
287
void
288
PrintDisplayListToStdout(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList)
289
0
{
290
0
  std::stringstream stream;
291
0
  PrintDisplayListTo(aBuilder, aList, stream, 0, false);
292
0
  puts(stream.str().c_str());
293
0
}
294
295
#ifdef MOZ_DUMP_PAINTING
296
static void
297
PrintDisplayListSetItem(nsDisplayListBuilder* aBuilder,
298
                        const char* aItemName,
299
                        const nsDisplayList& aList,
300
                        std::stringstream& aStream,
301
                        bool aDumpHtml)
302
{
303
  if (aDumpHtml) {
304
    aStream << "<li>";
305
  }
306
  aStream << aItemName << "\n";
307
  PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml);
308
  if (aDumpHtml) {
309
    aStream << "</li>";
310
  }
311
}
312
313
void
314
nsFrame::PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
315
                             const nsDisplayListSet& aSet,
316
                             std::stringstream& aStream,
317
                             bool aDumpHtml)
318
{
319
  if (aDumpHtml) {
320
    aStream << "<ul>";
321
  }
322
  PrintDisplayListSetItem(aBuilder, "[BorderBackground]", *(aSet.BorderBackground()), aStream, aDumpHtml);
323
  PrintDisplayListSetItem(aBuilder, "[BlockBorderBackgrounds]", *(aSet.BlockBorderBackgrounds()), aStream, aDumpHtml);
324
  PrintDisplayListSetItem(aBuilder, "[Floats]", *(aSet.Floats()), aStream, aDumpHtml);
325
  PrintDisplayListSetItem(aBuilder, "[PositionedDescendants]", *(aSet.PositionedDescendants()), aStream, aDumpHtml);
326
  PrintDisplayListSetItem(aBuilder, "[Outlines]", *(aSet.Outlines()), aStream, aDumpHtml);
327
  PrintDisplayListSetItem(aBuilder, "[Content]", *(aSet.Content()), aStream, aDumpHtml);
328
  if (aDumpHtml) {
329
    aStream << "</ul>";
330
  }
331
}
332
333
#endif