michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "Logging.h" michael@0: michael@0: #include "Accessible-inl.h" michael@0: #include "AccEvent.h" michael@0: #include "DocAccessible.h" michael@0: #include "nsAccessibilityService.h" michael@0: #include "nsCoreUtils.h" michael@0: #include "OuterDocAccessible.h" michael@0: michael@0: #include "nsDocShellLoadTypes.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsISelectionPrivate.h" michael@0: #include "nsTraceRefcnt.h" michael@0: #include "nsIWebProgress.h" michael@0: #include "prenv.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: #include "nsIURI.h" michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Logging helpers michael@0: michael@0: static uint32_t sModules = 0; michael@0: michael@0: struct ModuleRep { michael@0: const char* mStr; michael@0: logging::EModules mModule; michael@0: }; michael@0: michael@0: static ModuleRep sModuleMap[] = { michael@0: { "docload", logging::eDocLoad }, michael@0: { "doccreate", logging::eDocCreate }, michael@0: { "docdestroy", logging::eDocDestroy }, michael@0: { "doclifecycle", logging::eDocLifeCycle }, michael@0: michael@0: { "events", logging::eEvents }, michael@0: { "platforms", logging::ePlatforms }, michael@0: { "stack", logging::eStack }, michael@0: { "text", logging::eText }, michael@0: { "tree", logging::eTree }, michael@0: michael@0: { "DOMEvents", logging::eDOMEvents }, michael@0: { "focus", logging::eFocus }, michael@0: { "selection", logging::eSelection }, michael@0: { "notifications", logging::eNotifications } michael@0: }; michael@0: michael@0: static void michael@0: EnableLogging(const char* aModulesStr) michael@0: { michael@0: sModules = 0; michael@0: if (!aModulesStr) michael@0: return; michael@0: michael@0: const char* token = aModulesStr; michael@0: while (*token != '\0') { michael@0: size_t tokenLen = strcspn(token, ","); michael@0: for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) { michael@0: if (strncmp(token, sModuleMap[idx].mStr, tokenLen) == 0) { michael@0: #if !defined(MOZ_PROFILING) && (!defined(DEBUG) || defined(MOZ_OPTIMIZE)) michael@0: // Stack tracing on profiling enabled or debug not optimized builds. michael@0: if (strncmp(token, "stack", tokenLen) == 0) michael@0: break; michael@0: #endif michael@0: sModules |= sModuleMap[idx].mModule; michael@0: printf("\n\nmodule enabled: %s\n", sModuleMap[idx].mStr); michael@0: break; michael@0: } michael@0: } michael@0: token += tokenLen; michael@0: michael@0: if (*token == ',') michael@0: token++; // skip ',' char michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogDocURI(nsIDocument* aDocumentNode) michael@0: { michael@0: nsIURI* uri = aDocumentNode->GetDocumentURI(); michael@0: nsAutoCString spec; michael@0: uri->GetSpec(spec); michael@0: printf("uri: %s", spec.get()); michael@0: } michael@0: michael@0: static void michael@0: LogDocShellState(nsIDocument* aDocumentNode) michael@0: { michael@0: printf("docshell busy: "); michael@0: michael@0: nsAutoCString docShellBusy; michael@0: nsCOMPtr docShell = aDocumentNode->GetDocShell(); michael@0: uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE; michael@0: docShell->GetBusyFlags(&busyFlags); michael@0: if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) michael@0: printf("'none'"); michael@0: if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) michael@0: printf("'busy'"); michael@0: if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) michael@0: printf(", 'before page load'"); michael@0: if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) michael@0: printf(", 'page loading'"); michael@0: michael@0: printf("[failed]"); michael@0: } michael@0: michael@0: static void michael@0: LogDocType(nsIDocument* aDocumentNode) michael@0: { michael@0: if (aDocumentNode->IsActive()) { michael@0: bool isContent = nsCoreUtils::IsContentDocument(aDocumentNode); michael@0: printf("%s document", (isContent ? "content" : "chrome")); michael@0: } else { michael@0: printf("document type: [failed]");\ michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogDocShellTree(nsIDocument* aDocumentNode) michael@0: { michael@0: if (aDocumentNode->IsActive()) { michael@0: nsCOMPtr treeItem(aDocumentNode->GetDocShell()); michael@0: nsCOMPtr parentTreeItem; michael@0: treeItem->GetParent(getter_AddRefs(parentTreeItem)); michael@0: nsCOMPtr rootTreeItem; michael@0: treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem)); michael@0: printf("docshell hierarchy, parent: %p, root: %p, is tab document: %s;", michael@0: static_cast(parentTreeItem), static_cast(rootTreeItem), michael@0: (nsCoreUtils::IsTabDocument(aDocumentNode) ? "yes" : "no")); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogDocState(nsIDocument* aDocumentNode) michael@0: { michael@0: const char* docState = nullptr; michael@0: nsIDocument::ReadyState docStateFlag = aDocumentNode->GetReadyStateEnum(); michael@0: switch (docStateFlag) { michael@0: case nsIDocument::READYSTATE_UNINITIALIZED: michael@0: docState = "uninitialized"; michael@0: break; michael@0: case nsIDocument::READYSTATE_LOADING: michael@0: docState = "loading"; michael@0: break; michael@0: case nsIDocument::READYSTATE_INTERACTIVE: michael@0: docState = "interactive"; michael@0: break; michael@0: case nsIDocument::READYSTATE_COMPLETE: michael@0: docState = "complete"; michael@0: break; michael@0: } michael@0: michael@0: printf("doc state: %s", docState); michael@0: printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not "); michael@0: printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not "); michael@0: printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not "); michael@0: printf(", %svisible considering ancestors", aDocumentNode->IsVisibleConsideringAncestors() ? "" : "not "); michael@0: printf(", %sactive", aDocumentNode->IsActive() ? "" : "not "); michael@0: printf(", %sresource", aDocumentNode->IsResourceDoc() ? "" : "not "); michael@0: printf(", has %srole content", michael@0: nsCoreUtils::GetRoleContent(aDocumentNode) ? "" : "no "); michael@0: } michael@0: michael@0: static void michael@0: LogPresShell(nsIDocument* aDocumentNode) michael@0: { michael@0: nsIPresShell* ps = aDocumentNode->GetShell(); michael@0: printf("presshell: %p", static_cast(ps)); michael@0: michael@0: nsIScrollableFrame* sf = nullptr; michael@0: if (ps) { michael@0: printf(", is %s destroying", (ps->IsDestroying() ? "" : "not")); michael@0: sf = ps->GetRootScrollFrameAsScrollable(); michael@0: } michael@0: printf(", root scroll frame: %p", static_cast(sf)); michael@0: } michael@0: michael@0: static void michael@0: LogDocLoadGroup(nsIDocument* aDocumentNode) michael@0: { michael@0: nsCOMPtr loadGroup = aDocumentNode->GetDocumentLoadGroup(); michael@0: printf("load group: %p", static_cast(loadGroup)); michael@0: } michael@0: michael@0: static void michael@0: LogDocParent(nsIDocument* aDocumentNode) michael@0: { michael@0: nsIDocument* parentDoc = aDocumentNode->GetParentDocument(); michael@0: printf("parent id: %p", static_cast(parentDoc)); michael@0: if (parentDoc) { michael@0: printf("\n parent "); michael@0: LogDocURI(parentDoc); michael@0: printf("\n"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogDocInfo(nsIDocument* aDocumentNode, DocAccessible* aDocument) michael@0: { michael@0: printf(" DOM document: %p, acc document: %p\n ", michael@0: static_cast(aDocumentNode), static_cast(aDocument)); michael@0: michael@0: // log document info michael@0: if (aDocumentNode) { michael@0: LogDocURI(aDocumentNode); michael@0: printf("\n "); michael@0: LogDocShellState(aDocumentNode); michael@0: printf("; "); michael@0: LogDocType(aDocumentNode); michael@0: printf("\n "); michael@0: LogDocShellTree(aDocumentNode); michael@0: printf("\n "); michael@0: LogDocState(aDocumentNode); michael@0: printf("\n "); michael@0: LogPresShell(aDocumentNode); michael@0: printf("\n "); michael@0: LogDocLoadGroup(aDocumentNode); michael@0: printf(", "); michael@0: LogDocParent(aDocumentNode); michael@0: printf("\n"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogShellLoadType(nsIDocShell* aDocShell) michael@0: { michael@0: printf("load type: "); michael@0: michael@0: uint32_t loadType = 0; michael@0: aDocShell->GetLoadType(&loadType); michael@0: switch (loadType) { michael@0: case LOAD_NORMAL: michael@0: printf("normal; "); michael@0: break; michael@0: case LOAD_NORMAL_REPLACE: michael@0: printf("normal replace; "); michael@0: break; michael@0: case LOAD_NORMAL_EXTERNAL: michael@0: printf("normal external; "); michael@0: break; michael@0: case LOAD_HISTORY: michael@0: printf("history; "); michael@0: break; michael@0: case LOAD_NORMAL_BYPASS_CACHE: michael@0: printf("normal bypass cache; "); michael@0: break; michael@0: case LOAD_NORMAL_BYPASS_PROXY: michael@0: printf("normal bypass proxy; "); michael@0: break; michael@0: case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE: michael@0: printf("normal bypass proxy and cache; "); michael@0: break; michael@0: case LOAD_NORMAL_ALLOW_MIXED_CONTENT: michael@0: printf("normal allow mixed content; "); michael@0: break; michael@0: case LOAD_RELOAD_NORMAL: michael@0: printf("reload normal; "); michael@0: break; michael@0: case LOAD_RELOAD_BYPASS_CACHE: michael@0: printf("reload bypass cache; "); michael@0: break; michael@0: case LOAD_RELOAD_BYPASS_PROXY: michael@0: printf("reload bypass proxy; "); michael@0: break; michael@0: case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: michael@0: printf("reload bypass proxy and cache; "); michael@0: break; michael@0: case LOAD_RELOAD_ALLOW_MIXED_CONTENT: michael@0: printf("reload allow mixed content; "); michael@0: break; michael@0: case LOAD_LINK: michael@0: printf("link; "); michael@0: break; michael@0: case LOAD_REFRESH: michael@0: printf("refresh; "); michael@0: break; michael@0: case LOAD_RELOAD_CHARSET_CHANGE: michael@0: printf("reload charset change; "); michael@0: break; michael@0: case LOAD_BYPASS_HISTORY: michael@0: printf("bypass history; "); michael@0: break; michael@0: case LOAD_STOP_CONTENT: michael@0: printf("stop content; "); michael@0: break; michael@0: case LOAD_STOP_CONTENT_AND_REPLACE: michael@0: printf("stop content and replace; "); michael@0: break; michael@0: case LOAD_PUSHSTATE: michael@0: printf("load pushstate; "); michael@0: break; michael@0: case LOAD_REPLACE_BYPASS_CACHE: michael@0: printf("replace bypass cache; "); michael@0: break; michael@0: case LOAD_ERROR_PAGE: michael@0: printf("error page;"); michael@0: break; michael@0: default: michael@0: printf("unknown"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogRequest(nsIRequest* aRequest) michael@0: { michael@0: if (aRequest) { michael@0: nsAutoCString name; michael@0: aRequest->GetName(name); michael@0: printf(" request spec: %s\n", name.get()); michael@0: uint32_t loadFlags = 0; michael@0: aRequest->GetLoadFlags(&loadFlags); michael@0: printf(" request load flags: %x; ", loadFlags); michael@0: if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) michael@0: printf("document uri; "); michael@0: if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) michael@0: printf("retargeted document uri; "); michael@0: if (loadFlags & nsIChannel::LOAD_REPLACE) michael@0: printf("replace; "); michael@0: if (loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI) michael@0: printf("initial document uri; "); michael@0: if (loadFlags & nsIChannel::LOAD_TARGETED) michael@0: printf("targeted; "); michael@0: if (loadFlags & nsIChannel::LOAD_CALL_CONTENT_SNIFFERS) michael@0: printf("call content sniffers; "); michael@0: if (loadFlags & nsIChannel::LOAD_CLASSIFY_URI) michael@0: printf("classify uri; "); michael@0: } else { michael@0: printf(" no request"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: LogDocAccState(DocAccessible* aDocument) michael@0: { michael@0: printf("document acc state: "); michael@0: if (aDocument->HasLoadState(DocAccessible::eCompletelyLoaded)) michael@0: printf("completely loaded;"); michael@0: else if (aDocument->HasLoadState(DocAccessible::eReady)) michael@0: printf("ready;"); michael@0: else if (aDocument->HasLoadState(DocAccessible::eDOMLoaded)) michael@0: printf("DOM loaded;"); michael@0: else if (aDocument->HasLoadState(DocAccessible::eTreeConstructed)) michael@0: printf("tree constructed;"); michael@0: } michael@0: michael@0: static void michael@0: GetDocLoadEventType(AccEvent* aEvent, nsACString& aEventType) michael@0: { michael@0: uint32_t type = aEvent->GetEventType(); michael@0: if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED) { michael@0: aEventType.AssignLiteral("load stopped"); michael@0: } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) { michael@0: aEventType.AssignLiteral("load complete"); michael@0: } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD) { michael@0: aEventType.AssignLiteral("reload"); michael@0: } else if (type == nsIAccessibleEvent::EVENT_STATE_CHANGE) { michael@0: AccStateChangeEvent* event = downcast_accEvent(aEvent); michael@0: if (event->GetState() == states::BUSY) { michael@0: aEventType.AssignLiteral("busy "); michael@0: if (event->IsStateEnabled()) michael@0: aEventType.AppendLiteral("true"); michael@0: else michael@0: aEventType.AppendLiteral("false"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // namespace logging:: document life cycle logging methods michael@0: michael@0: static const char* sDocLoadTitle = "DOCLOAD"; michael@0: static const char* sDocCreateTitle = "DOCCREATE"; michael@0: static const char* sDocDestroyTitle = "DOCDESTROY"; michael@0: static const char* sDocEventTitle = "DOCEVENT"; michael@0: static const char* sFocusTitle = "FOCUS"; michael@0: michael@0: void michael@0: logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, uint32_t aStateFlags) michael@0: { michael@0: MsgBegin(sDocLoadTitle, aMsg); michael@0: michael@0: nsCOMPtr DOMWindow; michael@0: aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow)); michael@0: nsCOMPtr window = do_QueryInterface(DOMWindow); michael@0: if (!window) { michael@0: MsgEnd(); michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr documentNode = window->GetDoc(); michael@0: if (!documentNode) { michael@0: MsgEnd(); michael@0: return; michael@0: } michael@0: michael@0: DocAccessible* document = GetExistingDocAccessible(documentNode); michael@0: michael@0: LogDocInfo(documentNode, document); michael@0: michael@0: nsCOMPtr webNav(do_GetInterface(DOMWindow)); michael@0: nsCOMPtr docShell(do_QueryInterface(webNav)); michael@0: printf("\n "); michael@0: LogShellLoadType(docShell); michael@0: printf("\n"); michael@0: LogRequest(aRequest); michael@0: printf("\n"); michael@0: printf(" state flags: %x", aStateFlags); michael@0: bool isDocLoading; michael@0: aWebProgress->GetIsLoadingDocument(&isDocLoading); michael@0: printf(", document is %sloading\n", (isDocLoading ? "" : "not ")); michael@0: michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::DocLoad(const char* aMsg, nsIDocument* aDocumentNode) michael@0: { michael@0: MsgBegin(sDocLoadTitle, aMsg); michael@0: michael@0: DocAccessible* document = GetExistingDocAccessible(aDocumentNode); michael@0: LogDocInfo(aDocumentNode, document); michael@0: michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::DocCompleteLoad(DocAccessible* aDocument, bool aIsLoadEventTarget) michael@0: { michael@0: MsgBegin(sDocLoadTitle, "document loaded *completely*"); michael@0: michael@0: printf(" DOM document: %p, acc document: %p\n", michael@0: static_cast(aDocument->DocumentNode()), michael@0: static_cast(aDocument)); michael@0: michael@0: printf(" "); michael@0: LogDocURI(aDocument->DocumentNode()); michael@0: printf("\n"); michael@0: michael@0: printf(" "); michael@0: LogDocAccState(aDocument); michael@0: printf("\n"); michael@0: michael@0: printf(" document is load event target: %s\n", michael@0: (aIsLoadEventTarget ? "true" : "false")); michael@0: michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::DocLoadEventFired(AccEvent* aEvent) michael@0: { michael@0: nsAutoCString strEventType; michael@0: GetDocLoadEventType(aEvent, strEventType); michael@0: if (!strEventType.IsEmpty()) michael@0: printf(" fire: %s\n", strEventType.get()); michael@0: } michael@0: michael@0: void michael@0: logging::DocLoadEventHandled(AccEvent* aEvent) michael@0: { michael@0: nsAutoCString strEventType; michael@0: GetDocLoadEventType(aEvent, strEventType); michael@0: if (strEventType.IsEmpty()) michael@0: return; michael@0: michael@0: MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get()); michael@0: michael@0: DocAccessible* document = aEvent->GetAccessible()->AsDoc(); michael@0: if (document) michael@0: LogDocInfo(document->DocumentNode(), document); michael@0: michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::DocCreate(const char* aMsg, nsIDocument* aDocumentNode, michael@0: DocAccessible* aDocument) michael@0: { michael@0: DocAccessible* document = aDocument ? michael@0: aDocument : GetExistingDocAccessible(aDocumentNode); michael@0: michael@0: MsgBegin(sDocCreateTitle, aMsg); michael@0: LogDocInfo(aDocumentNode, document); michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::DocDestroy(const char* aMsg, nsIDocument* aDocumentNode, michael@0: DocAccessible* aDocument) michael@0: { michael@0: DocAccessible* document = aDocument ? michael@0: aDocument : GetExistingDocAccessible(aDocumentNode); michael@0: michael@0: MsgBegin(sDocDestroyTitle, aMsg); michael@0: LogDocInfo(aDocumentNode, document); michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc) michael@0: { michael@0: MsgBegin(sDocDestroyTitle, "outerdoc shutdown"); michael@0: logging::Address("outerdoc", aOuterDoc); michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr, michael@0: Accessible* aTarget) michael@0: { michael@0: MsgBegin(sFocusTitle, aMsg); michael@0: AccessibleNNode(aTargetDescr, aTarget); michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr, michael@0: nsINode* aTargetNode) michael@0: { michael@0: MsgBegin(sFocusTitle, aMsg); michael@0: Node(aTargetDescr, aTargetNode); michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr, michael@0: nsISupports* aTargetThing) michael@0: { michael@0: MsgBegin(sFocusTitle, aMsg); michael@0: michael@0: if (aTargetThing) { michael@0: nsCOMPtr targetNode(do_QueryInterface(aTargetThing)); michael@0: if (targetNode) michael@0: AccessibleNNode(aTargetDescr, targetNode); michael@0: else michael@0: printf(" %s: %p, window\n", aTargetDescr, michael@0: static_cast(aTargetThing)); michael@0: } michael@0: michael@0: MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::ActiveItemChangeCausedBy(const char* aCause, Accessible* aTarget) michael@0: { michael@0: SubMsgBegin(); michael@0: printf(" Caused by: %s\n", aCause); michael@0: AccessibleNNode("Item", aTarget); michael@0: SubMsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::ActiveWidget(Accessible* aWidget) michael@0: { michael@0: SubMsgBegin(); michael@0: michael@0: AccessibleNNode("Widget", aWidget); michael@0: printf(" Widget is active: %s, has operable items: %s\n", michael@0: (aWidget && aWidget->IsActiveWidget() ? "true" : "false"), michael@0: (aWidget && aWidget->AreItemsOperable() ? "true" : "false")); michael@0: michael@0: SubMsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::FocusDispatched(Accessible* aTarget) michael@0: { michael@0: SubMsgBegin(); michael@0: AccessibleNNode("A11y target", aTarget); michael@0: SubMsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument, michael@0: int16_t aReason) michael@0: { michael@0: nsCOMPtr privSel(do_QueryInterface(aSelection)); michael@0: michael@0: int16_t type = 0; michael@0: privSel->GetType(&type); michael@0: michael@0: const char* strType = 0; michael@0: if (type == nsISelectionController::SELECTION_NORMAL) michael@0: strType = "normal"; michael@0: else if (type == nsISelectionController::SELECTION_SPELLCHECK) michael@0: strType = "spellcheck"; michael@0: else michael@0: strType = "unknown"; michael@0: michael@0: bool isIgnored = !aDocument || !aDocument->IsContentLoaded(); michael@0: printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n", michael@0: strType, (isIgnored ? "ignored" : "pending"), aReason); michael@0: michael@0: Stack(); michael@0: } michael@0: michael@0: void michael@0: logging::MsgBegin(const char* aTitle, const char* aMsgText, ...) michael@0: { michael@0: printf("\nA11Y %s: ", aTitle); michael@0: michael@0: va_list argptr; michael@0: va_start(argptr, aMsgText); michael@0: vprintf(aMsgText, argptr); michael@0: va_end(argptr); michael@0: michael@0: PRIntervalTime time = PR_IntervalNow(); michael@0: uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60; michael@0: uint32_t secs = PR_IntervalToSeconds(time) % 60; michael@0: uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000; michael@0: printf("; %02d:%02d.%03d", mins, secs, msecs); michael@0: michael@0: printf("\n {\n"); michael@0: } michael@0: michael@0: void michael@0: logging::MsgEnd() michael@0: { michael@0: printf(" }\n"); michael@0: } michael@0: michael@0: void michael@0: logging::SubMsgBegin() michael@0: { michael@0: printf(" {\n"); michael@0: } michael@0: michael@0: void michael@0: logging::SubMsgEnd() michael@0: { michael@0: printf(" }\n"); michael@0: } michael@0: michael@0: void michael@0: logging::MsgEntry(const char* aEntryText, ...) michael@0: { michael@0: printf(" "); michael@0: michael@0: va_list argptr; michael@0: va_start(argptr, aEntryText); michael@0: vprintf(aEntryText, argptr); michael@0: va_end(argptr); michael@0: michael@0: printf("\n"); michael@0: } michael@0: michael@0: void michael@0: logging::Text(const char* aText) michael@0: { michael@0: printf(" %s\n", aText); michael@0: } michael@0: michael@0: void michael@0: logging::Address(const char* aDescr, Accessible* aAcc) michael@0: { michael@0: if (!aAcc->IsDoc()) { michael@0: printf(" %s accessible: %p, node: %p\n", aDescr, michael@0: static_cast(aAcc), static_cast(aAcc->GetNode())); michael@0: } michael@0: michael@0: DocAccessible* doc = aAcc->Document(); michael@0: nsIDocument* docNode = doc->DocumentNode(); michael@0: printf(" document: %p, node: %p\n", michael@0: static_cast(doc), static_cast(docNode)); michael@0: michael@0: printf(" "); michael@0: LogDocURI(docNode); michael@0: printf("\n"); michael@0: } michael@0: michael@0: void michael@0: logging::Node(const char* aDescr, nsINode* aNode) michael@0: { michael@0: printf(" "); michael@0: michael@0: if (!aNode) { michael@0: printf("%s: null\n", aDescr); michael@0: return; michael@0: } michael@0: michael@0: if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { michael@0: printf("%s: %p, document\n", aDescr, static_cast(aNode)); michael@0: return; michael@0: } michael@0: michael@0: nsINode* parentNode = aNode->GetParentNode(); michael@0: int32_t idxInParent = parentNode ? parentNode->IndexOf(aNode) : - 1; michael@0: michael@0: if (aNode->IsNodeOfType(nsINode::eTEXT)) { michael@0: printf("%s: %p, text node, idx in parent: %d\n", michael@0: aDescr, static_cast(aNode), idxInParent); michael@0: return; michael@0: } michael@0: michael@0: if (!aNode->IsElement()) { michael@0: printf("%s: %p, not accessible node type, idx in parent: %d\n", michael@0: aDescr, static_cast(aNode), idxInParent); michael@0: return; michael@0: } michael@0: michael@0: dom::Element* elm = aNode->AsElement(); michael@0: michael@0: nsAutoCString tag; michael@0: elm->Tag()->ToUTF8String(tag); michael@0: michael@0: nsIAtom* idAtom = elm->GetID(); michael@0: nsAutoCString id; michael@0: if (idAtom) michael@0: idAtom->ToUTF8String(id); michael@0: michael@0: printf("%s: %p, %s@id='%s', idx in parent: %d\n", michael@0: aDescr, static_cast(elm), tag.get(), id.get(), idxInParent); michael@0: } michael@0: michael@0: void michael@0: logging::Document(DocAccessible* aDocument) michael@0: { michael@0: printf(" Document: %p, document node: %p\n", michael@0: static_cast(aDocument), michael@0: static_cast(aDocument->DocumentNode())); michael@0: michael@0: printf(" Document "); michael@0: LogDocURI(aDocument->DocumentNode()); michael@0: printf("\n"); michael@0: } michael@0: michael@0: void michael@0: logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible) michael@0: { michael@0: printf(" %s: %p; ", aDescr, static_cast(aAccessible)); michael@0: if (!aAccessible) michael@0: return; michael@0: michael@0: nsAutoString role; michael@0: GetAccService()->GetStringRole(aAccessible->Role(), role); michael@0: nsAutoString name; michael@0: aAccessible->Name(name); michael@0: michael@0: printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(), michael@0: NS_ConvertUTF16toUTF8(name).get()); michael@0: michael@0: nsAutoCString nodeDescr(aDescr); michael@0: nodeDescr.AppendLiteral(" node"); michael@0: Node(nodeDescr.get(), aAccessible->GetNode()); michael@0: michael@0: Document(aAccessible->Document()); michael@0: } michael@0: michael@0: void michael@0: logging::AccessibleNNode(const char* aDescr, nsINode* aNode) michael@0: { michael@0: DocAccessible* document = michael@0: GetAccService()->GetDocAccessible(aNode->OwnerDoc()); michael@0: michael@0: if (document) { michael@0: Accessible* accessible = document->GetAccessible(aNode); michael@0: if (accessible) { michael@0: AccessibleNNode(aDescr, accessible); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: nsAutoCString nodeDescr("[not accessible] "); michael@0: nodeDescr.Append(aDescr); michael@0: Node(nodeDescr.get(), aNode); michael@0: michael@0: if (document) { michael@0: Document(document); michael@0: return; michael@0: } michael@0: michael@0: printf(" [contained by not accessible document]:\n"); michael@0: LogDocInfo(aNode->OwnerDoc(), document); michael@0: printf("\n"); michael@0: } michael@0: michael@0: void michael@0: logging::DOMEvent(const char* aDescr, nsINode* aOrigTarget, michael@0: const nsAString& aEventType) michael@0: { michael@0: logging::MsgBegin("DOMEvents", "event '%s' %s", michael@0: NS_ConvertUTF16toUTF8(aEventType).get(), aDescr); michael@0: logging::AccessibleNNode("Target", aOrigTarget); michael@0: logging::MsgEnd(); michael@0: } michael@0: michael@0: void michael@0: logging::Stack() michael@0: { michael@0: if (IsEnabled(eStack)) { michael@0: printf(" stack: \n"); michael@0: nsTraceRefcnt::WalkTheStack(stdout); michael@0: } michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // namespace logging:: initialization michael@0: michael@0: bool michael@0: logging::IsEnabled(uint32_t aModules) michael@0: { michael@0: return sModules & aModules; michael@0: } michael@0: michael@0: bool michael@0: logging::IsEnabled(const nsAString& aModuleStr) michael@0: { michael@0: for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) { michael@0: if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr)) michael@0: return sModules & sModuleMap[idx].mModule; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: logging::Enable(const nsAFlatCString& aModules) michael@0: { michael@0: EnableLogging(aModules.get()); michael@0: } michael@0: michael@0: michael@0: void michael@0: logging::CheckEnv() michael@0: { michael@0: EnableLogging(PR_GetEnv("A11YLOG")); michael@0: }