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 "nsIInterfaceRequestorUtils.h"
20 #include "nsIWebProgress.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 ////////////////////////////////////////////////////////////////////////////////
43 static uint32_t sModules
= 0;
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
) {
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;
83 sModules
|= sModuleMap
[idx
].mModule
;
84 printf("\n\nmodule enabled: %s\n", sModuleMap
[idx
].mStr
);
90 if (*token
== ',') token
++; // skip ',' char
94 static void LogDocURI(dom::Document
* aDocumentNode
) {
95 nsIURI
* uri
= aDocumentNode
->GetDocumentURI();
97 printf("uri: %s", uri
->GetSpecOrDefault().get());
103 static void LogDocShellState(dom::Document
* aDocumentNode
) {
104 printf("docshell busy: ");
105 nsCOMPtr
<nsIDocShell
> docShell
= aDocumentNode
->GetDocShell();
107 printf("null docshell");
111 nsAutoCString docShellBusy
;
112 nsIDocShell::BusyFlags busyFlags
= nsIDocShell::BUSY_FLAGS_NONE
;
113 docShell
->GetBusyFlags(&busyFlags
);
114 if (busyFlags
== nsIDocShell::BUSY_FLAGS_NONE
) {
117 if (busyFlags
& nsIDocShell::BUSY_FLAGS_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"));
133 printf("document type: [failed]");
137 static void LogDocShellTree(dom::Document
* aDocumentNode
) {
138 if (aDocumentNode
->IsActive()) {
139 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(aDocumentNode
->GetDocShell());
141 printf("in-process docshell hierarchy, null docshell;");
144 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
145 treeItem
->GetInProcessParent(getter_AddRefs(parentTreeItem
));
146 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
147 treeItem
->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem
));
149 "in-process docshell hierarchy, parent: %p, root: %p, "
151 static_cast<void*>(parentTreeItem
), static_cast<void*>(rootTreeItem
),
152 (nsCoreUtils::IsTopLevelContentDocInProcess(aDocumentNode
) ? "yes"
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";
164 case dom::Document::READYSTATE_LOADING
:
165 docState
= "loading";
167 case dom::Document::READYSTATE_INTERACTIVE
:
168 docState
= "interactive";
170 case dom::Document::READYSTATE_COMPLETE
:
171 docState
= "complete";
175 printf("doc state: %s", docState
);
176 printf(", %sinitial", aDocumentNode
->IsInitialDocument() ? "" : "not ");
177 printf(", %sshowing", aDocumentNode
->IsShowing() ? "" : "not ");
178 printf(", %svisible", aDocumentNode
->IsVisible() ? "" : "not ");
180 ", %svisible considering ancestors",
181 nsCoreUtils::IsDocumentVisibleConsideringInProcessAncestors(aDocumentNode
)
184 printf(", %sactive", aDocumentNode
->IsActive() ? "" : "not ");
185 printf(", %sresource", aDocumentNode
->IsResourceDoc() ? "" : "not ");
187 dom::Element
* rootEl
= aDocumentNode
->GetBodyElement();
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;
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
));
215 printf(", parent acc document: %p",
216 static_cast<void*>(GetExistingDocAccessible(parentDoc
)));
217 printf("\n parent ");
218 LogDocURI(parentDoc
);
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
));
229 LogDocURI(aDocumentNode
);
231 LogDocShellState(aDocumentNode
);
233 LogDocType(aDocumentNode
);
235 LogDocShellTree(aDocumentNode
);
237 LogDocState(aDocumentNode
);
239 LogPresShell(aDocumentNode
);
241 LogDocLoadGroup(aDocumentNode
);
243 LogDocParent(aDocumentNode
);
248 static void LogShellLoadType(nsIDocShell
* aDocShell
) {
249 printf("load type: ");
251 uint32_t loadType
= 0;
252 aDocShell
->GetLoadType(&loadType
);
257 case LOAD_NORMAL_REPLACE
:
258 printf("normal replace; ");
263 case LOAD_NORMAL_BYPASS_CACHE
:
264 printf("normal bypass cache; ");
266 case LOAD_NORMAL_BYPASS_PROXY
:
267 printf("normal bypass proxy; ");
269 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
270 printf("normal bypass proxy and cache; ");
272 case LOAD_RELOAD_NORMAL
:
273 printf("reload normal; ");
275 case LOAD_RELOAD_BYPASS_CACHE
:
276 printf("reload bypass cache; ");
278 case LOAD_RELOAD_BYPASS_PROXY
:
279 printf("reload bypass proxy; ");
281 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
282 printf("reload bypass proxy and cache; ");
290 case LOAD_REFRESH_REPLACE
:
291 printf("refresh replace; ");
293 case LOAD_RELOAD_CHARSET_CHANGE
:
294 printf("reload charset change; ");
296 case LOAD_BYPASS_HISTORY
:
297 printf("bypass history; ");
299 case LOAD_STOP_CONTENT
:
300 printf("stop content; ");
302 case LOAD_STOP_CONTENT_AND_REPLACE
:
303 printf("stop content and replace; ");
306 printf("load pushstate; ");
308 case LOAD_REPLACE_BYPASS_CACHE
:
309 printf("replace bypass cache; ");
311 case LOAD_ERROR_PAGE
:
312 printf("error page;");
319 static void LogRequest(nsIRequest
* aRequest
) {
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; ");
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
)) {
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");
375 aEventType
.AppendLiteral("false");
381 static void DescribeNode(nsINode
* aNode
, nsAString
& aOutDescription
) {
383 aOutDescription
.AppendLiteral("null");
387 aOutDescription
.AppendPrintf("0x%p, ", (void*)aNode
);
388 aOutDescription
.Append(aNode
->NodeInfo()->QualifiedName());
390 if (!aNode
->IsElement()) {
394 dom::Element
* elm
= aNode
->AsElement();
396 nsAtom
* idAtom
= elm
->GetID();
399 idAtom
->ToUTF8String(id
);
400 aOutDescription
.AppendPrintf("@id=\"%s\" ", id
.get());
402 aOutDescription
.Append(' ');
405 uint32_t attrCount
= elm
->GetAttrCount();
406 if (!attrCount
|| (idAtom
&& attrCount
== 1)) {
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
)) {
422 info
.mName
->GetQualifiedName(name
);
423 aOutDescription
.Append(name
);
425 aOutDescription
.AppendLiteral("=\"");
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
);
461 nsCOMPtr
<dom::Document
> documentNode
= window
->GetDoc();
467 DocAccessible
* document
= GetExistingDocAccessible(documentNode
);
469 LogDocInfo(documentNode
, document
);
471 nsCOMPtr
<nsIDocShell
> docShell
= window
->GetDocShell();
473 LogShellLoadType(docShell
);
475 LogRequest(aRequest
);
477 printf(" state flags: %x", aStateFlags
);
479 aWebProgress
->GetIsLoadingDocument(&isDocLoading
);
480 printf(", document is %sloading\n", (isDocLoading
? "" : "not "));
485 void logging::DocLoad(const char* aMsg
, dom::Document
* aDocumentNode
) {
486 MsgBegin(sDocLoadTitle
, "%s", aMsg
);
488 DocAccessible
* document
= GetExistingDocAccessible(aDocumentNode
);
489 LogDocInfo(aDocumentNode
, document
);
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
));
503 LogDocURI(aDocument
->DocumentNode());
507 LogDocAccState(aDocument
);
510 printf(" document is load event target: %s\n",
511 (aIsLoadEventTarget
? "true" : "false"));
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
);
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
);
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
);
555 void logging::OuterDocDestroy(OuterDocAccessible
* aOuterDoc
) {
556 MsgBegin(sDocDestroyTitle
, "outerdoc shutdown");
557 logging::Address("outerdoc", aOuterDoc
);
561 void logging::FocusNotificationTarget(const char* aMsg
,
562 const char* aTargetDescr
,
563 LocalAccessible
* aTarget
) {
564 MsgBegin(sFocusTitle
, "%s", aMsg
);
565 AccessibleNNode(aTargetDescr
, aTarget
);
569 void logging::FocusNotificationTarget(const char* aMsg
,
570 const char* aTargetDescr
,
571 nsINode
* aTargetNode
) {
572 MsgBegin(sFocusTitle
, "%s", aMsg
);
573 Node(aTargetDescr
, aTargetNode
);
577 void logging::FocusNotificationTarget(const char* aMsg
,
578 const char* aTargetDescr
,
579 nsISupports
* aTargetThing
) {
580 MsgBegin(sFocusTitle
, "%s", aMsg
);
583 nsCOMPtr
<nsINode
> targetNode(do_QueryInterface(aTargetThing
));
585 AccessibleNNode(aTargetDescr
, targetNode
);
587 printf(" %s: %p, window\n", aTargetDescr
,
588 static_cast<void*>(aTargetThing
));
595 void logging::ActiveItemChangeCausedBy(const char* aCause
,
596 LocalAccessible
* aTarget
) {
598 printf(" Caused by: %s\n", aCause
);
599 AccessibleNNode("Item", aTarget
);
603 void logging::ActiveWidget(LocalAccessible
* aWidget
) {
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"));
614 void logging::FocusDispatched(LocalAccessible
* aTarget
) {
616 AccessibleNNode("A11y target", aTarget
);
620 void logging::SelChange(dom::Selection
* aSelection
, DocAccessible
* aDocument
,
622 SelectionType type
= aSelection
->GetType();
624 const char* strType
= 0;
625 if (type
== SelectionType::eNormal
) {
627 } else if (type
== SelectionType::eSpellCheck
) {
628 strType
= "spellcheck";
633 bool isIgnored
= !aDocument
|| !aDocument
->IsContentLoaded();
635 "\nSelection changed, selection type: %s, notification %s, reason: %d\n",
636 strType
, (isIgnored
? "ignored" : "pending"), aReason
);
641 void logging::TreeInfo(const char* aMsg
, uint32_t aExtraFlags
, ...) {
642 if (IsEnabledAll(logging::eTree
| aExtraFlags
)) {
644 va_start(vl
, aExtraFlags
);
645 const char* descr
= va_arg(vl
, const char*);
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
*));
654 MsgBegin("TREE", "%s", aMsg
);
659 if (aExtraFlags
& eStack
) {
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;
674 AccessibleInfo(aMsg2
, acc
);
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
));
694 void logging::Tree(const char* aTitle
, const char* aMsgText
,
695 LocalAccessible
* aRoot
, GetTreePrefix aPrefixFunc
,
696 void* aGetTreePrefixData
) {
697 logging::MsgBegin(aTitle
, "%s", aMsgText
);
700 LocalAccessible
* root
= aRoot
;
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();
711 int32_t idxInParent
= root
!= aRoot
&& root
->mParent
712 ? root
->mParent
->mChildren
.IndexOf(root
)
714 if (idxInParent
!= -1 &&
716 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
717 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
720 while (root
!= aRoot
&& (root
= root
->LocalParent())) {
722 int32_t idxInParent
= !root
->IsDoc() && root
->mParent
723 ? root
->mParent
->mChildren
.IndexOf(root
)
725 if (idxInParent
!= -1 &&
727 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
728 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
732 } while (root
&& root
!= aRoot
);
737 void logging::DOMTree(const char* aTitle
, const char* aMsgText
,
738 DocAccessible
* aDocument
) {
739 logging::MsgBegin(aTitle
, "%s", aMsgText
);
741 nsINode
* root
= aDocument
->DocumentNode();
743 printf("%s", NS_ConvertUTF16toUTF8(level
).get());
744 logging::Node("", root
);
745 if (root
->GetFirstChild()) {
746 level
.AppendLiteral(u
" ");
747 root
= root
->GetFirstChild();
750 if (root
->GetNextSibling()) {
751 root
= root
->GetNextSibling();
754 while ((root
= root
->GetParentNode())) {
756 if (root
->GetNextSibling()) {
757 root
= root
->GetNextSibling();
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
);
771 LocalAccessible
* root
= aRoot
;
773 // Process the current acc
774 b
+= AccessibleLoggingMallocSizeOf(root
);
778 if (root
->LocalFirstChild() && !root
->LocalFirstChild()->IsDoc()) {
779 root
= root
->LocalFirstChild();
782 int32_t idxInParent
= root
!= aRoot
&& root
->mParent
783 ? root
->mParent
->mChildren
.IndexOf(root
)
785 if (idxInParent
!= -1 &&
787 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
788 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
791 while (root
!= aRoot
&& (root
= root
->LocalParent())) {
792 int32_t idxInParent
= !root
->IsDoc() && root
->mParent
793 ? root
->mParent
->mChildren
.IndexOf(root
)
795 if (idxInParent
!= -1 &&
797 static_cast<int32_t>(root
->mParent
->mChildren
.Length() - 1)) {
798 root
= root
->mParent
->mChildren
.ElementAt(idxInParent
+ 1);
802 } while (root
&& root
!= aRoot
);
804 printf("\nTree contains %zu accessibles and is %zu bytes\n", n
, b
);
808 void logging::MsgBegin(const char* aTitle
, const char* aMsgText
, ...) {
809 printf("\nA11Y %s: ", aTitle
);
812 va_start(argptr
, aMsgText
);
813 vprintf(aMsgText
, 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
);
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
, ...) {
835 va_start(argptr
, aEntryText
);
836 vprintf(aEntryText
, argptr
);
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
));
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());
877 void logging::AccessibleInfo(const char* aDescr
, LocalAccessible
* aAccessible
) {
878 printf(" %s: %p; ", aDescr
, static_cast<void*>(aAccessible
));
883 if (aAccessible
->IsDefunct()) {
887 if (!aAccessible
->Document() || aAccessible
->Document()->IsDefunct()) {
888 printf("document is shutting down, no info\n");
893 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
894 printf("role: %s", NS_ConvertUTF16toUTF8(role
).get());
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;
915 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
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());
934 LocalAccessible
* accessible
= document
->GetAccessible(aNode
);
936 AccessibleNNode(aDescr
, accessible
);
941 nsAutoCString
nodeDescr("[not accessible] ");
942 nodeDescr
.Append(aDescr
);
943 Node(nodeDescr
.get(), aNode
);
950 printf(" [contained by not accessible document]:\n");
951 LogDocInfo(aNode
->OwnerDoc(), document
);
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
);
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
;
989 void logging::Enable(const nsCString
& aModules
) {
990 EnableLogging(aModules
.get());
993 void logging::CheckEnv() { EnableLogging(PR_GetEnv("A11YLOG")); }