Logging.cpp (30487B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "Logging.h" 8 9 #include "LocalAccessible-inl.h" 10 #include "AccEvent.h" 11 #include "DocAccessible.h" 12 #include "DocAccessible-inl.h" 13 #include "nsAccessibilityService.h" 14 #include "nsCoreUtils.h" 15 #include "OuterDocAccessible.h" 16 17 #include "nsDocShellLoadTypes.h" 18 #include "nsIChannel.h" 19 #include "nsIWebProgress.h" 20 #include "prenv.h" 21 #include "nsIDocShellTreeItem.h" 22 #include "mozilla/Maybe.h" 23 #include "mozilla/PresShell.h" 24 #include "mozilla/ScrollContainerFrame.h" 25 #include "mozilla/StackWalk.h" 26 #include "mozilla/ToString.h" 27 #include "mozilla/dom/BorrowedAttrInfo.h" 28 #include "mozilla/dom/Document.h" 29 #include "mozilla/dom/Element.h" 30 #include "mozilla/dom/HTMLBodyElement.h" 31 #include "mozilla/dom/Selection.h" 32 33 using namespace mozilla; 34 using namespace mozilla::a11y; 35 36 using mozilla::dom::BorrowedAttrInfo; 37 38 MOZ_DEFINE_MALLOC_SIZE_OF(AccessibleLoggingMallocSizeOf) 39 40 //////////////////////////////////////////////////////////////////////////////// 41 // Logging helpers 42 43 static uint32_t sModules = 0; 44 45 struct ModuleRep { 46 const char* mStr; 47 logging::EModules mModule; 48 }; 49 50 static ModuleRep sModuleMap[] = {{"docload", logging::eDocLoad}, 51 {"doccreate", logging::eDocCreate}, 52 {"docdestroy", logging::eDocDestroy}, 53 {"doclifecycle", logging::eDocLifeCycle}, 54 55 {"events", logging::eEvents}, 56 {"platforms", logging::ePlatforms}, 57 {"text", logging::eText}, 58 {"tree", logging::eTree}, 59 {"treeSize", logging::eTreeSize}, 60 61 {"DOMEvents", logging::eDOMEvents}, 62 {"focus", logging::eFocus}, 63 {"selection", logging::eSelection}, 64 {"notifications", logging::eNotifications}, 65 66 {"stack", logging::eStack}, 67 {"verbose", logging::eVerbose}, 68 {"cache", logging::eCache}}; 69 70 static void EnableLogging(const char* aModulesStr) { 71 sModules = 0; 72 if (!aModulesStr) return; 73 74 const char* token = aModulesStr; 75 while (*token != '\0') { 76 size_t tokenLen = strcspn(token, ","); 77 for (unsigned int idx = 0; idx < std::size(sModuleMap); idx++) { 78 if (strncmp(token, sModuleMap[idx].mStr, tokenLen) == 0) { 79 #if !defined(MOZ_PROFILING) && (!defined(DEBUG) || defined(MOZ_OPTIMIZE)) 80 // Stack tracing on profiling enabled or debug not optimized builds. 81 if (strncmp(token, "stack", tokenLen) == 0) break; 82 #endif 83 sModules |= sModuleMap[idx].mModule; 84 printf("\n\nmodule enabled: %s\n", sModuleMap[idx].mStr); 85 break; 86 } 87 } 88 token += tokenLen; 89 90 if (*token == ',') token++; // skip ',' char 91 } 92 } 93 94 static void LogDocURI(dom::Document* aDocumentNode) { 95 nsIURI* uri = aDocumentNode->GetDocumentURI(); 96 if (uri) { 97 printf("uri: %s", uri->GetSpecOrDefault().get()); 98 } else { 99 printf("uri: null"); 100 } 101 } 102 103 static void LogDocShellState(dom::Document* aDocumentNode) { 104 printf("docshell busy: "); 105 nsCOMPtr<nsIDocShell> docShell = aDocumentNode->GetDocShell(); 106 if (!docShell) { 107 printf("null docshell"); 108 return; 109 } 110 111 nsAutoCString docShellBusy; 112 nsIDocShell::BusyFlags busyFlags = nsIDocShell::BUSY_FLAGS_NONE; 113 docShell->GetBusyFlags(&busyFlags); 114 if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) { 115 printf("'none'"); 116 } 117 if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) { 118 printf("'busy'"); 119 } 120 if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) { 121 printf(", 'before page load'"); 122 } 123 if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) { 124 printf(", 'page loading'"); 125 } 126 } 127 128 static void LogDocType(dom::Document* aDocumentNode) { 129 if (aDocumentNode->IsActive()) { 130 bool isContent = aDocumentNode->IsContentDocument(); 131 printf("%s document", (isContent ? "content" : "chrome")); 132 } else { 133 printf("document type: [failed]"); 134 } 135 } 136 137 static void LogDocShellTree(dom::Document* aDocumentNode) { 138 if (aDocumentNode->IsActive()) { 139 nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell()); 140 if (!treeItem) { 141 printf("in-process docshell hierarchy, null docshell;"); 142 return; 143 } 144 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; 145 treeItem->GetInProcessParent(getter_AddRefs(parentTreeItem)); 146 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; 147 treeItem->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem)); 148 printf( 149 "in-process docshell hierarchy, parent: %p, root: %p, " 150 "is top level: %s;", 151 static_cast<void*>(parentTreeItem), static_cast<void*>(rootTreeItem), 152 (nsCoreUtils::IsTopLevelContentDocInProcess(aDocumentNode) ? "yes" 153 : "no")); 154 } 155 } 156 157 static void LogDocState(dom::Document* aDocumentNode) { 158 const char* docState = nullptr; 159 dom::Document::ReadyState docStateFlag = aDocumentNode->GetReadyStateEnum(); 160 switch (docStateFlag) { 161 case dom::Document::READYSTATE_UNINITIALIZED: 162 docState = "uninitialized"; 163 break; 164 case dom::Document::READYSTATE_LOADING: 165 docState = "loading"; 166 break; 167 case dom::Document::READYSTATE_INTERACTIVE: 168 docState = "interactive"; 169 break; 170 case dom::Document::READYSTATE_COMPLETE: 171 docState = "complete"; 172 break; 173 } 174 175 printf("doc state: %s", docState); 176 printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not "); 177 printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not "); 178 printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not "); 179 printf( 180 ", %svisible considering ancestors", 181 nsCoreUtils::IsDocumentVisibleConsideringInProcessAncestors(aDocumentNode) 182 ? "" 183 : "not "); 184 printf(", %sactive", aDocumentNode->IsActive() ? "" : "not "); 185 printf(", %sresource", aDocumentNode->IsResourceDoc() ? "" : "not "); 186 187 dom::Element* rootEl = aDocumentNode->GetBodyElement(); 188 if (!rootEl) { 189 rootEl = aDocumentNode->GetRootElement(); 190 } 191 printf(", has %srole content", rootEl ? "" : "no "); 192 } 193 194 static void LogPresShell(dom::Document* aDocumentNode) { 195 PresShell* presShell = aDocumentNode->GetPresShell(); 196 printf("presshell: %p", static_cast<void*>(presShell)); 197 198 ScrollContainerFrame* sf = nullptr; 199 if (presShell) { 200 printf(", is %s destroying", (presShell->IsDestroying() ? "" : "not")); 201 sf = presShell->GetRootScrollContainerFrame(); 202 } 203 printf(", root scroll container frame: %p", static_cast<void*>(sf)); 204 } 205 206 static void LogDocLoadGroup(dom::Document* aDocumentNode) { 207 nsCOMPtr<nsILoadGroup> loadGroup = aDocumentNode->GetDocumentLoadGroup(); 208 printf("load group: %p", static_cast<void*>(loadGroup)); 209 } 210 211 static void LogDocParent(dom::Document* aDocumentNode) { 212 dom::Document* parentDoc = aDocumentNode->GetInProcessParentDocument(); 213 printf("parent DOM document: %p", static_cast<void*>(parentDoc)); 214 if (parentDoc) { 215 printf(", parent acc document: %p", 216 static_cast<void*>(GetExistingDocAccessible(parentDoc))); 217 printf("\n parent "); 218 LogDocURI(parentDoc); 219 printf("\n"); 220 } 221 } 222 223 static void LogDocInfo(dom::Document* aDocumentNode, DocAccessible* aDocument) { 224 printf(" DOM document: %p, acc document: %p\n ", 225 static_cast<void*>(aDocumentNode), static_cast<void*>(aDocument)); 226 227 // log document info 228 if (aDocumentNode) { 229 LogDocURI(aDocumentNode); 230 printf("\n "); 231 LogDocShellState(aDocumentNode); 232 printf("; "); 233 LogDocType(aDocumentNode); 234 printf("\n "); 235 LogDocShellTree(aDocumentNode); 236 printf("\n "); 237 LogDocState(aDocumentNode); 238 printf("\n "); 239 LogPresShell(aDocumentNode); 240 printf("\n "); 241 LogDocLoadGroup(aDocumentNode); 242 printf(", "); 243 LogDocParent(aDocumentNode); 244 printf("\n"); 245 } 246 } 247 248 static void LogShellLoadType(nsIDocShell* aDocShell) { 249 printf("load type: "); 250 251 uint32_t loadType = 0; 252 aDocShell->GetLoadType(&loadType); 253 switch (loadType) { 254 case LOAD_NORMAL: 255 printf("normal; "); 256 break; 257 case LOAD_NORMAL_REPLACE: 258 printf("normal replace; "); 259 break; 260 case LOAD_HISTORY: 261 printf("history; "); 262 break; 263 case LOAD_NORMAL_BYPASS_CACHE: 264 printf("normal bypass cache; "); 265 break; 266 case LOAD_NORMAL_BYPASS_PROXY: 267 printf("normal bypass proxy; "); 268 break; 269 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: 270 printf("normal bypass proxy and cache; "); 271 break; 272 case LOAD_RELOAD_NORMAL: 273 printf("reload normal; "); 274 break; 275 case LOAD_RELOAD_BYPASS_CACHE: 276 printf("reload bypass cache; "); 277 break; 278 case LOAD_RELOAD_BYPASS_PROXY: 279 printf("reload bypass proxy; "); 280 break; 281 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: 282 printf("reload bypass proxy and cache; "); 283 break; 284 case LOAD_LINK: 285 printf("link; "); 286 break; 287 case LOAD_REFRESH: 288 printf("refresh; "); 289 break; 290 case LOAD_REFRESH_REPLACE: 291 printf("refresh replace; "); 292 break; 293 case LOAD_RELOAD_CHARSET_CHANGE: 294 printf("reload charset change; "); 295 break; 296 case LOAD_BYPASS_HISTORY: 297 printf("bypass history; "); 298 break; 299 case LOAD_STOP_CONTENT: 300 printf("stop content; "); 301 break; 302 case LOAD_STOP_CONTENT_AND_REPLACE: 303 printf("stop content and replace; "); 304 break; 305 case LOAD_PUSHSTATE: 306 printf("load pushstate; "); 307 break; 308 case LOAD_REPLACE_BYPASS_CACHE: 309 printf("replace bypass cache; "); 310 break; 311 case LOAD_ERROR_PAGE: 312 printf("error page;"); 313 break; 314 default: 315 printf("unknown"); 316 } 317 } 318 319 static void LogRequest(nsIRequest* aRequest) { 320 if (aRequest) { 321 nsAutoCString name; 322 aRequest->GetName(name); 323 printf(" request spec: %s\n", name.get()); 324 uint32_t loadFlags = 0; 325 aRequest->GetLoadFlags(&loadFlags); 326 printf(" request load flags: %x; ", loadFlags); 327 if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) printf("document uri; "); 328 if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) { 329 printf("retargeted document uri; "); 330 } 331 if (loadFlags & nsIChannel::LOAD_REPLACE) printf("replace; "); 332 if (loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI) { 333 printf("initial document uri; "); 334 } 335 if (loadFlags & nsIChannel::LOAD_TARGETED) printf("targeted; "); 336 if (loadFlags & nsIChannel::LOAD_CALL_CONTENT_SNIFFERS) { 337 printf("call content sniffers; "); 338 } 339 if (loadFlags & nsIChannel::LOAD_BYPASS_URL_CLASSIFIER) { 340 printf("bypass classify uri; "); 341 } 342 } else { 343 printf(" no request"); 344 } 345 } 346 347 static void LogDocAccState(DocAccessible* aDocument) { 348 printf("document acc state: "); 349 if (aDocument->HasLoadState(DocAccessible::eCompletelyLoaded)) { 350 printf("completely loaded;"); 351 } else if (aDocument->HasLoadState(DocAccessible::eReady)) { 352 printf("ready;"); 353 } else if (aDocument->HasLoadState(DocAccessible::eDOMLoaded)) { 354 printf("DOM loaded;"); 355 } else if (aDocument->HasLoadState(DocAccessible::eTreeConstructed)) { 356 printf("tree constructed;"); 357 } 358 } 359 360 static void GetDocLoadEventType(AccEvent* aEvent, nsACString& aEventType) { 361 uint32_t type = aEvent->GetEventType(); 362 if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED) { 363 aEventType.AssignLiteral("load stopped"); 364 } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) { 365 aEventType.AssignLiteral("load complete"); 366 } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD) { 367 aEventType.AssignLiteral("reload"); 368 } else if (type == nsIAccessibleEvent::EVENT_STATE_CHANGE) { 369 AccStateChangeEvent* event = downcast_accEvent(aEvent); 370 if (event->GetState() == states::BUSY) { 371 aEventType.AssignLiteral("busy "); 372 if (event->IsStateEnabled()) { 373 aEventType.AppendLiteral("true"); 374 } else { 375 aEventType.AppendLiteral("false"); 376 } 377 } 378 } 379 } 380 381 static void DescribeNode(nsINode* aNode, nsAString& aOutDescription) { 382 if (!aNode) { 383 aOutDescription.AppendLiteral("null"); 384 return; 385 } 386 387 aOutDescription.AppendPrintf("0x%p, ", (void*)aNode); 388 aOutDescription.Append(aNode->NodeInfo()->QualifiedName()); 389 390 if (!aNode->IsElement()) { 391 return; 392 } 393 394 dom::Element* elm = aNode->AsElement(); 395 396 nsAtom* idAtom = elm->GetID(); 397 if (idAtom) { 398 nsAutoCString id; 399 idAtom->ToUTF8String(id); 400 aOutDescription.AppendPrintf("@id=\"%s\" ", id.get()); 401 } else { 402 aOutDescription.Append(' '); 403 } 404 405 uint32_t attrCount = elm->GetAttrCount(); 406 if (!attrCount || (idAtom && attrCount == 1)) { 407 return; 408 } 409 410 aOutDescription.AppendLiteral("[ "); 411 412 for (uint32_t index = 0; index < attrCount; index++) { 413 BorrowedAttrInfo info = elm->GetAttrInfoAt(index); 414 415 // Skip redundant display of id attribute. 416 if (info.mName->Equals(nsGkAtoms::id)) { 417 continue; 418 } 419 420 // name 421 nsAutoString name; 422 info.mName->GetQualifiedName(name); 423 aOutDescription.Append(name); 424 425 aOutDescription.AppendLiteral("=\""); 426 427 // value 428 nsAutoString value; 429 info.mValue->ToString(value); 430 for (uint32_t i = value.Length(); i > 0; --i) { 431 if (value[i - 1] == char16_t('"')) value.Insert(char16_t('\\'), i - 1); 432 } 433 aOutDescription.Append(value); 434 aOutDescription.AppendLiteral("\" "); 435 } 436 437 aOutDescription.Append(']'); 438 } 439 440 //////////////////////////////////////////////////////////////////////////////// 441 // namespace logging:: document life cycle logging methods 442 443 static const char* sDocLoadTitle = "DOCLOAD"; 444 static const char* sDocCreateTitle = "DOCCREATE"; 445 static const char* sDocDestroyTitle = "DOCDESTROY"; 446 static const char* sDocEventTitle = "DOCEVENT"; 447 static const char* sFocusTitle = "FOCUS"; 448 449 void logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress, 450 nsIRequest* aRequest, uint32_t aStateFlags) { 451 MsgBegin(sDocLoadTitle, "%s", aMsg); 452 453 nsCOMPtr<mozIDOMWindowProxy> DOMWindow; 454 aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow)); 455 nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow); 456 if (!window) { 457 MsgEnd(); 458 return; 459 } 460 461 nsCOMPtr<dom::Document> documentNode = window->GetDoc(); 462 if (!documentNode) { 463 MsgEnd(); 464 return; 465 } 466 467 DocAccessible* document = GetExistingDocAccessible(documentNode); 468 469 LogDocInfo(documentNode, document); 470 471 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell(); 472 printf("\n "); 473 LogShellLoadType(docShell); 474 printf("\n"); 475 LogRequest(aRequest); 476 printf("\n"); 477 printf(" state flags: %x", aStateFlags); 478 bool isDocLoading; 479 aWebProgress->GetIsLoadingDocument(&isDocLoading); 480 printf(", document is %sloading\n", (isDocLoading ? "" : "not ")); 481 482 MsgEnd(); 483 } 484 485 void logging::DocLoad(const char* aMsg, dom::Document* aDocumentNode) { 486 MsgBegin(sDocLoadTitle, "%s", aMsg); 487 488 DocAccessible* document = GetExistingDocAccessible(aDocumentNode); 489 LogDocInfo(aDocumentNode, document); 490 491 MsgEnd(); 492 } 493 494 void logging::DocCompleteLoad(DocAccessible* aDocument, 495 bool aIsLoadEventTarget) { 496 MsgBegin(sDocLoadTitle, "document loaded *completely*"); 497 498 printf(" DOM document: %p, acc document: %p\n", 499 static_cast<void*>(aDocument->DocumentNode()), 500 static_cast<void*>(aDocument)); 501 502 printf(" "); 503 LogDocURI(aDocument->DocumentNode()); 504 printf("\n"); 505 506 printf(" "); 507 LogDocAccState(aDocument); 508 printf("\n"); 509 510 printf(" document is load event target: %s\n", 511 (aIsLoadEventTarget ? "true" : "false")); 512 513 MsgEnd(); 514 } 515 516 void logging::DocLoadEventFired(AccEvent* aEvent) { 517 nsAutoCString strEventType; 518 GetDocLoadEventType(aEvent, strEventType); 519 if (!strEventType.IsEmpty()) printf(" fire: %s\n", strEventType.get()); 520 } 521 522 void logging::DocLoadEventHandled(AccEvent* aEvent) { 523 nsAutoCString strEventType; 524 GetDocLoadEventType(aEvent, strEventType); 525 if (strEventType.IsEmpty()) return; 526 527 MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get()); 528 529 DocAccessible* document = aEvent->GetAccessible()->AsDoc(); 530 if (document) LogDocInfo(document->DocumentNode(), document); 531 532 MsgEnd(); 533 } 534 535 void logging::DocCreate(const char* aMsg, dom::Document* aDocumentNode, 536 DocAccessible* aDocument) { 537 DocAccessible* document = 538 aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode); 539 540 MsgBegin(sDocCreateTitle, "%s", aMsg); 541 LogDocInfo(aDocumentNode, document); 542 MsgEnd(); 543 } 544 545 void logging::DocDestroy(const char* aMsg, dom::Document* aDocumentNode, 546 DocAccessible* aDocument) { 547 DocAccessible* document = 548 aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode); 549 550 MsgBegin(sDocDestroyTitle, "%s", aMsg); 551 LogDocInfo(aDocumentNode, document); 552 MsgEnd(); 553 } 554 555 void logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc) { 556 MsgBegin(sDocDestroyTitle, "outerdoc shutdown"); 557 logging::Address("outerdoc", aOuterDoc); 558 MsgEnd(); 559 } 560 561 void logging::FocusNotificationTarget(const char* aMsg, 562 const char* aTargetDescr, 563 LocalAccessible* aTarget) { 564 MsgBegin(sFocusTitle, "%s", aMsg); 565 AccessibleNNode(aTargetDescr, aTarget); 566 MsgEnd(); 567 } 568 569 void logging::FocusNotificationTarget(const char* aMsg, 570 const char* aTargetDescr, 571 nsINode* aTargetNode) { 572 MsgBegin(sFocusTitle, "%s", aMsg); 573 Node(aTargetDescr, aTargetNode); 574 MsgEnd(); 575 } 576 577 void logging::FocusNotificationTarget(const char* aMsg, 578 const char* aTargetDescr, 579 nsISupports* aTargetThing) { 580 MsgBegin(sFocusTitle, "%s", aMsg); 581 582 if (aTargetThing) { 583 nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTargetThing)); 584 if (targetNode) { 585 AccessibleNNode(aTargetDescr, targetNode); 586 } else { 587 printf(" %s: %p, window\n", aTargetDescr, 588 static_cast<void*>(aTargetThing)); 589 } 590 } 591 592 MsgEnd(); 593 } 594 595 void logging::ActiveItemChangeCausedBy(const char* aCause, 596 LocalAccessible* aTarget) { 597 SubMsgBegin(); 598 printf(" Caused by: %s\n", aCause); 599 AccessibleNNode("Item", aTarget); 600 SubMsgEnd(); 601 } 602 603 void logging::ActiveWidget(LocalAccessible* aWidget) { 604 SubMsgBegin(); 605 606 AccessibleNNode("Widget", aWidget); 607 printf(" Widget is active: %s, has operable items: %s\n", 608 (aWidget && aWidget->IsActiveWidget() ? "true" : "false"), 609 (aWidget && aWidget->AreItemsOperable() ? "true" : "false")); 610 611 SubMsgEnd(); 612 } 613 614 void logging::FocusDispatched(LocalAccessible* aTarget) { 615 SubMsgBegin(); 616 AccessibleNNode("A11y target", aTarget); 617 SubMsgEnd(); 618 } 619 620 void logging::SelChange(dom::Selection* aSelection, DocAccessible* aDocument, 621 int16_t aReason) { 622 SelectionType type = aSelection->GetType(); 623 624 const char* strType = 0; 625 if (type == SelectionType::eNormal) { 626 strType = "normal"; 627 } else if (type == SelectionType::eSpellCheck) { 628 strType = "spellcheck"; 629 } else { 630 strType = "unknown"; 631 } 632 633 bool isIgnored = !aDocument || !aDocument->IsContentLoaded(); 634 printf( 635 "\nSelection changed, selection type: %s, notification %s, reason: %d\n", 636 strType, (isIgnored ? "ignored" : "pending"), aReason); 637 638 Stack(); 639 } 640 641 void logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...) { 642 if (IsEnabledAll(logging::eTree | aExtraFlags)) { 643 va_list vl; 644 va_start(vl, aExtraFlags); 645 const char* descr = va_arg(vl, const char*); 646 if (descr) { 647 LocalAccessible* acc = va_arg(vl, LocalAccessible*); 648 MsgBegin("TREE", "%s; doc: %p", aMsg, acc ? acc->Document() : nullptr); 649 AccessibleInfo(descr, acc); 650 while ((descr = va_arg(vl, const char*))) { 651 AccessibleInfo(descr, va_arg(vl, LocalAccessible*)); 652 } 653 } else { 654 MsgBegin("TREE", "%s", aMsg); 655 } 656 va_end(vl); 657 MsgEnd(); 658 659 if (aExtraFlags & eStack) { 660 Stack(); 661 } 662 } 663 } 664 665 void logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, 666 const char* aMsg1, LocalAccessible* aAcc, 667 const char* aMsg2, nsINode* aNode) { 668 if (IsEnabledAll(logging::eTree | aExtraFlags)) { 669 MsgBegin("TREE", "%s; doc: %p", aMsg, aAcc ? aAcc->Document() : nullptr); 670 AccessibleInfo(aMsg1, aAcc); 671 LocalAccessible* acc = 672 aAcc ? aAcc->Document()->GetAccessible(aNode) : nullptr; 673 if (acc) { 674 AccessibleInfo(aMsg2, acc); 675 } else { 676 Node(aMsg2, aNode); 677 } 678 MsgEnd(); 679 } 680 } 681 682 void logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, 683 LocalAccessible* aParent) { 684 if (IsEnabledAll(logging::eTree | aExtraFlags)) { 685 MsgBegin("TREE", "%s; doc: %p", aMsg, aParent->Document()); 686 AccessibleInfo("container", aParent); 687 for (uint32_t idx = 0; idx < aParent->ChildCount(); idx++) { 688 AccessibleInfo("child", aParent->LocalChildAt(idx)); 689 } 690 MsgEnd(); 691 } 692 } 693 694 void logging::Tree(const char* aTitle, const char* aMsgText, 695 LocalAccessible* aRoot, GetTreePrefix aPrefixFunc, 696 void* aGetTreePrefixData) { 697 logging::MsgBegin(aTitle, "%s", aMsgText); 698 699 nsAutoString level; 700 LocalAccessible* root = aRoot; 701 do { 702 const char* prefix = 703 aPrefixFunc ? aPrefixFunc(aGetTreePrefixData, root) : ""; 704 printf("%s", NS_ConvertUTF16toUTF8(level).get()); 705 logging::AccessibleInfo(prefix, root); 706 if (root->LocalFirstChild() && !root->LocalFirstChild()->IsDoc()) { 707 level.AppendLiteral(u" "); 708 root = root->LocalFirstChild(); 709 continue; 710 } 711 int32_t idxInParent = root != aRoot && root->mParent 712 ? root->mParent->mChildren.IndexOf(root) 713 : -1; 714 if (idxInParent != -1 && 715 idxInParent < 716 static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) { 717 root = root->mParent->mChildren.ElementAt(idxInParent + 1); 718 continue; 719 } 720 while (root != aRoot && (root = root->LocalParent())) { 721 level.Cut(0, 2); 722 int32_t idxInParent = !root->IsDoc() && root->mParent 723 ? root->mParent->mChildren.IndexOf(root) 724 : -1; 725 if (idxInParent != -1 && 726 idxInParent < 727 static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) { 728 root = root->mParent->mChildren.ElementAt(idxInParent + 1); 729 break; 730 } 731 } 732 } while (root && root != aRoot); 733 734 logging::MsgEnd(); 735 } 736 737 void logging::DOMTree(const char* aTitle, const char* aMsgText, 738 DocAccessible* aDocument) { 739 logging::MsgBegin(aTitle, "%s", aMsgText); 740 nsAutoString level; 741 nsINode* root = aDocument->DocumentNode(); 742 do { 743 printf("%s", NS_ConvertUTF16toUTF8(level).get()); 744 logging::Node("", root); 745 if (root->GetFirstChild()) { 746 level.AppendLiteral(u" "); 747 root = root->GetFirstChild(); 748 continue; 749 } 750 if (root->GetNextSibling()) { 751 root = root->GetNextSibling(); 752 continue; 753 } 754 while ((root = root->GetParentNode())) { 755 level.Cut(0, 2); 756 if (root->GetNextSibling()) { 757 root = root->GetNextSibling(); 758 break; 759 } 760 } 761 } while (root); 762 logging::MsgEnd(); 763 } 764 765 void logging::TreeSize(const char* aTitle, const char* aMsgText, 766 LocalAccessible* aRoot) { 767 logging::MsgBegin(aTitle, "%s", aMsgText); 768 logging::AccessibleInfo("Logging tree size from: ", aRoot); 769 size_t b = 0; 770 size_t n = 0; 771 LocalAccessible* root = aRoot; 772 do { 773 // Process the current acc 774 b += AccessibleLoggingMallocSizeOf(root); 775 n++; 776 777 // Get next acc 778 if (root->LocalFirstChild() && !root->LocalFirstChild()->IsDoc()) { 779 root = root->LocalFirstChild(); 780 continue; 781 } 782 int32_t idxInParent = root != aRoot && root->mParent 783 ? root->mParent->mChildren.IndexOf(root) 784 : -1; 785 if (idxInParent != -1 && 786 idxInParent < 787 static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) { 788 root = root->mParent->mChildren.ElementAt(idxInParent + 1); 789 continue; 790 } 791 while (root != aRoot && (root = root->LocalParent())) { 792 int32_t idxInParent = !root->IsDoc() && root->mParent 793 ? root->mParent->mChildren.IndexOf(root) 794 : -1; 795 if (idxInParent != -1 && 796 idxInParent < 797 static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) { 798 root = root->mParent->mChildren.ElementAt(idxInParent + 1); 799 break; 800 } 801 } 802 } while (root && root != aRoot); 803 804 printf("\nTree contains %zu accessibles and is %zu bytes\n", n, b); 805 logging::MsgEnd(); 806 } 807 808 void logging::MsgBegin(const char* aTitle, const char* aMsgText, ...) { 809 printf("\nA11Y %s: ", aTitle); 810 811 va_list argptr; 812 va_start(argptr, aMsgText); 813 vprintf(aMsgText, argptr); 814 va_end(argptr); 815 816 PRIntervalTime time = PR_IntervalNow(); 817 uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60; 818 uint32_t secs = PR_IntervalToSeconds(time) % 60; 819 uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000; 820 printf("; %02u:%02u.%03u", mins, secs, msecs); 821 822 printf("\n {\n"); 823 } 824 825 void logging::MsgEnd() { printf(" }\n"); } 826 827 void logging::SubMsgBegin() { printf(" {\n"); } 828 829 void logging::SubMsgEnd() { printf(" }\n"); } 830 831 void logging::MsgEntry(const char* aEntryText, ...) { 832 printf(" "); 833 834 va_list argptr; 835 va_start(argptr, aEntryText); 836 vprintf(aEntryText, argptr); 837 va_end(argptr); 838 839 printf("\n"); 840 } 841 842 void logging::Text(const char* aText) { printf(" %s\n", aText); } 843 844 void logging::Address(const char* aDescr, LocalAccessible* aAcc) { 845 if (!aAcc->IsDoc()) { 846 printf(" %s accessible: %p, node: %p\n", aDescr, 847 static_cast<void*>(aAcc), static_cast<void*>(aAcc->GetNode())); 848 } 849 850 DocAccessible* doc = aAcc->Document(); 851 dom::Document* docNode = doc->DocumentNode(); 852 printf(" document: %p, node: %p\n", static_cast<void*>(doc), 853 static_cast<void*>(docNode)); 854 855 printf(" "); 856 LogDocURI(docNode); 857 printf("\n"); 858 } 859 860 void logging::Node(const char* aDescr, nsINode* aNode) { 861 Maybe<uint32_t> idxInParent = aNode->ComputeIndexInParentNode(); 862 nsAutoString nodeDesc; 863 DescribeNode(aNode, nodeDesc); 864 printf(" %s: %s, idx in parent %s\n", aDescr, 865 NS_ConvertUTF16toUTF8(nodeDesc).get(), ToString(idxInParent).c_str()); 866 } 867 868 void logging::Document(DocAccessible* aDocument) { 869 printf(" Document: %p, document node: %p\n", static_cast<void*>(aDocument), 870 static_cast<void*>(aDocument->DocumentNode())); 871 872 printf(" Document "); 873 LogDocURI(aDocument->DocumentNode()); 874 printf("\n"); 875 } 876 877 void logging::AccessibleInfo(const char* aDescr, LocalAccessible* aAccessible) { 878 printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible)); 879 if (!aAccessible) { 880 printf("\n"); 881 return; 882 } 883 if (aAccessible->IsDefunct()) { 884 printf("defunct\n"); 885 return; 886 } 887 if (!aAccessible->Document() || aAccessible->Document()->IsDefunct()) { 888 printf("document is shutting down, no info\n"); 889 return; 890 } 891 892 nsAutoString role; 893 GetAccService()->GetStringRole(aAccessible->Role(), role); 894 printf("role: %s", NS_ConvertUTF16toUTF8(role).get()); 895 896 nsAutoString name; 897 aAccessible->Name(name); 898 if (!name.IsEmpty()) { 899 printf(", name: '%s'", NS_ConvertUTF16toUTF8(name).get()); 900 } 901 902 printf(", idx: %d", aAccessible->IndexInParent()); 903 904 nsAutoString nodeDesc; 905 DescribeNode(aAccessible->GetNode(), nodeDesc); 906 printf(", node: %s\n", NS_ConvertUTF16toUTF8(nodeDesc).get()); 907 } 908 909 void logging::AccessibleNNode(const char* aDescr, 910 LocalAccessible* aAccessible) { 911 printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible)); 912 if (!aAccessible) return; 913 914 nsAutoString role; 915 GetAccService()->GetStringRole(aAccessible->Role(), role); 916 nsAutoString name; 917 aAccessible->Name(name); 918 919 printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(), 920 NS_ConvertUTF16toUTF8(name).get()); 921 922 nsAutoCString nodeDescr(aDescr); 923 nodeDescr.AppendLiteral(" node"); 924 Node(nodeDescr.get(), aAccessible->GetNode()); 925 926 Document(aAccessible->Document()); 927 } 928 929 void logging::AccessibleNNode(const char* aDescr, nsINode* aNode) { 930 DocAccessible* document = 931 GetAccService()->GetDocAccessible(aNode->OwnerDoc()); 932 933 if (document) { 934 LocalAccessible* accessible = document->GetAccessible(aNode); 935 if (accessible) { 936 AccessibleNNode(aDescr, accessible); 937 return; 938 } 939 } 940 941 nsAutoCString nodeDescr("[not accessible] "); 942 nodeDescr.Append(aDescr); 943 Node(nodeDescr.get(), aNode); 944 945 if (document) { 946 Document(document); 947 return; 948 } 949 950 printf(" [contained by not accessible document]:\n"); 951 LogDocInfo(aNode->OwnerDoc(), document); 952 printf("\n"); 953 } 954 955 void logging::DOMEvent(const char* aDescr, nsINode* aOrigTarget, 956 const nsAString& aEventType) { 957 logging::MsgBegin("DOMEvents", "event '%s' %s", 958 NS_ConvertUTF16toUTF8(aEventType).get(), aDescr); 959 logging::AccessibleNNode("Target", aOrigTarget); 960 logging::MsgEnd(); 961 } 962 963 void logging::Stack() { 964 if (IsEnabled(eStack)) { 965 printf(" stack: \n"); 966 MozWalkTheStack(stdout); 967 } 968 } 969 970 //////////////////////////////////////////////////////////////////////////////// 971 // namespace logging:: initialization 972 973 bool logging::IsEnabled(uint32_t aModules) { return sModules & aModules; } 974 975 bool logging::IsEnabledAll(uint32_t aModules) { 976 return (sModules & aModules) == aModules; 977 } 978 979 bool logging::IsEnabled(const nsAString& aModuleStr) { 980 for (unsigned int idx = 0; idx < std::size(sModuleMap); idx++) { 981 if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr)) { 982 return sModules & sModuleMap[idx].mModule; 983 } 984 } 985 986 return false; 987 } 988 989 void logging::Enable(const nsCString& aModules) { 990 EnableLogging(aModules.get()); 991 } 992 993 void logging::CheckEnv() { EnableLogging(PR_GetEnv("A11YLOG")); }