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