Bug 1833114 - Simplify marking code now |stack| represents the mark stack for the...
[gecko.git] / accessible / base / Logging.cpp
blob7b4551e77f8eb5b526ac20cfe175245ad753e038
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/. */
7 #include "Logging.h"
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"
17 #include "nsDocShellLoadTypes.h"
18 #include "nsIChannel.h"
19 #include "nsIInterfaceRequestorUtils.h"
20 #include "nsIWebProgress.h"
21 #include "prenv.h"
22 #include "nsIDocShellTreeItem.h"
23 #include "mozilla/Maybe.h"
24 #include "mozilla/PresShell.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"
33 using namespace mozilla;
34 using namespace mozilla::a11y;
36 using mozilla::dom::BorrowedAttrInfo;
38 MOZ_DEFINE_MALLOC_SIZE_OF(AccessibleLoggingMallocSizeOf)
40 ////////////////////////////////////////////////////////////////////////////////
41 // Logging helpers
43 static uint32_t sModules = 0;
45 struct ModuleRep {
46 const char* mStr;
47 logging::EModules mModule;
50 static ModuleRep sModuleMap[] = {{"docload", logging::eDocLoad},
51 {"doccreate", logging::eDocCreate},
52 {"docdestroy", logging::eDocDestroy},
53 {"doclifecycle", logging::eDocLifeCycle},
55 {"events", logging::eEvents},
56 {"platforms", logging::ePlatforms},
57 {"text", logging::eText},
58 {"tree", logging::eTree},
59 {"treeSize", logging::eTreeSize},
61 {"DOMEvents", logging::eDOMEvents},
62 {"focus", logging::eFocus},
63 {"selection", logging::eSelection},
64 {"notifications", logging::eNotifications},
66 {"stack", logging::eStack},
67 {"verbose", logging::eVerbose},
68 {"cache", logging::eCache}};
70 static void EnableLogging(const char* aModulesStr) {
71 sModules = 0;
72 if (!aModulesStr) return;
74 const char* token = aModulesStr;
75 while (*token != '\0') {
76 size_t tokenLen = strcspn(token, ",");
77 for (unsigned int idx = 0; idx < ArrayLength(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;
88 token += tokenLen;
90 if (*token == ',') token++; // skip ',' char
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");
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;
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'");
117 if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) {
118 printf("'busy'");
120 if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) {
121 printf(", 'before page load'");
123 if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
124 printf(", 'page loading'");
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]");
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;
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"));
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;
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 ");
187 dom::Element* rootEl = aDocumentNode->GetBodyElement();
188 if (!rootEl) {
189 rootEl = aDocumentNode->GetRootElement();
191 printf(", has %srole content", rootEl ? "" : "no ");
194 static void LogPresShell(dom::Document* aDocumentNode) {
195 PresShell* presShell = aDocumentNode->GetPresShell();
196 printf("presshell: %p", static_cast<void*>(presShell));
198 nsIScrollableFrame* sf = nullptr;
199 if (presShell) {
200 printf(", is %s destroying", (presShell->IsDestroying() ? "" : "not"));
201 sf = presShell->GetRootScrollFrameAsScrollable();
203 printf(", root scroll frame: %p", static_cast<void*>(sf));
206 static void LogDocLoadGroup(dom::Document* aDocumentNode) {
207 nsCOMPtr<nsILoadGroup> loadGroup = aDocumentNode->GetDocumentLoadGroup();
208 printf("load group: %p", static_cast<void*>(loadGroup));
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");
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));
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");
248 static void LogShellLoadType(nsIDocShell* aDocShell) {
249 printf("load type: ");
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");
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; ");
331 if (loadFlags & nsIChannel::LOAD_REPLACE) printf("replace; ");
332 if (loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI) {
333 printf("initial document uri; ");
335 if (loadFlags & nsIChannel::LOAD_TARGETED) printf("targeted; ");
336 if (loadFlags & nsIChannel::LOAD_CALL_CONTENT_SNIFFERS) {
337 printf("call content sniffers; ");
339 if (loadFlags & nsIChannel::LOAD_BYPASS_URL_CLASSIFIER) {
340 printf("bypass classify uri; ");
342 } else {
343 printf(" no request");
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;");
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");
381 static void DescribeNode(nsINode* aNode, nsAString& aOutDescription) {
382 if (!aNode) {
383 aOutDescription.AppendLiteral("null");
384 return;
387 aOutDescription.AppendPrintf("0x%p, ", (void*)aNode);
388 aOutDescription.Append(aNode->NodeInfo()->QualifiedName());
390 if (!aNode->IsElement()) {
391 return;
394 dom::Element* elm = aNode->AsElement();
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(' ');
405 uint32_t attrCount = elm->GetAttrCount();
406 if (!attrCount || (idAtom && attrCount == 1)) {
407 return;
410 aOutDescription.AppendLiteral("[ ");
412 for (uint32_t index = 0; index < attrCount; index++) {
413 BorrowedAttrInfo info = elm->GetAttrInfoAt(index);
415 // Skip redundant display of id attribute.
416 if (info.mName->Equals(nsGkAtoms::id)) {
417 continue;
420 // name
421 nsAutoString name;
422 info.mName->GetQualifiedName(name);
423 aOutDescription.Append(name);
425 aOutDescription.AppendLiteral("=\"");
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);
433 aOutDescription.Append(value);
434 aOutDescription.AppendLiteral("\" ");
437 aOutDescription.Append(']');
440 ////////////////////////////////////////////////////////////////////////////////
441 // namespace logging:: document life cycle logging methods
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";
449 void logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
450 nsIRequest* aRequest, uint32_t aStateFlags) {
451 MsgBegin(sDocLoadTitle, "%s", aMsg);
453 nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
454 aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
455 nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
456 if (!window) {
457 MsgEnd();
458 return;
461 nsCOMPtr<dom::Document> documentNode = window->GetDoc();
462 if (!documentNode) {
463 MsgEnd();
464 return;
467 DocAccessible* document = GetExistingDocAccessible(documentNode);
469 LogDocInfo(documentNode, document);
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 "));
482 MsgEnd();
485 void logging::DocLoad(const char* aMsg, dom::Document* aDocumentNode) {
486 MsgBegin(sDocLoadTitle, "%s", aMsg);
488 DocAccessible* document = GetExistingDocAccessible(aDocumentNode);
489 LogDocInfo(aDocumentNode, document);
491 MsgEnd();
494 void logging::DocCompleteLoad(DocAccessible* aDocument,
495 bool aIsLoadEventTarget) {
496 MsgBegin(sDocLoadTitle, "document loaded *completely*");
498 printf(" DOM document: %p, acc document: %p\n",
499 static_cast<void*>(aDocument->DocumentNode()),
500 static_cast<void*>(aDocument));
502 printf(" ");
503 LogDocURI(aDocument->DocumentNode());
504 printf("\n");
506 printf(" ");
507 LogDocAccState(aDocument);
508 printf("\n");
510 printf(" document is load event target: %s\n",
511 (aIsLoadEventTarget ? "true" : "false"));
513 MsgEnd();
516 void logging::DocLoadEventFired(AccEvent* aEvent) {
517 nsAutoCString strEventType;
518 GetDocLoadEventType(aEvent, strEventType);
519 if (!strEventType.IsEmpty()) printf(" fire: %s\n", strEventType.get());
522 void logging::DocLoadEventHandled(AccEvent* aEvent) {
523 nsAutoCString strEventType;
524 GetDocLoadEventType(aEvent, strEventType);
525 if (strEventType.IsEmpty()) return;
527 MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get());
529 DocAccessible* document = aEvent->GetAccessible()->AsDoc();
530 if (document) LogDocInfo(document->DocumentNode(), document);
532 MsgEnd();
535 void logging::DocCreate(const char* aMsg, dom::Document* aDocumentNode,
536 DocAccessible* aDocument) {
537 DocAccessible* document =
538 aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode);
540 MsgBegin(sDocCreateTitle, "%s", aMsg);
541 LogDocInfo(aDocumentNode, document);
542 MsgEnd();
545 void logging::DocDestroy(const char* aMsg, dom::Document* aDocumentNode,
546 DocAccessible* aDocument) {
547 DocAccessible* document =
548 aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode);
550 MsgBegin(sDocDestroyTitle, "%s", aMsg);
551 LogDocInfo(aDocumentNode, document);
552 MsgEnd();
555 void logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc) {
556 MsgBegin(sDocDestroyTitle, "outerdoc shutdown");
557 logging::Address("outerdoc", aOuterDoc);
558 MsgEnd();
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();
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();
577 void logging::FocusNotificationTarget(const char* aMsg,
578 const char* aTargetDescr,
579 nsISupports* aTargetThing) {
580 MsgBegin(sFocusTitle, "%s", aMsg);
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));
592 MsgEnd();
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();
603 void logging::ActiveWidget(LocalAccessible* aWidget) {
604 SubMsgBegin();
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"));
611 SubMsgEnd();
614 void logging::FocusDispatched(LocalAccessible* aTarget) {
615 SubMsgBegin();
616 AccessibleNNode("A11y target", aTarget);
617 SubMsgEnd();
620 void logging::SelChange(dom::Selection* aSelection, DocAccessible* aDocument,
621 int16_t aReason) {
622 SelectionType type = aSelection->GetType();
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";
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);
638 Stack();
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*));
653 } else {
654 MsgBegin("TREE", "%s", aMsg);
656 va_end(vl);
657 MsgEnd();
659 if (aExtraFlags & eStack) {
660 Stack();
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);
678 MsgEnd();
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));
690 MsgEnd();
694 void logging::Tree(const char* aTitle, const char* aMsgText,
695 LocalAccessible* aRoot, GetTreePrefix aPrefixFunc,
696 void* aGetTreePrefixData) {
697 logging::MsgBegin(aTitle, "%s", aMsgText);
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;
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;
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;
732 } while (root && root != aRoot);
734 logging::MsgEnd();
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;
750 if (root->GetNextSibling()) {
751 root = root->GetNextSibling();
752 continue;
754 while ((root = root->GetParentNode())) {
755 level.Cut(0, 2);
756 if (root->GetNextSibling()) {
757 root = root->GetNextSibling();
758 break;
761 } while (root);
762 logging::MsgEnd();
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++;
777 // Get next acc
778 if (root->LocalFirstChild() && !root->LocalFirstChild()->IsDoc()) {
779 root = root->LocalFirstChild();
780 continue;
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;
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;
802 } while (root && root != aRoot);
804 printf("\nTree contains %zu accessibles and is %zu bytes\n", n, b);
805 logging::MsgEnd();
808 void logging::MsgBegin(const char* aTitle, const char* aMsgText, ...) {
809 printf("\nA11Y %s: ", aTitle);
811 va_list argptr;
812 va_start(argptr, aMsgText);
813 vprintf(aMsgText, argptr);
814 va_end(argptr);
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);
822 printf("\n {\n");
825 void logging::MsgEnd() { printf(" }\n"); }
827 void logging::SubMsgBegin() { printf(" {\n"); }
829 void logging::SubMsgEnd() { printf(" }\n"); }
831 void logging::MsgEntry(const char* aEntryText, ...) {
832 printf(" ");
834 va_list argptr;
835 va_start(argptr, aEntryText);
836 vprintf(aEntryText, argptr);
837 va_end(argptr);
839 printf("\n");
842 void logging::Text(const char* aText) { printf(" %s\n", aText); }
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()));
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));
855 printf(" ");
856 LogDocURI(docNode);
857 printf("\n");
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());
868 void logging::Document(DocAccessible* aDocument) {
869 printf(" Document: %p, document node: %p\n", static_cast<void*>(aDocument),
870 static_cast<void*>(aDocument->DocumentNode()));
872 printf(" Document ");
873 LogDocURI(aDocument->DocumentNode());
874 printf("\n");
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;
883 if (aAccessible->IsDefunct()) {
884 printf("defunct\n");
885 return;
887 if (!aAccessible->Document() || aAccessible->Document()->IsDefunct()) {
888 printf("document is shutting down, no info\n");
889 return;
892 nsAutoString role;
893 GetAccService()->GetStringRole(aAccessible->Role(), role);
894 printf("role: %s", NS_ConvertUTF16toUTF8(role).get());
896 nsAutoString name;
897 aAccessible->Name(name);
898 if (!name.IsEmpty()) {
899 printf(", name: '%s'", NS_ConvertUTF16toUTF8(name).get());
902 printf(", idx: %d", aAccessible->IndexInParent());
904 nsAutoString nodeDesc;
905 DescribeNode(aAccessible->GetNode(), nodeDesc);
906 printf(", node: %s\n", NS_ConvertUTF16toUTF8(nodeDesc).get());
909 void logging::AccessibleNNode(const char* aDescr,
910 LocalAccessible* aAccessible) {
911 printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible));
912 if (!aAccessible) return;
914 nsAutoString role;
915 GetAccService()->GetStringRole(aAccessible->Role(), role);
916 nsAutoString name;
917 aAccessible->Name(name);
919 printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(),
920 NS_ConvertUTF16toUTF8(name).get());
922 nsAutoCString nodeDescr(aDescr);
923 nodeDescr.AppendLiteral(" node");
924 Node(nodeDescr.get(), aAccessible->GetNode());
926 Document(aAccessible->Document());
929 void logging::AccessibleNNode(const char* aDescr, nsINode* aNode) {
930 DocAccessible* document =
931 GetAccService()->GetDocAccessible(aNode->OwnerDoc());
933 if (document) {
934 LocalAccessible* accessible = document->GetAccessible(aNode);
935 if (accessible) {
936 AccessibleNNode(aDescr, accessible);
937 return;
941 nsAutoCString nodeDescr("[not accessible] ");
942 nodeDescr.Append(aDescr);
943 Node(nodeDescr.get(), aNode);
945 if (document) {
946 Document(document);
947 return;
950 printf(" [contained by not accessible document]:\n");
951 LogDocInfo(aNode->OwnerDoc(), document);
952 printf("\n");
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();
963 void logging::Stack() {
964 if (IsEnabled(eStack)) {
965 printf(" stack: \n");
966 MozWalkTheStack(stdout);
970 ////////////////////////////////////////////////////////////////////////////////
971 // namespace logging:: initialization
973 bool logging::IsEnabled(uint32_t aModules) { return sModules & aModules; }
975 bool logging::IsEnabledAll(uint32_t aModules) {
976 return (sModules & aModules) == aModules;
979 bool logging::IsEnabled(const nsAString& aModuleStr) {
980 for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) {
981 if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr)) {
982 return sModules & sModuleMap[idx].mModule;
986 return false;
989 void logging::Enable(const nsCString& aModules) {
990 EnableLogging(aModules.get());
993 void logging::CheckEnv() { EnableLogging(PR_GetEnv("A11YLOG")); }