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 "nsTraceRefcntImpl.h"
21 #include "nsIWebProgress.h"
23 #include "nsIDocShellTreeItem.h"
25 using namespace mozilla
;
26 using namespace mozilla::a11y
;
28 ////////////////////////////////////////////////////////////////////////////////
31 static uint32_t sModules
= 0;
35 logging::EModules mModule
;
38 static ModuleRep sModuleMap
[] = {
39 { "docload", logging::eDocLoad
},
40 { "doccreate", logging::eDocCreate
},
41 { "docdestroy", logging::eDocDestroy
},
42 { "doclifecycle", logging::eDocLifeCycle
},
44 { "events", logging::eEvents
},
45 { "platforms", logging::ePlatforms
},
46 { "stack", logging::eStack
},
47 { "text", logging::eText
},
48 { "tree", logging::eTree
},
50 { "DOMEvents", logging::eDOMEvents
},
51 { "focus", logging::eFocus
},
52 { "selection", logging::eSelection
},
53 { "notifications", logging::eNotifications
}
57 EnableLogging(const char* aModulesStr
)
63 const char* token
= aModulesStr
;
64 while (*token
!= '\0') {
65 size_t tokenLen
= strcspn(token
, ",");
66 for (unsigned int idx
= 0; idx
< ArrayLength(sModuleMap
); idx
++) {
67 if (strncmp(token
, sModuleMap
[idx
].mStr
, tokenLen
) == 0) {
68 #if !defined(MOZ_PROFILING) && (!defined(DEBUG) || defined(MOZ_OPTIMIZE))
69 // Stack tracing on profiling enabled or debug not optimized builds.
70 if (strncmp(token
, "stack", tokenLen
) == 0)
73 sModules
|= sModuleMap
[idx
].mModule
;
74 printf("\n\nmodule enabled: %s\n", sModuleMap
[idx
].mStr
);
81 token
++; // skip ',' char
86 LogDocURI(nsIDocument
* aDocumentNode
)
88 nsIURI
* uri
= aDocumentNode
->GetDocumentURI();
91 printf("uri: %s", spec
.get());
95 LogDocShellState(nsIDocument
* aDocumentNode
)
97 printf("docshell busy: ");
99 nsAutoCString docShellBusy
;
100 nsCOMPtr
<nsISupports
> container
= aDocumentNode
->GetContainer();
102 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(container
);
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'");
119 LogDocType(nsIDocument
* aDocumentNode
)
121 if (aDocumentNode
->IsActive()) {
122 bool isContent
= nsCoreUtils::IsContentDocument(aDocumentNode
);
123 printf("%s document", (isContent
? "content" : "chrome"));
125 printf("document type: [failed]");\
130 LogDocShellTree(nsIDocument
* aDocumentNode
)
132 if (aDocumentNode
->IsActive()) {
133 nsCOMPtr
<nsISupports
> container
= aDocumentNode
->GetContainer();
134 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(do_QueryInterface(container
));
135 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
136 treeItem
->GetParent(getter_AddRefs(parentTreeItem
));
137 nsCOMPtr
<nsIDocShellTreeItem
> rootTreeItem
;
138 treeItem
->GetRootTreeItem(getter_AddRefs(rootTreeItem
));
139 printf("docshell hierarchy, parent: %p, root: %p, is tab document: %s;",
140 static_cast<void*>(parentTreeItem
), static_cast<void*>(rootTreeItem
),
141 (nsCoreUtils::IsTabDocument(aDocumentNode
) ? "yes" : "no"));
146 LogDocState(nsIDocument
* aDocumentNode
)
148 const char* docState
= nullptr;
149 nsIDocument::ReadyState docStateFlag
= aDocumentNode
->GetReadyStateEnum();
150 switch (docStateFlag
) {
151 case nsIDocument::READYSTATE_UNINITIALIZED
:
152 docState
= "uninitialized";
154 case nsIDocument::READYSTATE_LOADING
:
155 docState
= "loading";
157 case nsIDocument::READYSTATE_INTERACTIVE
:
158 docState
= "interactive";
160 case nsIDocument::READYSTATE_COMPLETE
:
161 docState
= "complete";
165 printf("doc state: %s", docState
);
166 printf(", %sinitial", aDocumentNode
->IsInitialDocument() ? "" : "not ");
167 printf(", %sshowing", aDocumentNode
->IsShowing() ? "" : "not ");
168 printf(", %svisible", aDocumentNode
->IsVisible() ? "" : "not ");
169 printf(", %svisible considering ancestors", aDocumentNode
->IsVisibleConsideringAncestors() ? "" : "not ");
170 printf(", %sactive", aDocumentNode
->IsActive() ? "" : "not ");
171 printf(", %sresource", aDocumentNode
->IsResourceDoc() ? "" : "not ");
172 printf(", has %srole content",
173 nsCoreUtils::GetRoleContent(aDocumentNode
) ? "" : "no ");
177 LogPresShell(nsIDocument
* aDocumentNode
)
179 nsIPresShell
* ps
= aDocumentNode
->GetShell();
180 printf("presshell: %p", static_cast<void*>(ps
));
182 nsIScrollableFrame
* sf
= nullptr;
184 printf(", is %s destroying", (ps
->IsDestroying() ? "" : "not"));
185 sf
= ps
->GetRootScrollFrameAsScrollable();
187 printf(", root scroll frame: %p", static_cast<void*>(sf
));
191 LogDocLoadGroup(nsIDocument
* aDocumentNode
)
193 nsCOMPtr
<nsILoadGroup
> loadGroup
= aDocumentNode
->GetDocumentLoadGroup();
194 printf("load group: %p", static_cast<void*>(loadGroup
));
198 LogDocParent(nsIDocument
* aDocumentNode
)
200 nsIDocument
* parentDoc
= aDocumentNode
->GetParentDocument();
201 printf("parent id: %p", static_cast<void*>(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_RELOAD_NORMAL
:
266 printf("reload normal; ");
268 case LOAD_RELOAD_BYPASS_CACHE
:
269 printf("reload bypass cache; ");
271 case LOAD_RELOAD_BYPASS_PROXY
:
272 printf("reload bypass proxy; ");
274 case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE
:
275 printf("reload bypass proxy and cache; ");
277 case LOAD_RELOAD_ALLOW_MIXED_CONTENT
:
278 printf("reload allow mixed content; ");
286 case LOAD_RELOAD_CHARSET_CHANGE
:
287 printf("reload charset change; ");
289 case LOAD_BYPASS_HISTORY
:
290 printf("bypass history; ");
292 case LOAD_STOP_CONTENT
:
293 printf("stop content; ");
295 case LOAD_STOP_CONTENT_AND_REPLACE
:
296 printf("stop content and replace; ");
299 printf("load pushstate; ");
301 case LOAD_REPLACE_BYPASS_CACHE
:
302 printf("replace bypass cache; ");
304 case LOAD_ERROR_PAGE
:
305 printf("error page;");
313 LogRequest(nsIRequest
* aRequest
)
317 aRequest
->GetName(name
);
318 printf(" request spec: %s\n", name
.get());
319 uint32_t loadFlags
= 0;
320 aRequest
->GetLoadFlags(&loadFlags
);
321 printf(" request load flags: %x; ", loadFlags
);
322 if (loadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)
323 printf("document uri; ");
324 if (loadFlags
& nsIChannel::LOAD_RETARGETED_DOCUMENT_URI
)
325 printf("retargeted document uri; ");
326 if (loadFlags
& nsIChannel::LOAD_REPLACE
)
328 if (loadFlags
& nsIChannel::LOAD_INITIAL_DOCUMENT_URI
)
329 printf("initial document uri; ");
330 if (loadFlags
& nsIChannel::LOAD_TARGETED
)
331 printf("targeted; ");
332 if (loadFlags
& nsIChannel::LOAD_CALL_CONTENT_SNIFFERS
)
333 printf("call content sniffers; ");
334 if (loadFlags
& nsIChannel::LOAD_CLASSIFY_URI
)
335 printf("classify uri; ");
337 printf(" no request");
342 LogDocAccState(DocAccessible
* aDocument
)
344 printf("document acc state: ");
345 if (aDocument
->HasLoadState(DocAccessible::eCompletelyLoaded
))
346 printf("completely loaded;");
347 else if (aDocument
->HasLoadState(DocAccessible::eReady
))
349 else if (aDocument
->HasLoadState(DocAccessible::eDOMLoaded
))
350 printf("DOM loaded;");
351 else if (aDocument
->HasLoadState(DocAccessible::eTreeConstructed
))
352 printf("tree constructed;");
356 GetDocLoadEventType(AccEvent
* aEvent
, nsACString
& aEventType
)
358 uint32_t type
= aEvent
->GetEventType();
359 if (type
== nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED
) {
360 aEventType
.AssignLiteral("load stopped");
361 } else if (type
== nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE
) {
362 aEventType
.AssignLiteral("load complete");
363 } else if (type
== nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD
) {
364 aEventType
.AssignLiteral("reload");
365 } else if (type
== nsIAccessibleEvent::EVENT_STATE_CHANGE
) {
366 AccStateChangeEvent
* event
= downcast_accEvent(aEvent
);
367 if (event
->GetState() == states::BUSY
) {
368 aEventType
.AssignLiteral("busy ");
369 if (event
->IsStateEnabled())
370 aEventType
.AppendLiteral("true");
372 aEventType
.AppendLiteral("false");
377 ////////////////////////////////////////////////////////////////////////////////
378 // namespace logging:: document life cycle logging methods
380 static const char* sDocLoadTitle
= "DOCLOAD";
381 static const char* sDocCreateTitle
= "DOCCREATE";
382 static const char* sDocDestroyTitle
= "DOCDESTROY";
383 static const char* sDocEventTitle
= "DOCEVENT";
384 static const char* sFocusTitle
= "FOCUS";
387 logging::DocLoad(const char* aMsg
, nsIWebProgress
* aWebProgress
,
388 nsIRequest
* aRequest
, uint32_t aStateFlags
)
390 MsgBegin(sDocLoadTitle
, aMsg
);
392 nsCOMPtr
<nsIDOMWindow
> DOMWindow
;
393 aWebProgress
->GetDOMWindow(getter_AddRefs(DOMWindow
));
399 nsCOMPtr
<nsIDOMDocument
> DOMDocument
;
400 DOMWindow
->GetDocument(getter_AddRefs(DOMDocument
));
406 nsCOMPtr
<nsIDocument
> documentNode(do_QueryInterface(DOMDocument
));
407 DocAccessible
* document
= GetExistingDocAccessible(documentNode
);
409 LogDocInfo(documentNode
, document
);
411 nsCOMPtr
<nsIWebNavigation
> webNav(do_GetInterface(DOMWindow
));
412 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(webNav
));
414 LogShellLoadType(docShell
);
416 LogRequest(aRequest
);
418 printf(" state flags: %x", aStateFlags
);
420 aWebProgress
->GetIsLoadingDocument(&isDocLoading
);
421 printf(", document is %sloading\n", (isDocLoading
? "" : "not "));
427 logging::DocLoad(const char* aMsg
, nsIDocument
* aDocumentNode
)
429 MsgBegin(sDocLoadTitle
, aMsg
);
431 DocAccessible
* document
= GetExistingDocAccessible(aDocumentNode
);
432 LogDocInfo(aDocumentNode
, document
);
438 logging::DocCompleteLoad(DocAccessible
* aDocument
, bool aIsLoadEventTarget
)
440 MsgBegin(sDocLoadTitle
, "document loaded *completely*");
442 printf(" DOM document: %p, acc document: %p\n",
443 static_cast<void*>(aDocument
->DocumentNode()),
444 static_cast<void*>(aDocument
));
447 LogDocURI(aDocument
->DocumentNode());
451 LogDocAccState(aDocument
);
454 printf(" document is load event target: %s\n",
455 (aIsLoadEventTarget
? "true" : "false"));
461 logging::DocLoadEventFired(AccEvent
* aEvent
)
463 nsAutoCString strEventType
;
464 GetDocLoadEventType(aEvent
, strEventType
);
465 if (!strEventType
.IsEmpty())
466 printf(" fire: %s\n", strEventType
.get());
470 logging::DocLoadEventHandled(AccEvent
* aEvent
)
472 nsAutoCString strEventType
;
473 GetDocLoadEventType(aEvent
, strEventType
);
474 if (strEventType
.IsEmpty())
477 MsgBegin(sDocEventTitle
, "handled '%s' event", strEventType
.get());
479 DocAccessible
* document
= aEvent
->GetAccessible()->AsDoc();
481 LogDocInfo(document
->DocumentNode(), document
);
487 logging::DocCreate(const char* aMsg
, nsIDocument
* aDocumentNode
,
488 DocAccessible
* aDocument
)
490 DocAccessible
* document
= aDocument
?
491 aDocument
: GetExistingDocAccessible(aDocumentNode
);
493 MsgBegin(sDocCreateTitle
, aMsg
);
494 LogDocInfo(aDocumentNode
, document
);
499 logging::DocDestroy(const char* aMsg
, nsIDocument
* aDocumentNode
,
500 DocAccessible
* aDocument
)
502 DocAccessible
* document
= aDocument
?
503 aDocument
: GetExistingDocAccessible(aDocumentNode
);
505 MsgBegin(sDocDestroyTitle
, aMsg
);
506 LogDocInfo(aDocumentNode
, document
);
511 logging::OuterDocDestroy(OuterDocAccessible
* aOuterDoc
)
513 MsgBegin(sDocDestroyTitle
, "outerdoc shutdown");
514 logging::Address("outerdoc", aOuterDoc
);
519 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
522 MsgBegin(sFocusTitle
, aMsg
);
523 AccessibleNNode(aTargetDescr
, aTarget
);
528 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
529 nsINode
* aTargetNode
)
531 MsgBegin(sFocusTitle
, aMsg
);
532 Node(aTargetDescr
, aTargetNode
);
537 logging::FocusNotificationTarget(const char* aMsg
, const char* aTargetDescr
,
538 nsISupports
* aTargetThing
)
540 MsgBegin(sFocusTitle
, aMsg
);
543 nsCOMPtr
<nsINode
> targetNode(do_QueryInterface(aTargetThing
));
545 AccessibleNNode(aTargetDescr
, targetNode
);
547 printf(" %s: %p, window\n", aTargetDescr
,
548 static_cast<void*>(aTargetThing
));
555 logging::ActiveItemChangeCausedBy(const char* aCause
, Accessible
* aTarget
)
558 printf(" Caused by: %s\n", aCause
);
559 AccessibleNNode("Item", aTarget
);
564 logging::ActiveWidget(Accessible
* aWidget
)
568 AccessibleNNode("Widget", aWidget
);
569 printf(" Widget is active: %s, has operable items: %s\n",
570 (aWidget
&& aWidget
->IsActiveWidget() ? "true" : "false"),
571 (aWidget
&& aWidget
->AreItemsOperable() ? "true" : "false"));
577 logging::FocusDispatched(Accessible
* aTarget
)
580 AccessibleNNode("A11y target", aTarget
);
585 logging::SelChange(nsISelection
* aSelection
, DocAccessible
* aDocument
)
587 nsCOMPtr
<nsISelectionPrivate
> privSel(do_QueryInterface(aSelection
));
590 privSel
->GetType(&type
);
592 const char* strType
= 0;
593 if (type
== nsISelectionController::SELECTION_NORMAL
)
595 else if (type
== nsISelectionController::SELECTION_SPELLCHECK
)
596 strType
= "spellcheck";
600 bool isIgnored
= !aDocument
|| !aDocument
->IsContentLoaded();
601 printf("\nSelection changed, selection type: %s, notification %s\n",
602 strType
, (isIgnored
? "ignored" : "pending"));
606 logging::MsgBegin(const char* aTitle
, const char* aMsgText
, ...)
608 printf("\nA11Y %s: ", aTitle
);
611 va_start(argptr
, aMsgText
);
612 vprintf(aMsgText
, argptr
);
615 PRIntervalTime time
= PR_IntervalNow();
616 uint32_t mins
= (PR_IntervalToSeconds(time
) / 60) % 60;
617 uint32_t secs
= PR_IntervalToSeconds(time
) % 60;
618 uint32_t msecs
= PR_IntervalToMilliseconds(time
) % 1000;
619 printf("; %02d:%02d.%03d", mins
, secs
, msecs
);
631 logging::SubMsgBegin()
643 logging::MsgEntry(const char* aEntryText
, ...)
648 va_start(argptr
, aEntryText
);
649 vprintf(aEntryText
, argptr
);
656 logging::Text(const char* aText
)
658 printf(" %s\n", aText
);
662 logging::Address(const char* aDescr
, Accessible
* aAcc
)
664 if (!aAcc
->IsDoc()) {
665 printf(" %s accessible: %p, node: %p\n", aDescr
,
666 static_cast<void*>(aAcc
), static_cast<void*>(aAcc
->GetNode()));
669 DocAccessible
* doc
= aAcc
->Document();
670 nsIDocument
* docNode
= doc
->DocumentNode();
671 printf(" document: %p, node: %p\n",
672 static_cast<void*>(doc
), static_cast<void*>(docNode
));
680 logging::Node(const char* aDescr
, nsINode
* aNode
)
685 printf("%s: null\n", aDescr
);
689 if (aNode
->IsNodeOfType(nsINode::eDOCUMENT
)) {
690 printf("%s: %p, document\n", aDescr
, static_cast<void*>(aNode
));
694 nsINode
* parentNode
= aNode
->GetParentNode();
695 int32_t idxInParent
= parentNode
? parentNode
->IndexOf(aNode
) : - 1;
697 if (aNode
->IsNodeOfType(nsINode::eTEXT
)) {
698 printf("%s: %p, text node, idx in parent: %d\n",
699 aDescr
, static_cast<void*>(aNode
), idxInParent
);
703 if (!aNode
->IsElement()) {
704 printf("%s: %p, not accessible node type, idx in parent: %d\n",
705 aDescr
, static_cast<void*>(aNode
), idxInParent
);
709 dom::Element
* elm
= aNode
->AsElement();
712 elm
->Tag()->ToUTF8String(tag
);
714 nsIAtom
* idAtom
= elm
->GetID();
717 idAtom
->ToUTF8String(id
);
719 printf("%s: %p, %s@id='%s', idx in parent: %d\n",
720 aDescr
, static_cast<void*>(elm
), tag
.get(), id
.get(), idxInParent
);
724 logging::Document(DocAccessible
* aDocument
)
726 printf(" Document: %p, document node: %p\n",
727 static_cast<void*>(aDocument
),
728 static_cast<void*>(aDocument
->DocumentNode()));
730 printf(" Document ");
731 LogDocURI(aDocument
->DocumentNode());
736 logging::AccessibleNNode(const char* aDescr
, Accessible
* aAccessible
)
738 printf(" %s: %p; ", aDescr
, static_cast<void*>(aAccessible
));
743 GetAccService()->GetStringRole(aAccessible
->Role(), role
);
745 aAccessible
->Name(name
);
747 printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role
).get(),
748 NS_ConvertUTF16toUTF8(name
).get());
750 nsAutoCString
nodeDescr(aDescr
);
751 nodeDescr
.AppendLiteral(" node");
752 Node(nodeDescr
.get(), aAccessible
->GetNode());
754 Document(aAccessible
->Document());
758 logging::AccessibleNNode(const char* aDescr
, nsINode
* aNode
)
760 DocAccessible
* document
=
761 GetAccService()->GetDocAccessible(aNode
->OwnerDoc());
764 Accessible
* accessible
= document
->GetAccessible(aNode
);
766 AccessibleNNode(aDescr
, accessible
);
771 nsAutoCString
nodeDescr("[not accessible] ");
772 nodeDescr
.Append(aDescr
);
773 Node(nodeDescr
.get(), aNode
);
780 printf(" [contained by not accessible document]:\n");
781 LogDocInfo(aNode
->OwnerDoc(), document
);
786 logging::DOMEvent(const char* aDescr
, nsINode
* aOrigTarget
,
787 const nsAString
& aEventType
)
789 logging::MsgBegin("DOMEvents", "event '%s' %s",
790 NS_ConvertUTF16toUTF8(aEventType
).get(), aDescr
);
791 logging::AccessibleNNode("Target", aOrigTarget
);
798 if (IsEnabled(eStack
)) {
799 printf(" stack: \n");
800 nsTraceRefcntImpl::WalkTheStack(stdout
);
804 ////////////////////////////////////////////////////////////////////////////////
805 // namespace logging:: initialization
808 logging::IsEnabled(uint32_t aModules
)
810 return sModules
& aModules
;
814 logging::IsEnabled(const nsAString
& aModuleStr
)
816 for (unsigned int idx
= 0; idx
< ArrayLength(sModuleMap
); idx
++) {
817 if (aModuleStr
.EqualsASCII(sModuleMap
[idx
].mStr
))
818 return sModules
& sModuleMap
[idx
].mModule
;
825 logging::Enable(const nsAFlatCString
& aModules
)
827 EnableLogging(aModules
.get());
834 EnableLogging(PR_GetEnv("A11YLOG"));