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/. */
9 #include "LocalAccessible-inl.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"
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 ////////////////////////////////////////////////////////////////////////////////
42 static uint32_t sModules
= 0;
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
) {
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;
82 sModules
|= sModuleMap
[idx
].mModule
;
83 printf("\n\nmodule enabled: %s\n", sModuleMap
[idx
].mStr
);
89 if (*token
== ',') token
++; // skip ',' char
93 static void LogDocURI(dom::Document
* aDocumentNode
) {
94 nsIURI
* uri
= aDocumentNode
->GetDocumentURI();
96 printf("uri: %s", uri
->GetSpecOrDefault().get());
102 static void LogDocShellState(dom::Document
* aDocumentNode
) {
103 printf("docshell busy: ");
104 nsCOMPtr
<nsIDocShell
> docShell
= aDocumentNode
->GetDocShell();
106 printf("null docshell");
110 nsAutoCString docShellBusy
;
111 nsIDocShell::BusyFlags busyFlags
= nsIDocShell::BUSY_FLAGS_NONE
;
112 docShell
->GetBusyFlags(&busyFlags
);
113 if (busyFlags
== nsIDocShell::BUSY_FLAGS_NONE
) {
116 if (busyFlags
& nsIDocShell::BUSY_FLAGS_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"));
132 printf("document type: [failed]");
136 static void LogDocShellTree(dom::Document
* aDocumentNode
) {
137 if (aDocumentNode
->IsActive()) {
138 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(aDocumentNode
->GetDocShell());
140 printf("in-process docshell hierarchy, null docshell;");
143 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
144 treeItem
->GetInProcessParent(getter_AddRefs(parentTreeItem
));
145 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
146 treeItem
->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem
));
148 "in-process docshell hierarchy, parent: %p, root: %p, "
150 static_cast<void*>(parentTreeItem
), static_cast<void*>(rootTreeItem
),
151 (nsCoreUtils::IsTopLevelContentDocInProcess(aDocumentNode
) ? "yes"
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";
163 case dom::Document::READYSTATE_LOADING
:
164 docState
= "loading";
166 case dom::Document::READYSTATE_INTERACTIVE
:
167 docState
= "interactive";
169 case dom::Document::READYSTATE_COMPLETE
:
170 docState
= "complete";
174 printf("doc state: %s", docState
);
175 printf(", %sinitial", aDocumentNode
->IsInitialDocument() ? "" : "not ");
176 printf(", %sshowing", aDocumentNode
->IsShowing() ? "" : "not ");
177 printf(", %svisible", aDocumentNode
->IsVisible() ? "" : "not ");
179 ", %svisible considering ancestors",
180 nsCoreUtils::IsDocumentVisibleConsideringInProcessAncestors(aDocumentNode
)
183 printf(", %sactive", aDocumentNode
->IsActive() ? "" : "not ");
184 printf(", %sresource", aDocumentNode
->IsResourceDoc() ? "" : "not ");
186 dom::Element
* rootEl
= aDocumentNode
->GetBodyElement();
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;
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
));
214 printf(", parent acc document: %p",
215 static_cast<void*>(GetExistingDocAccessible(parentDoc
)));
216 printf("\n parent ");
217 LogDocURI(parentDoc
);
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
));
228 LogDocURI(aDocumentNode
);
230 LogDocShellState(aDocumentNode
);
232 LogDocType(aDocumentNode
);
234 LogDocShellTree(aDocumentNode
);
236 LogDocState(aDocumentNode
);
238 LogPresShell(aDocumentNode
);
240 LogDocLoadGroup(aDocumentNode
);
242 LogDocParent(aDocumentNode
);
247 static void LogShellLoadType(nsIDocShell
* aDocShell
) {
248 printf("load type: ");
250 uint32_t loadType
= 0;
251 aDocShell
->GetLoadType(&loadType
);
256 case LOAD_NORMAL_REPLACE
:
257 printf("normal replace; ");
262 case LOAD_NORMAL_BYPASS_CACHE
:
263 printf("normal bypass cache; ");
265 case LOAD_NORMAL_BYPASS_PROXY
:
266 printf("normal bypass proxy; ");
268 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
269 printf("normal bypass proxy and cache; ");
271 case LOAD_RELOAD_NORMAL
:
272 printf("reload normal; ");
274 case LOAD_RELOAD_BYPASS_CACHE
:
275 printf("reload bypass cache; ");
277 case LOAD_RELOAD_BYPASS_PROXY
:
278 printf("reload bypass proxy; ");
280 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
281 printf("reload bypass proxy and cache; ");
289 case LOAD_REFRESH_REPLACE
:
290 printf("refresh replace; ");
292 case LOAD_RELOAD_CHARSET_CHANGE
:
293 printf("reload charset change; ");
295 case LOAD_BYPASS_HISTORY
:
296 printf("bypass history; ");
298 case LOAD_STOP_CONTENT
:
299 printf("stop content; ");
301 case LOAD_STOP_CONTENT_AND_REPLACE
:
302 printf("stop content and replace; ");
305 printf("load pushstate; ");
307 case LOAD_REPLACE_BYPASS_CACHE
:
308 printf("replace bypass cache; ");
310 case LOAD_ERROR_PAGE
:
311 printf("error page;");
318 static void LogRequest(nsIRequest
* aRequest
) {
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; ");
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
)) {
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");
374 aEventType
.AppendLiteral("false");
380 static void DescribeNode(nsINode
* aNode
, nsAString
& aOutDescription
) {
382 aOutDescription
.AppendLiteral("null");
386 aOutDescription
.AppendPrintf("0x%p, ", (void*)aNode
);
387 aOutDescription
.Append(aNode
->NodeInfo()->QualifiedName());
389 if (!aNode
->IsElement()) {
393 dom::Element
* elm
= aNode
->AsElement();
395 nsAtom
* idAtom
= elm
->GetID();
398 idAtom
->ToUTF8String(id
);
399 aOutDescription
.AppendPrintf("@id=\"%s\" ", id
.get());
401 aOutDescription
.Append(' ');
404 uint32_t attrCount
= elm
->GetAttrCount();
405 if (!attrCount
|| (idAtom
&& attrCount
== 1)) {
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
)) {
421 info
.mName
->GetQualifiedName(name
);
422 aOutDescription
.Append(name
);
424 aOutDescription
.AppendLiteral("=\"");
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
);
460 nsCOMPtr
<dom::Document
> documentNode
= window
->GetDoc();
466 DocAccessible
* document
= GetExistingDocAccessible(documentNode
);
468 LogDocInfo(documentNode
, document
);
470 nsCOMPtr
<nsIDocShell
> docShell
= window
->GetDocShell();
472 LogShellLoadType(docShell
);
474 LogRequest(aRequest
);
476 printf(" state flags: %x", aStateFlags
);
478 aWebProgress
->GetIsLoadingDocument(&isDocLoading
);
479 printf(", document is %sloading\n", (isDocLoading
? "" : "not "));
484 void logging::DocLoad(const char* aMsg
, dom::Document
* aDocumentNode
) {
485 MsgBegin(sDocLoadTitle
, "%s", aMsg
);
487 DocAccessible
* document
= GetExistingDocAccessible(aDocumentNode
);
488 LogDocInfo(aDocumentNode
, document
);
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
));
502 LogDocURI(aDocument
->DocumentNode());
506 LogDocAccState(aDocument
);
509 printf(" document is load event target: %s\n",
510 (aIsLoadEventTarget
? "true" : "false"));
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
);
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
);
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
);
554 void logging::OuterDocDestroy(OuterDocAccessible
* aOuterDoc
) {
555 MsgBegin(sDocDestroyTitle
, "outerdoc shutdown");
556 logging::Address("outerdoc", aOuterDoc
);
560 void logging::FocusNotificationTarget(const char* aMsg
,
561 const char* aTargetDescr
,
562 LocalAccessible
* aTarget
) {
563 MsgBegin(sFocusTitle
, "%s", aMsg
);
564 AccessibleNNode(aTargetDescr
, aTarget
);
568 void logging::FocusNotificationTarget(const char* aMsg
,
569 const char* aTargetDescr
,
570 nsINode
* aTargetNode
) {
571 MsgBegin(sFocusTitle
, "%s", aMsg
);
572 Node(aTargetDescr
, aTargetNode
);
576 void logging::FocusNotificationTarget(const char* aMsg
,
577 const char* aTargetDescr
,
578 nsISupports
* aTargetThing
) {
579 MsgBegin(sFocusTitle
, "%s", aMsg
);
582 nsCOMPtr
<nsINode
> targetNode(do_QueryInterface(aTargetThing
));
584 AccessibleNNode(aTargetDescr
, targetNode
);
586 printf(" %s: %p, window\n", aTargetDescr
,
587 static_cast<void*>(aTargetThing
));
594 void logging::ActiveItemChangeCausedBy(const char* aCause
,
595 LocalAccessible
* aTarget
) {
597 printf(" Caused by: %s\n", aCause
);
598 AccessibleNNode("Item", aTarget
);
602 void logging::ActiveWidget(LocalAccessible
* aWidget
) {
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"));
613 void logging::FocusDispatched(LocalAccessible
* aTarget
) {
615 AccessibleNNode("A11y target", aTarget
);
619 void logging::SelChange(dom::Selection
* aSelection
, DocAccessible
* aDocument
,
621 SelectionType type
= aSelection
->GetType();
623 const char* strType
= 0;
624 if (type
== SelectionType::eNormal
) {
626 } else if (type
== SelectionType::eSpellCheck
) {
627 strType
= "spellcheck";
632 bool isIgnored
= !aDocument
|| !aDocument
->IsContentLoaded();
634 "\nSelection changed, selection type: %s, notification %s, reason: %d\n",
635 strType
, (isIgnored
? "ignored" : "pending"), aReason
);
640 void logging::TreeInfo(const char* aMsg
, uint32_t aExtraFlags
, ...) {
641 if (IsEnabledAll(logging::eTree
| aExtraFlags
)) {
643 va_start(vl
, aExtraFlags
);
644 const char* descr
= va_arg(vl
, const char*);
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
*));
653 MsgBegin("TREE", "%s", aMsg
);
658 if (aExtraFlags
& eStack
) {
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;
673 AccessibleInfo(aMsg2
, acc
);
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
));
693 void logging::Tree(const char* aTitle
, const char* aMsgText
,
694 LocalAccessible
* aRoot
, GetTreePrefix aPrefixFunc
,
695 void* aGetTreePrefixData
) {
696 logging::MsgBegin(aTitle
, "%s", aMsgText
);
699 LocalAccessible
* root
= aRoot
;
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();
710 int32_t idxInParent
= root
!= aRoot
&& root
->mParent
711 ? root
->mParent
->mChildren
.IndexOf(root
)
713 if (idxInParent
!= -1 &&
715 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
716 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
719 while (root
!= aRoot
&& (root
= root
->LocalParent())) {
721 int32_t idxInParent
= !root
->IsDoc() && root
->mParent
722 ? root
->mParent
->mChildren
.IndexOf(root
)
724 if (idxInParent
!= -1 &&
726 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
727 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
731 } while (root
&& root
!= aRoot
);
736 void logging::DOMTree(const char* aTitle
, const char* aMsgText
,
737 DocAccessible
* aDocument
) {
738 logging::MsgBegin(aTitle
, "%s", aMsgText
);
740 nsINode
* root
= aDocument
->DocumentNode();
742 printf("%s", NS_ConvertUTF16toUTF8(level
).get());
743 logging::Node("", root
);
744 if (root
->GetFirstChild()) {
745 level
.AppendLiteral(u
" ");
746 root
= root
->GetFirstChild();
749 if (root
->GetNextSibling()) {
750 root
= root
->GetNextSibling();
753 while ((root
= root
->GetParentNode())) {
755 if (root
->GetNextSibling()) {
756 root
= root
->GetNextSibling();
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
);
770 LocalAccessible
* root
= aRoot
;
772 // Process the current acc
773 b
+= AccessibleLoggingMallocSizeOf(root
);
777 if (root
->LocalFirstChild() && !root
->LocalFirstChild()->IsDoc()) {
778 root
= root
->LocalFirstChild();
781 int32_t idxInParent
= root
!= aRoot
&& root
->mParent
782 ? root
->mParent
->mChildren
.IndexOf(root
)
784 if (idxInParent
!= -1 &&
786 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
787 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
790 while (root
!= aRoot
&& (root
= root
->LocalParent())) {
791 int32_t idxInParent
= !root
->IsDoc() && root
->mParent
792 ? root
->mParent
->mChildren
.IndexOf(root
)
794 if (idxInParent
!= -1 &&
796 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
797 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
801 } while (root
&& root
!= aRoot
);
803 printf("\nTree contains %zu accessibles and is %zu bytes\n", n
, b
);
807 void logging::MsgBegin(const char* aTitle
, const char* aMsgText
, ...) {
808 printf("\nA11Y %s: ", aTitle
);
811 va_start(argptr
, aMsgText
);
812 vprintf(aMsgText
, 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
);
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
, ...) {
834 va_start(argptr
, aEntryText
);
835 vprintf(aEntryText
, argptr
);
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
));
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());
876 void logging::AccessibleInfo(const char* aDescr
, LocalAccessible
* aAccessible
) {
877 printf(" %s: %p; ", aDescr
, static_cast<void*>(aAccessible
));
882 if (aAccessible
->IsDefunct()) {
886 if (!aAccessible
->Document() || aAccessible
->Document()->IsDefunct()) {
887 printf("document is shutting down, no info\n");
892 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
893 printf("role: %s", NS_ConvertUTF16toUTF8(role
).get());
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;
914 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
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());
933 LocalAccessible
* accessible
= document
->GetAccessible(aNode
);
935 AccessibleNNode(aDescr
, accessible
);
940 nsAutoCString
nodeDescr("[not accessible] ");
941 nodeDescr
.Append(aDescr
);
942 Node(nodeDescr
.get(), aNode
);
949 printf(" [contained by not accessible document]:\n");
950 LogDocInfo(aNode
->OwnerDoc(), document
);
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
);
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
;
988 void logging::Enable(const nsCString
& aModules
) {
989 EnableLogging(aModules
.get());
992 void logging::CheckEnv() { EnableLogging(PR_GetEnv("A11YLOG")); }