nsLayoutDebugger.cpp (9535B)
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 /* some layout debugging functions that ought to live in nsFrame.cpp */ 8 9 #include <stdio.h> 10 11 #include "nsAttrValue.h" 12 #include "nsDisplayList.h" 13 #include "nsIFrame.h" 14 #include "nsPrintfCString.h" 15 16 using namespace mozilla; 17 using namespace mozilla::layers; 18 19 static std::ostream& operator<<(std::ostream& os, const nsPrintfCString& rhs) { 20 os << rhs.get(); 21 return os; 22 } 23 24 static void PrintDisplayListTo(nsDisplayListBuilder* aBuilder, 25 const nsDisplayList& aList, 26 std::stringstream& aStream, uint32_t aIndent, 27 bool aDumpHtml); 28 29 static void PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, 30 nsDisplayItem* aItem, std::stringstream& aStream, 31 uint32_t aIndent, bool aDumpSublist, 32 bool aDumpHtml) { 33 std::stringstream ss; 34 35 if (!aDumpHtml) { 36 for (uint32_t indent = 0; indent < aIndent; indent++) { 37 aStream << " "; 38 } 39 } 40 nsAutoString contentData; 41 nsIFrame* f = aItem->Frame(); 42 #ifdef DEBUG_FRAME_DUMP 43 f->GetFrameName(contentData); 44 #endif 45 nsIContent* content = f->GetContent(); 46 if (content) { 47 nsString tmp; 48 if (content->GetID()) { 49 content->GetID()->ToString(tmp); 50 contentData.AppendLiteral(" id:"); 51 contentData.Append(tmp); 52 } 53 const nsAttrValue* classes = 54 content->IsElement() ? content->AsElement()->GetClasses() : nullptr; 55 if (classes) { 56 classes->ToString(tmp); 57 contentData.AppendLiteral(" class:"); 58 contentData.Append(tmp); 59 } 60 } 61 bool snap; 62 nsRect rect = aBuilder ? aItem->GetBounds(aBuilder, &snap) : nsRect(); 63 nsRect component = 64 aBuilder ? aItem->GetComponentAlphaBounds(aBuilder) : nsRect(); 65 nsDisplayList* list = aItem->GetChildren(); 66 const DisplayItemClip& clip = aItem->GetClip(); 67 nsRegion opaque = 68 aBuilder ? aItem->GetOpaqueRegion(aBuilder, &snap) : nsRect(); 69 70 #ifdef MOZ_DUMP_PAINTING 71 if (aDumpHtml && aItem->Painted()) { 72 nsCString string(aItem->Name()); 73 string.Append('-'); 74 string.AppendInt((uint64_t)aItem); 75 aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", 76 string.BeginReading()); 77 } 78 #endif 79 80 aStream << nsPrintfCString( 81 "%s p=0x%p f=0x%p(%s) key=%d %sbounds(%d,%d,%d,%d) " 82 "componentAlpha(%d,%d,%d,%d) clip(%s) asr(%s) clipChain(%s)%s ", 83 aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(contentData).get(), 84 aItem->GetPerFrameKey(), 85 (aItem->ZIndex() ? nsPrintfCString("z=%d ", aItem->ZIndex()).get() : ""), 86 rect.x, rect.y, rect.width, rect.height, component.x, component.y, 87 component.width, component.height, clip.ToString().get(), 88 ActiveScrolledRoot::ToString(aItem->GetActiveScrolledRoot()).get(), 89 DisplayItemClipChain::ToString(aItem->GetClipChain()).get(), 90 (aBuilder && aItem->IsUniform(aBuilder)) ? " uniform" : ""); 91 92 for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) { 93 const nsRect& r = iter.Get(); 94 aStream << nsPrintfCString(" (opaque %d,%d,%d,%d)", r.x, r.y, r.width, 95 r.height); 96 } 97 98 const auto& willChange = aItem->Frame()->StyleDisplay()->mWillChange; 99 if (!willChange.features.IsEmpty()) { 100 aStream << " (will-change="; 101 for (size_t i = 0; i < willChange.features.Length(); i++) { 102 if (i > 0) { 103 aStream << ","; 104 } 105 nsDependentAtomString buffer(willChange.features.AsSpan()[i].AsAtom()); 106 aStream << NS_LossyConvertUTF16toASCII(buffer).get(); 107 } 108 aStream << ")"; 109 } 110 111 if (aItem->HasHitTestInfo()) { 112 const auto& hitTestInfo = aItem->GetHitTestInfo(); 113 aStream << nsPrintfCString(" hitTestInfo(0x%x)", 114 hitTestInfo.Info().serialize()); 115 116 nsRect area = hitTestInfo.Area(); 117 aStream << nsPrintfCString(" hitTestArea(%d,%d,%d,%d)", area.x, area.y, 118 area.width, area.height); 119 } 120 121 auto ReuseStateToString = [](nsDisplayItem::ReuseState aState) { 122 switch (aState) { 123 case nsDisplayItem::ReuseState::None: 124 return "None"; 125 case nsDisplayItem::ReuseState::Reusable: 126 return "Reusable"; 127 case nsDisplayItem::ReuseState::PreProcessed: 128 return "PreProcessed"; 129 case nsDisplayItem::ReuseState::Reused: 130 return "Reused"; 131 } 132 133 MOZ_ASSERT_UNREACHABLE(); 134 return ""; 135 }; 136 137 aStream << nsPrintfCString(" reuse-state(%s)", 138 ReuseStateToString(aItem->GetReuseState())); 139 140 // Display item specific debug info 141 aItem->WriteDebugInfo(aStream); 142 143 #ifdef MOZ_DUMP_PAINTING 144 if (aDumpHtml && aItem->Painted()) { 145 aStream << "</a>"; 146 } 147 #endif 148 #ifdef MOZ_DUMP_PAINTING 149 if (aItem->GetType() == DisplayItemType::TYPE_MASK) { 150 nsCString str; 151 (static_cast<nsDisplayMasksAndClipPaths*>(aItem))->PrintEffects(str); 152 aStream << str.get(); 153 } 154 155 if (aItem->GetType() == DisplayItemType::TYPE_FILTER) { 156 nsCString str; 157 (static_cast<nsDisplayFilters*>(aItem))->PrintEffects(str); 158 aStream << str.get(); 159 } 160 #endif 161 aStream << "\n"; 162 #ifdef MOZ_DUMP_PAINTING 163 if (aDumpHtml && aItem->Painted()) { 164 nsCString string(aItem->Name()); 165 string.Append('-'); 166 string.AppendInt((uint64_t)aItem); 167 aStream << nsPrintfCString("<br><img id=\"%s\">\n", string.BeginReading()); 168 } 169 #endif 170 171 if (aDumpSublist && list) { 172 PrintDisplayListTo(aBuilder, *list, aStream, aIndent + 1, aDumpHtml); 173 } 174 } 175 176 static void PrintDisplayListTo(nsDisplayListBuilder* aBuilder, 177 const nsDisplayList& aList, 178 std::stringstream& aStream, uint32_t aIndent, 179 bool aDumpHtml) { 180 if (aDumpHtml) { 181 aStream << "<ul>"; 182 } 183 184 for (nsDisplayItem* i : aList) { 185 if (aDumpHtml) { 186 aStream << "<li>"; 187 } 188 PrintDisplayItemTo(aBuilder, i, aStream, aIndent, true, aDumpHtml); 189 if (aDumpHtml) { 190 aStream << "</li>"; 191 } 192 } 193 194 if (aDumpHtml) { 195 aStream << "</ul>"; 196 } 197 } 198 199 void nsIFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder, 200 const nsDisplayList& aList, uint32_t aIndent, 201 bool aDumpHtml) { 202 std::stringstream ss; 203 PrintDisplayListTo(aBuilder, aList, ss, aIndent, aDumpHtml); 204 fprintf_stderr(stderr, "%s", ss.str().c_str()); 205 } 206 207 void nsIFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder, 208 const nsDisplayList& aList, 209 std::stringstream& aStream, bool aDumpHtml) { 210 PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml); 211 } 212 213 void nsIFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder, 214 nsDisplayItem* aItem, 215 std::stringstream& aStream, uint32_t aIndent, 216 bool aDumpSublist, bool aDumpHtml) { 217 PrintDisplayItemTo(aBuilder, aItem, aStream, aIndent, aDumpSublist, 218 aDumpHtml); 219 } 220 221 /** 222 * The two functions below are intended to be called from a debugger. 223 */ 224 void PrintDisplayItemToStdout(nsDisplayListBuilder* aBuilder, 225 nsDisplayItem* aItem) { 226 std::stringstream stream; 227 PrintDisplayItemTo(aBuilder, aItem, stream, 0, true, false); 228 puts(stream.str().c_str()); 229 } 230 231 void PrintDisplayListToStdout(nsDisplayListBuilder* aBuilder, 232 const nsDisplayList& aList) { 233 std::stringstream stream; 234 PrintDisplayListTo(aBuilder, aList, stream, 0, false); 235 puts(stream.str().c_str()); 236 } 237 238 #ifdef MOZ_DUMP_PAINTING 239 static void PrintDisplayListSetItem(nsDisplayListBuilder* aBuilder, 240 const char* aItemName, 241 const nsDisplayList& aList, 242 std::stringstream& aStream, 243 bool aDumpHtml) { 244 if (aDumpHtml) { 245 aStream << "<li>"; 246 } 247 aStream << aItemName << "\n"; 248 PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml); 249 if (aDumpHtml) { 250 aStream << "</li>"; 251 } 252 } 253 254 void nsIFrame::PrintDisplayListSet(nsDisplayListBuilder* aBuilder, 255 const nsDisplayListSet& aSet, 256 std::stringstream& aStream, bool aDumpHtml) { 257 if (aDumpHtml) { 258 aStream << "<ul>"; 259 } 260 PrintDisplayListSetItem(aBuilder, "[BorderBackground]", 261 *(aSet.BorderBackground()), aStream, aDumpHtml); 262 PrintDisplayListSetItem(aBuilder, "[BlockBorderBackgrounds]", 263 *(aSet.BlockBorderBackgrounds()), aStream, aDumpHtml); 264 PrintDisplayListSetItem(aBuilder, "[Floats]", *(aSet.Floats()), aStream, 265 aDumpHtml); 266 PrintDisplayListSetItem(aBuilder, "[PositionedDescendants]", 267 *(aSet.PositionedDescendants()), aStream, aDumpHtml); 268 PrintDisplayListSetItem(aBuilder, "[Outlines]", *(aSet.Outlines()), aStream, 269 aDumpHtml); 270 PrintDisplayListSetItem(aBuilder, "[Content]", *(aSet.Content()), aStream, 271 aDumpHtml); 272 if (aDumpHtml) { 273 aStream << "</ul>"; 274 } 275 } 276 277 #endif