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 "Accessible-inl.h"
11 #include "DocAccessible.h"
12 #include "nsAccessibilityService.h"
13 #include "nsCoreUtils.h"
14 #include "OuterDocAccessible.h"
16 #include "nsDocShellLoadTypes.h"
17 #include "nsIChannel.h"
18 #include "nsIInterfaceRequestorUtils.h"
19 #include "nsISelectionPrivate.h"
20 #include "nsTraceRefcnt.h"
21 #include "nsIWebProgress.h"
23 #include "nsIDocShellTreeItem.h"
25 #include "mozilla/dom/Element.h"
27 using namespace mozilla
;
28 using namespace mozilla::a11y
;
30 ////////////////////////////////////////////////////////////////////////////////
33 static uint32_t sModules
= 0;
37 logging::EModules mModule
;
40 static ModuleRep sModuleMap
[] = {
41 { "docload", logging::eDocLoad
},
42 { "doccreate", logging::eDocCreate
},
43 { "docdestroy", logging::eDocDestroy
},
44 { "doclifecycle", logging::eDocLifeCycle
},
46 { "events", logging::eEvents
},
47 { "platforms", logging::ePlatforms
},
48 { "stack", logging::eStack
},
49 { "text", logging::eText
},
50 { "tree", logging::eTree
},
52 { "DOMEvents", logging::eDOMEvents
},
53 { "focus", logging::eFocus
},
54 { "selection", logging::eSelection
},
55 { "notifications", logging::eNotifications
}
59 EnableLogging(const char* aModulesStr
)
65 const char* token
= aModulesStr
;
66 while (*token
!= '\0') {
67 size_t tokenLen
= strcspn(token
, ",");
68 for (unsigned int idx
= 0; idx
< ArrayLength(sModuleMap
); idx
++) {
69 if (strncmp(token
, sModuleMap
[idx
].mStr
, tokenLen
) == 0) {
70 #if !defined(MOZ_PROFILING) && (!defined(DEBUG) || defined(MOZ_OPTIMIZE))
71 // Stack tracing on profiling enabled or debug not optimized builds.
72 if (strncmp(token
, "stack", tokenLen
) == 0)
75 sModules
|= sModuleMap
[idx
].mModule
;
76 printf("\n\nmodule enabled: %s\n", sModuleMap
[idx
].mStr
);
83 token
++; // skip ',' char
88 LogDocURI(nsIDocument
* aDocumentNode
)
90 nsIURI
* uri
= aDocumentNode
->GetDocumentURI();
93 printf("uri: %s", spec
.get());
97 LogDocShellState(nsIDocument
* aDocumentNode
)
99 printf("docshell busy: ");
101 nsAutoCString docShellBusy
;
102 nsCOMPtr
<nsIDocShell
> docShell
= aDocumentNode
->GetDocShell();
103 uint32_t busyFlags
= nsIDocShell::BUSY_FLAGS_NONE
;
104 docShell
->GetBusyFlags(&busyFlags
);
105 if (busyFlags
== nsIDocShell::BUSY_FLAGS_NONE
)
107 if (busyFlags
& nsIDocShell::BUSY_FLAGS_BUSY
)
109 if (busyFlags
& nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD
)
110 printf(", 'before page load'");
111 if (busyFlags
& nsIDocShell::BUSY_FLAGS_PAGE_LOADING
)
112 printf(", 'page loading'");
118 LogDocType(nsIDocument
* aDocumentNode
)
120 if (aDocumentNode
->IsActive()) {
121 bool isContent
= nsCoreUtils::IsContentDocument(aDocumentNode
);
122 printf("%s document", (isContent
? "content" : "chrome"));
124 printf("document type: [failed]");\
129 LogDocShellTree(nsIDocument
* aDocumentNode
)
131 if (aDocumentNode
->IsActive()) {
132 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(aDocumentNode
->GetDocShell());
133 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
134 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
135 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
136 treeItem
->GetRootTreeItem(getter_AddRefs(rootTreeItem
));
137 printf("docshell hierarchy, parent: %p, root: %p, is tab document: %s;",
138 static_cast<void*>(parentTreeItem
), static_cast<void*>(rootTreeItem
),
139 (nsCoreUtils::IsTabDocument(aDocumentNode
) ? "yes" : "no"));
144 LogDocState(nsIDocument
* aDocumentNode
)
146 const char* docState
= nullptr;
147 nsIDocument::ReadyState docStateFlag
= aDocumentNode
->GetReadyStateEnum();
148 switch (docStateFlag
) {
149 case nsIDocument::READYSTATE_UNINITIALIZED
:
150 docState
= "uninitialized";
152 case nsIDocument::READYSTATE_LOADING
:
153 docState
= "loading";
155 case nsIDocument::READYSTATE_INTERACTIVE
:
156 docState
= "interactive";
158 case nsIDocument::READYSTATE_COMPLETE
:
159 docState
= "complete";
163 printf("doc state: %s", docState
);
164 printf(", %sinitial", aDocumentNode
->IsInitialDocument() ? "" : "not ");
165 printf(", %sshowing", aDocumentNode
->IsShowing() ? "" : "not ");
166 printf(", %svisible", aDocumentNode
->IsVisible() ? "" : "not ");
167 printf(", %svisible considering ancestors", aDocumentNode
->IsVisibleConsideringAncestors() ? "" : "not ");
168 printf(", %sactive", aDocumentNode
->IsActive() ? "" : "not ");
169 printf(", %sresource", aDocumentNode
->IsResourceDoc() ? "" : "not ");
170 printf(", has %srole content",
171 nsCoreUtils::GetRoleContent(aDocumentNode
) ? "" : "no ");
175 LogPresShell(nsIDocument
* aDocumentNode
)
177 nsIPresShell
* ps
= aDocumentNode
->GetShell();
178 printf("presshell: %p", static_cast<void*>(ps
));
180 nsIScrollableFrame
* sf
= nullptr;
182 printf(", is %s destroying", (ps
->IsDestroying() ? "" : "not"));
183 sf
= ps
->GetRootScrollFrameAsScrollable();
185 printf(", root scroll frame: %p", static_cast<void*>(sf
));
189 LogDocLoadGroup(nsIDocument
* aDocumentNode
)
191 nsCOMPtr
<nsILoadGroup
> loadGroup
= aDocumentNode
->GetDocumentLoadGroup();
192 printf("load group: %p", static_cast<void*>(loadGroup
));
196 LogDocParent(nsIDocument
* aDocumentNode
)
198 nsIDocument
* parentDoc
= aDocumentNode
->GetParentDocument();
199 printf("parent DOM document: %p", static_cast<void*>(parentDoc
));
201 printf(", parent acc document: %p",
202 static_cast<void*>(GetExistingDocAccessible(parentDoc
)));
203 printf("\n parent ");
204 LogDocURI(parentDoc
);
210 LogDocInfo(nsIDocument
* aDocumentNode
, DocAccessible
* aDocument
)
212 printf(" DOM document: %p, acc document: %p\n ",
213 static_cast<void*>(aDocumentNode
), static_cast<void*>(aDocument
));
217 LogDocURI(aDocumentNode
);
219 LogDocShellState(aDocumentNode
);
221 LogDocType(aDocumentNode
);
223 LogDocShellTree(aDocumentNode
);
225 LogDocState(aDocumentNode
);
227 LogPresShell(aDocumentNode
);
229 LogDocLoadGroup(aDocumentNode
);
231 LogDocParent(aDocumentNode
);
237 LogShellLoadType(nsIDocShell
* aDocShell
)
239 printf("load type: ");
241 uint32_t loadType
= 0;
242 aDocShell
->GetLoadType(&loadType
);
247 case LOAD_NORMAL_REPLACE
:
248 printf("normal replace; ");
250 case LOAD_NORMAL_EXTERNAL
:
251 printf("normal external; ");
256 case LOAD_NORMAL_BYPASS_CACHE
:
257 printf("normal bypass cache; ");
259 case LOAD_NORMAL_BYPASS_PROXY
:
260 printf("normal bypass proxy; ");
262 case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE
:
263 printf("normal bypass proxy and cache; ");
265 case LOAD_NORMAL_ALLOW_MIXED_CONTENT
:
266 printf("normal allow mixed content; ");
268 case LOAD_RELOAD_NORMAL
:
269 printf("reload normal; ");
271 case LOAD_RELOAD_BYPASS_CACHE
:
272 printf("reload bypass cache; ");
274 case LOAD_RELOAD_BYPASS_PROXY
:
275 printf("reload bypass proxy; ");
277 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
278 printf("reload bypass proxy and cache; ");
280 case LOAD_RELOAD_ALLOW_MIXED_CONTENT
:
281 printf("reload allow mixed content; ");
289 case LOAD_RELOAD_CHARSET_CHANGE
:
290 printf("reload charset change; ");
292 case LOAD_BYPASS_HISTORY
:
293 printf("bypass history; ");
295 case LOAD_STOP_CONTENT
:
296 printf("stop content; ");
298 case LOAD_STOP_CONTENT_AND_REPLACE
:
299 printf("stop content and replace; ");
302 printf("load pushstate; ");
304 case LOAD_REPLACE_BYPASS_CACHE
:
305 printf("replace bypass cache; ");
307 case LOAD_ERROR_PAGE
:
308 printf("error page;");
316 LogRequest(nsIRequest
* aRequest
)
320 aRequest
->GetName(name
);
321 printf(" request spec: %s\n", name
.get());
322 uint32_t loadFlags
= 0;
323 aRequest
->GetLoadFlags(&loadFlags
);
324 printf(" request load flags: %x; ", loadFlags
);
325 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)
326 printf("document uri; ");
327 if (loadFlags
& nsIChannel::LOAD_RETARGETED_DOCUMENT_URI
)
328 printf("retargeted document uri; ");
329 if (loadFlags
& nsIChannel::LOAD_REPLACE
)
331 if (loadFlags
& nsIChannel::LOAD_INITIAL_DOCUMENT_URI
)
332 printf("initial document uri; ");
333 if (loadFlags
& nsIChannel::LOAD_TARGETED
)
334 printf("targeted; ");
335 if (loadFlags
& nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
)
336 printf("call content sniffers; ");
337 if (loadFlags
& nsIChannel::LOAD_CLASSIFY_URI
)
338 printf("classify uri; ");
340 printf(" no request");
345 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 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");
380 ////////////////////////////////////////////////////////////////////////////////
381 // namespace logging:: document life cycle logging methods
383 static const char* sDocLoadTitle
= "DOCLOAD";
384 static const char* sDocCreateTitle
= "DOCCREATE";
385 static const char* sDocDestroyTitle
= "DOCDESTROY";
386 static const char* sDocEventTitle
= "DOCEVENT";
387 static const char* sFocusTitle
= "FOCUS";
390 logging::DocLoad(const char* aMsg
, nsIWebProgress
* aWebProgress
,
391 nsIRequest
* aRequest
, uint32_t aStateFlags
)
393 MsgBegin(sDocLoadTitle
, aMsg
);
395 nsCOMPtr
<nsIDOMWindow
> DOMWindow
;
396 aWebProgress
->GetDOMWindow(getter_AddRefs(DOMWindow
));
397 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(DOMWindow
);
403 nsCOMPtr
<nsIDocument
> documentNode
= window
->GetDoc();
409 DocAccessible
* document
= GetExistingDocAccessible(documentNode
);
411 LogDocInfo(documentNode
, document
);
413 nsCOMPtr
<nsIDocShell
> docShell
= window
->GetDocShell();
415 LogShellLoadType(docShell
);
417 LogRequest(aRequest
);
419 printf(" state flags: %x", aStateFlags
);
421 aWebProgress
->GetIsLoadingDocument(&isDocLoading
);
422 printf(", document is %sloading\n", (isDocLoading
? "" : "not "));
428 logging::DocLoad(const char* aMsg
, nsIDocument
* aDocumentNode
)
430 MsgBegin(sDocLoadTitle
, aMsg
);
432 DocAccessible
* document
= GetExistingDocAccessible(aDocumentNode
);
433 LogDocInfo(aDocumentNode
, document
);
439 logging::DocCompleteLoad(DocAccessible
* aDocument
, bool aIsLoadEventTarget
)
441 MsgBegin(sDocLoadTitle
, "document loaded *completely*");
443 printf(" DOM document: %p, acc document: %p\n",
444 static_cast<void*>(aDocument
->DocumentNode()),
445 static_cast<void*>(aDocument
));
448 LogDocURI(aDocument
->DocumentNode());
452 LogDocAccState(aDocument
);
455 printf(" document is load event target: %s\n",
456 (aIsLoadEventTarget
? "true" : "false"));
462 logging::DocLoadEventFired(AccEvent
* aEvent
)
464 nsAutoCString strEventType
;
465 GetDocLoadEventType(aEvent
, strEventType
);
466 if (!strEventType
.IsEmpty())
467 printf(" fire: %s\n", strEventType
.get());
471 logging::DocLoadEventHandled(AccEvent
* aEvent
)
473 nsAutoCString strEventType
;
474 GetDocLoadEventType(aEvent
, strEventType
);
475 if (strEventType
.IsEmpty())
478 MsgBegin(sDocEventTitle
, "handled '%s' event", strEventType
.get());
480 DocAccessible
* document
= aEvent
->GetAccessible()->AsDoc();
482 LogDocInfo(document
->DocumentNode(), document
);
488 logging::DocCreate(const char* aMsg
, nsIDocument
* aDocumentNode
,
489 DocAccessible
* aDocument
)
491 DocAccessible
* document
= aDocument
?
492 aDocument
: GetExistingDocAccessible(aDocumentNode
);
494 MsgBegin(sDocCreateTitle
, aMsg
);
495 LogDocInfo(aDocumentNode
, document
);
500 logging::DocDestroy(const char* aMsg
, nsIDocument
* aDocumentNode
,
501 DocAccessible
* aDocument
)
503 DocAccessible
* document
= aDocument
?
504 aDocument
: GetExistingDocAccessible(aDocumentNode
);
506 MsgBegin(sDocDestroyTitle
, aMsg
);
507 LogDocInfo(aDocumentNode
, document
);
512 logging::OuterDocDestroy(OuterDocAccessible
* aOuterDoc
)
514 MsgBegin(sDocDestroyTitle
, "outerdoc shutdown");
515 logging::Address("outerdoc", aOuterDoc
);
520 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
523 MsgBegin(sFocusTitle
, aMsg
);
524 AccessibleNNode(aTargetDescr
, aTarget
);
529 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
530 nsINode
* aTargetNode
)
532 MsgBegin(sFocusTitle
, aMsg
);
533 Node(aTargetDescr
, aTargetNode
);
538 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
539 nsISupports
* aTargetThing
)
541 MsgBegin(sFocusTitle
, aMsg
);
544 nsCOMPtr
<nsINode
> targetNode(do_QueryInterface(aTargetThing
));
546 AccessibleNNode(aTargetDescr
, targetNode
);
548 printf(" %s: %p, window\n", aTargetDescr
,
549 static_cast<void*>(aTargetThing
));
556 logging::ActiveItemChangeCausedBy(const char* aCause
, Accessible
* aTarget
)
559 printf(" Caused by: %s\n", aCause
);
560 AccessibleNNode("Item", aTarget
);
565 logging::ActiveWidget(Accessible
* aWidget
)
569 AccessibleNNode("Widget", aWidget
);
570 printf(" Widget is active: %s, has operable items: %s\n",
571 (aWidget
&& aWidget
->IsActiveWidget() ? "true" : "false"),
572 (aWidget
&& aWidget
->AreItemsOperable() ? "true" : "false"));
578 logging::FocusDispatched(Accessible
* aTarget
)
581 AccessibleNNode("A11y target", aTarget
);
586 logging::SelChange(nsISelection
* aSelection
, DocAccessible
* aDocument
,
589 nsCOMPtr
<nsISelectionPrivate
> privSel(do_QueryInterface(aSelection
));
592 privSel
->GetType(&type
);
594 const char* strType
= 0;
595 if (type
== nsISelectionController::SELECTION_NORMAL
)
597 else if (type
== nsISelectionController::SELECTION_SPELLCHECK
)
598 strType
= "spellcheck";
602 bool isIgnored
= !aDocument
|| !aDocument
->IsContentLoaded();
603 printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
604 strType
, (isIgnored
? "ignored" : "pending"), aReason
);
610 logging::MsgBegin(const char* aTitle
, const char* aMsgText
, ...)
612 printf("\nA11Y %s: ", aTitle
);
615 va_start(argptr
, aMsgText
);
616 vprintf(aMsgText
, argptr
);
619 PRIntervalTime time
= PR_IntervalNow();
620 uint32_t mins
= (PR_IntervalToSeconds(time
) / 60) % 60;
621 uint32_t secs
= PR_IntervalToSeconds(time
) % 60;
622 uint32_t msecs
= PR_IntervalToMilliseconds(time
) % 1000;
623 printf("; %02d:%02d.%03d", mins
, secs
, msecs
);
635 logging::SubMsgBegin()
647 logging::MsgEntry(const char* aEntryText
, ...)
652 va_start(argptr
, aEntryText
);
653 vprintf(aEntryText
, argptr
);
660 logging::Text(const char* aText
)
662 printf(" %s\n", aText
);
666 logging::Address(const char* aDescr
, Accessible
* aAcc
)
668 if (!aAcc
->IsDoc()) {
669 printf(" %s accessible: %p, node: %p\n", aDescr
,
670 static_cast<void*>(aAcc
), static_cast<void*>(aAcc
->GetNode()));
673 DocAccessible
* doc
= aAcc
->Document();
674 nsIDocument
* docNode
= doc
->DocumentNode();
675 printf(" document: %p, node: %p\n",
676 static_cast<void*>(doc
), static_cast<void*>(docNode
));
684 logging::Node(const char* aDescr
, nsINode
* aNode
)
689 printf("%s: null\n", aDescr
);
693 if (aNode
->IsNodeOfType(nsINode::eDOCUMENT
)) {
694 printf("%s: %p, document\n", aDescr
, static_cast<void*>(aNode
));
698 nsINode
* parentNode
= aNode
->GetParentNode();
699 int32_t idxInParent
= parentNode
? parentNode
->IndexOf(aNode
) : - 1;
701 if (aNode
->IsNodeOfType(nsINode::eTEXT
)) {
702 printf("%s: %p, text node, idx in parent: %d\n",
703 aDescr
, static_cast<void*>(aNode
), idxInParent
);
707 if (!aNode
->IsElement()) {
708 printf("%s: %p, not accessible node type, idx in parent: %d\n",
709 aDescr
, static_cast<void*>(aNode
), idxInParent
);
713 dom::Element
* elm
= aNode
->AsElement();
716 elm
->Tag()->ToUTF8String(tag
);
718 nsIAtom
* idAtom
= elm
->GetID();
721 idAtom
->ToUTF8String(id
);
723 printf("%s: %p, %s@id='%s', idx in parent: %d\n",
724 aDescr
, static_cast<void*>(elm
), tag
.get(), id
.get(), idxInParent
);
728 logging::Document(DocAccessible
* aDocument
)
730 printf(" Document: %p, document node: %p\n",
731 static_cast<void*>(aDocument
),
732 static_cast<void*>(aDocument
->DocumentNode()));
734 printf(" Document ");
735 LogDocURI(aDocument
->DocumentNode());
740 logging::AccessibleNNode(const char* aDescr
, Accessible
* aAccessible
)
742 printf(" %s: %p; ", aDescr
, static_cast<void*>(aAccessible
));
747 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
749 aAccessible
->Name(name
);
751 printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role
).get(),
752 NS_ConvertUTF16toUTF8(name
).get());
754 nsAutoCString
nodeDescr(aDescr
);
755 nodeDescr
.AppendLiteral(" node");
756 Node(nodeDescr
.get(), aAccessible
->GetNode());
758 Document(aAccessible
->Document());
762 logging::AccessibleNNode(const char* aDescr
, nsINode
* aNode
)
764 DocAccessible
* document
=
765 GetAccService()->GetDocAccessible(aNode
->OwnerDoc());
768 Accessible
* accessible
= document
->GetAccessible(aNode
);
770 AccessibleNNode(aDescr
, accessible
);
775 nsAutoCString
nodeDescr("[not accessible] ");
776 nodeDescr
.Append(aDescr
);
777 Node(nodeDescr
.get(), aNode
);
784 printf(" [contained by not accessible document]:\n");
785 LogDocInfo(aNode
->OwnerDoc(), document
);
790 logging::DOMEvent(const char* aDescr
, nsINode
* aOrigTarget
,
791 const nsAString
& aEventType
)
793 logging::MsgBegin("DOMEvents", "event '%s' %s",
794 NS_ConvertUTF16toUTF8(aEventType
).get(), aDescr
);
795 logging::AccessibleNNode("Target", aOrigTarget
);
802 if (IsEnabled(eStack
)) {
803 printf(" stack: \n");
804 nsTraceRefcnt::WalkTheStack(stdout
);
808 ////////////////////////////////////////////////////////////////////////////////
809 // namespace logging:: initialization
812 logging::IsEnabled(uint32_t aModules
)
814 return sModules
& aModules
;
818 logging::IsEnabled(const nsAString
& aModuleStr
)
820 for (unsigned int idx
= 0; idx
< ArrayLength(sModuleMap
); idx
++) {
821 if (aModuleStr
.EqualsASCII(sModuleMap
[idx
].mStr
))
822 return sModules
& sModuleMap
[idx
].mModule
;
829 logging::Enable(const nsAFlatCString
& aModules
)
831 EnableLogging(aModules
.get());
838 EnableLogging(PR_GetEnv("A11YLOG"));