Logging.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "Logging.h"
  6. #include "Accessible-inl.h"
  7. #include "AccEvent.h"
  8. #include "DocAccessible.h"
  9. #include "DocAccessible-inl.h"
  10. #include "nsAccessibilityService.h"
  11. #include "nsCoreUtils.h"
  12. #include "OuterDocAccessible.h"
  13. #include "nsDocShellLoadTypes.h"
  14. #include "nsIChannel.h"
  15. #include "nsIInterfaceRequestorUtils.h"
  16. #include "nsISelectionPrivate.h"
  17. #include "nsTraceRefcnt.h"
  18. #include "nsIWebProgress.h"
  19. #include "prenv.h"
  20. #include "nsIDocShellTreeItem.h"
  21. #include "nsIURI.h"
  22. #include "mozilla/dom/Element.h"
  23. #include "mozilla/dom/HTMLBodyElement.h"
  24. using namespace mozilla;
  25. using namespace mozilla::a11y;
  26. ////////////////////////////////////////////////////////////////////////////////
  27. // Logging helpers
  28. static uint32_t sModules = 0;
  29. struct ModuleRep {
  30. const char* mStr;
  31. logging::EModules mModule;
  32. };
  33. static ModuleRep sModuleMap[] = {
  34. { "docload", logging::eDocLoad },
  35. { "doccreate", logging::eDocCreate },
  36. { "docdestroy", logging::eDocDestroy },
  37. { "doclifecycle", logging::eDocLifeCycle },
  38. { "events", logging::eEvents },
  39. { "eventTree", logging::eEventTree },
  40. { "platforms", logging::ePlatforms },
  41. { "text", logging::eText },
  42. { "tree", logging::eTree },
  43. { "DOMEvents", logging::eDOMEvents },
  44. { "focus", logging::eFocus },
  45. { "selection", logging::eSelection },
  46. { "notifications", logging::eNotifications },
  47. { "stack", logging::eStack },
  48. { "verbose", logging::eVerbose }
  49. };
  50. static void
  51. EnableLogging(const char* aModulesStr)
  52. {
  53. sModules = 0;
  54. if (!aModulesStr)
  55. return;
  56. const char* token = aModulesStr;
  57. while (*token != '\0') {
  58. size_t tokenLen = strcspn(token, ",");
  59. for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) {
  60. if (strncmp(token, sModuleMap[idx].mStr, tokenLen) == 0) {
  61. #if !defined(MOZ_PROFILING) && (!defined(DEBUG) || defined(MOZ_OPTIMIZE))
  62. // Stack tracing on profiling enabled or debug not optimized builds.
  63. if (strncmp(token, "stack", tokenLen) == 0)
  64. break;
  65. #endif
  66. sModules |= sModuleMap[idx].mModule;
  67. printf("\n\nmodule enabled: %s\n", sModuleMap[idx].mStr);
  68. break;
  69. }
  70. }
  71. token += tokenLen;
  72. if (*token == ',')
  73. token++; // skip ',' char
  74. }
  75. }
  76. static void
  77. LogDocURI(nsIDocument* aDocumentNode)
  78. {
  79. printf("uri: %s", aDocumentNode->GetDocumentURI()->GetSpecOrDefault().get());
  80. }
  81. static void
  82. LogDocShellState(nsIDocument* aDocumentNode)
  83. {
  84. printf("docshell busy: ");
  85. nsAutoCString docShellBusy;
  86. nsCOMPtr<nsIDocShell> docShell = aDocumentNode->GetDocShell();
  87. uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
  88. docShell->GetBusyFlags(&busyFlags);
  89. if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) {
  90. printf("'none'");
  91. }
  92. if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) {
  93. printf("'busy'");
  94. }
  95. if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) {
  96. printf(", 'before page load'");
  97. }
  98. if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
  99. printf(", 'page loading'");
  100. }
  101. }
  102. static void
  103. LogDocType(nsIDocument* aDocumentNode)
  104. {
  105. if (aDocumentNode->IsActive()) {
  106. bool isContent = nsCoreUtils::IsContentDocument(aDocumentNode);
  107. printf("%s document", (isContent ? "content" : "chrome"));
  108. } else {
  109. printf("document type: [failed]");\
  110. }
  111. }
  112. static void
  113. LogDocShellTree(nsIDocument* aDocumentNode)
  114. {
  115. if (aDocumentNode->IsActive()) {
  116. nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
  117. nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
  118. treeItem->GetParent(getter_AddRefs(parentTreeItem));
  119. nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
  120. treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
  121. printf("docshell hierarchy, parent: %p, root: %p, is tab document: %s;",
  122. static_cast<void*>(parentTreeItem), static_cast<void*>(rootTreeItem),
  123. (nsCoreUtils::IsTabDocument(aDocumentNode) ? "yes" : "no"));
  124. }
  125. }
  126. static void
  127. LogDocState(nsIDocument* aDocumentNode)
  128. {
  129. const char* docState = nullptr;
  130. nsIDocument::ReadyState docStateFlag = aDocumentNode->GetReadyStateEnum();
  131. switch (docStateFlag) {
  132. case nsIDocument::READYSTATE_UNINITIALIZED:
  133. docState = "uninitialized";
  134. break;
  135. case nsIDocument::READYSTATE_LOADING:
  136. docState = "loading";
  137. break;
  138. case nsIDocument::READYSTATE_INTERACTIVE:
  139. docState = "interactive";
  140. break;
  141. case nsIDocument::READYSTATE_COMPLETE:
  142. docState = "complete";
  143. break;
  144. }
  145. printf("doc state: %s", docState);
  146. printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not ");
  147. printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not ");
  148. printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not ");
  149. printf(", %svisible considering ancestors", aDocumentNode->IsVisibleConsideringAncestors() ? "" : "not ");
  150. printf(", %sactive", aDocumentNode->IsActive() ? "" : "not ");
  151. printf(", %sresource", aDocumentNode->IsResourceDoc() ? "" : "not ");
  152. dom::Element* rootEl = aDocumentNode->GetBodyElement();
  153. if (!rootEl) {
  154. rootEl = aDocumentNode->GetRootElement();
  155. }
  156. printf(", has %srole content", rootEl ? "" : "no ");
  157. }
  158. static void
  159. LogPresShell(nsIDocument* aDocumentNode)
  160. {
  161. nsIPresShell* ps = aDocumentNode->GetShell();
  162. printf("presshell: %p", static_cast<void*>(ps));
  163. nsIScrollableFrame* sf = nullptr;
  164. if (ps) {
  165. printf(", is %s destroying", (ps->IsDestroying() ? "" : "not"));
  166. sf = ps->GetRootScrollFrameAsScrollable();
  167. }
  168. printf(", root scroll frame: %p", static_cast<void*>(sf));
  169. }
  170. static void
  171. LogDocLoadGroup(nsIDocument* aDocumentNode)
  172. {
  173. nsCOMPtr<nsILoadGroup> loadGroup = aDocumentNode->GetDocumentLoadGroup();
  174. printf("load group: %p", static_cast<void*>(loadGroup));
  175. }
  176. static void
  177. LogDocParent(nsIDocument* aDocumentNode)
  178. {
  179. nsIDocument* parentDoc = aDocumentNode->GetParentDocument();
  180. printf("parent DOM document: %p", static_cast<void*>(parentDoc));
  181. if (parentDoc) {
  182. printf(", parent acc document: %p",
  183. static_cast<void*>(GetExistingDocAccessible(parentDoc)));
  184. printf("\n parent ");
  185. LogDocURI(parentDoc);
  186. printf("\n");
  187. }
  188. }
  189. static void
  190. LogDocInfo(nsIDocument* aDocumentNode, DocAccessible* aDocument)
  191. {
  192. printf(" DOM document: %p, acc document: %p\n ",
  193. static_cast<void*>(aDocumentNode), static_cast<void*>(aDocument));
  194. // log document info
  195. if (aDocumentNode) {
  196. LogDocURI(aDocumentNode);
  197. printf("\n ");
  198. LogDocShellState(aDocumentNode);
  199. printf("; ");
  200. LogDocType(aDocumentNode);
  201. printf("\n ");
  202. LogDocShellTree(aDocumentNode);
  203. printf("\n ");
  204. LogDocState(aDocumentNode);
  205. printf("\n ");
  206. LogPresShell(aDocumentNode);
  207. printf("\n ");
  208. LogDocLoadGroup(aDocumentNode);
  209. printf(", ");
  210. LogDocParent(aDocumentNode);
  211. printf("\n");
  212. }
  213. }
  214. static void
  215. LogShellLoadType(nsIDocShell* aDocShell)
  216. {
  217. printf("load type: ");
  218. uint32_t loadType = 0;
  219. aDocShell->GetLoadType(&loadType);
  220. switch (loadType) {
  221. case LOAD_NORMAL:
  222. printf("normal; ");
  223. break;
  224. case LOAD_NORMAL_REPLACE:
  225. printf("normal replace; ");
  226. break;
  227. case LOAD_NORMAL_EXTERNAL:
  228. printf("normal external; ");
  229. break;
  230. case LOAD_HISTORY:
  231. printf("history; ");
  232. break;
  233. case LOAD_NORMAL_BYPASS_CACHE:
  234. printf("normal bypass cache; ");
  235. break;
  236. case LOAD_NORMAL_BYPASS_PROXY:
  237. printf("normal bypass proxy; ");
  238. break;
  239. case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
  240. printf("normal bypass proxy and cache; ");
  241. break;
  242. case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
  243. printf("normal allow mixed content; ");
  244. break;
  245. case LOAD_RELOAD_NORMAL:
  246. printf("reload normal; ");
  247. break;
  248. case LOAD_RELOAD_BYPASS_CACHE:
  249. printf("reload bypass cache; ");
  250. break;
  251. case LOAD_RELOAD_BYPASS_PROXY:
  252. printf("reload bypass proxy; ");
  253. break;
  254. case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
  255. printf("reload bypass proxy and cache; ");
  256. break;
  257. case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
  258. printf("reload allow mixed content; ");
  259. break;
  260. case LOAD_LINK:
  261. printf("link; ");
  262. break;
  263. case LOAD_REFRESH:
  264. printf("refresh; ");
  265. break;
  266. case LOAD_RELOAD_CHARSET_CHANGE:
  267. printf("reload charset change; ");
  268. break;
  269. case LOAD_BYPASS_HISTORY:
  270. printf("bypass history; ");
  271. break;
  272. case LOAD_STOP_CONTENT:
  273. printf("stop content; ");
  274. break;
  275. case LOAD_STOP_CONTENT_AND_REPLACE:
  276. printf("stop content and replace; ");
  277. break;
  278. case LOAD_PUSHSTATE:
  279. printf("load pushstate; ");
  280. break;
  281. case LOAD_REPLACE_BYPASS_CACHE:
  282. printf("replace bypass cache; ");
  283. break;
  284. case LOAD_ERROR_PAGE:
  285. printf("error page;");
  286. break;
  287. default:
  288. printf("unknown");
  289. }
  290. }
  291. static void
  292. LogRequest(nsIRequest* aRequest)
  293. {
  294. if (aRequest) {
  295. nsAutoCString name;
  296. aRequest->GetName(name);
  297. printf(" request spec: %s\n", name.get());
  298. uint32_t loadFlags = 0;
  299. aRequest->GetLoadFlags(&loadFlags);
  300. printf(" request load flags: %x; ", loadFlags);
  301. if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
  302. printf("document uri; ");
  303. if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
  304. printf("retargeted document uri; ");
  305. if (loadFlags & nsIChannel::LOAD_REPLACE)
  306. printf("replace; ");
  307. if (loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI)
  308. printf("initial document uri; ");
  309. if (loadFlags & nsIChannel::LOAD_TARGETED)
  310. printf("targeted; ");
  311. if (loadFlags & nsIChannel::LOAD_CALL_CONTENT_SNIFFERS)
  312. printf("call content sniffers; ");
  313. if (loadFlags & nsIChannel::LOAD_CLASSIFY_URI)
  314. printf("classify uri; ");
  315. } else {
  316. printf(" no request");
  317. }
  318. }
  319. static void
  320. LogDocAccState(DocAccessible* aDocument)
  321. {
  322. printf("document acc state: ");
  323. if (aDocument->HasLoadState(DocAccessible::eCompletelyLoaded))
  324. printf("completely loaded;");
  325. else if (aDocument->HasLoadState(DocAccessible::eReady))
  326. printf("ready;");
  327. else if (aDocument->HasLoadState(DocAccessible::eDOMLoaded))
  328. printf("DOM loaded;");
  329. else if (aDocument->HasLoadState(DocAccessible::eTreeConstructed))
  330. printf("tree constructed;");
  331. }
  332. static void
  333. GetDocLoadEventType(AccEvent* aEvent, nsACString& aEventType)
  334. {
  335. uint32_t type = aEvent->GetEventType();
  336. if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED) {
  337. aEventType.AssignLiteral("load stopped");
  338. } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) {
  339. aEventType.AssignLiteral("load complete");
  340. } else if (type == nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD) {
  341. aEventType.AssignLiteral("reload");
  342. } else if (type == nsIAccessibleEvent::EVENT_STATE_CHANGE) {
  343. AccStateChangeEvent* event = downcast_accEvent(aEvent);
  344. if (event->GetState() == states::BUSY) {
  345. aEventType.AssignLiteral("busy ");
  346. if (event->IsStateEnabled())
  347. aEventType.AppendLiteral("true");
  348. else
  349. aEventType.AppendLiteral("false");
  350. }
  351. }
  352. }
  353. ////////////////////////////////////////////////////////////////////////////////
  354. // namespace logging:: document life cycle logging methods
  355. static const char* sDocLoadTitle = "DOCLOAD";
  356. static const char* sDocCreateTitle = "DOCCREATE";
  357. static const char* sDocDestroyTitle = "DOCDESTROY";
  358. static const char* sDocEventTitle = "DOCEVENT";
  359. static const char* sFocusTitle = "FOCUS";
  360. void
  361. logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
  362. nsIRequest* aRequest, uint32_t aStateFlags)
  363. {
  364. MsgBegin(sDocLoadTitle, aMsg);
  365. nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
  366. aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
  367. nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
  368. if (!window) {
  369. MsgEnd();
  370. return;
  371. }
  372. nsCOMPtr<nsIDocument> documentNode = window->GetDoc();
  373. if (!documentNode) {
  374. MsgEnd();
  375. return;
  376. }
  377. DocAccessible* document = GetExistingDocAccessible(documentNode);
  378. LogDocInfo(documentNode, document);
  379. nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
  380. printf("\n ");
  381. LogShellLoadType(docShell);
  382. printf("\n");
  383. LogRequest(aRequest);
  384. printf("\n");
  385. printf(" state flags: %x", aStateFlags);
  386. bool isDocLoading;
  387. aWebProgress->GetIsLoadingDocument(&isDocLoading);
  388. printf(", document is %sloading\n", (isDocLoading ? "" : "not "));
  389. MsgEnd();
  390. }
  391. void
  392. logging::DocLoad(const char* aMsg, nsIDocument* aDocumentNode)
  393. {
  394. MsgBegin(sDocLoadTitle, aMsg);
  395. DocAccessible* document = GetExistingDocAccessible(aDocumentNode);
  396. LogDocInfo(aDocumentNode, document);
  397. MsgEnd();
  398. }
  399. void
  400. logging::DocCompleteLoad(DocAccessible* aDocument, bool aIsLoadEventTarget)
  401. {
  402. MsgBegin(sDocLoadTitle, "document loaded *completely*");
  403. printf(" DOM document: %p, acc document: %p\n",
  404. static_cast<void*>(aDocument->DocumentNode()),
  405. static_cast<void*>(aDocument));
  406. printf(" ");
  407. LogDocURI(aDocument->DocumentNode());
  408. printf("\n");
  409. printf(" ");
  410. LogDocAccState(aDocument);
  411. printf("\n");
  412. printf(" document is load event target: %s\n",
  413. (aIsLoadEventTarget ? "true" : "false"));
  414. MsgEnd();
  415. }
  416. void
  417. logging::DocLoadEventFired(AccEvent* aEvent)
  418. {
  419. nsAutoCString strEventType;
  420. GetDocLoadEventType(aEvent, strEventType);
  421. if (!strEventType.IsEmpty())
  422. printf(" fire: %s\n", strEventType.get());
  423. }
  424. void
  425. logging::DocLoadEventHandled(AccEvent* aEvent)
  426. {
  427. nsAutoCString strEventType;
  428. GetDocLoadEventType(aEvent, strEventType);
  429. if (strEventType.IsEmpty())
  430. return;
  431. MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get());
  432. DocAccessible* document = aEvent->GetAccessible()->AsDoc();
  433. if (document)
  434. LogDocInfo(document->DocumentNode(), document);
  435. MsgEnd();
  436. }
  437. void
  438. logging::DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
  439. DocAccessible* aDocument)
  440. {
  441. DocAccessible* document = aDocument ?
  442. aDocument : GetExistingDocAccessible(aDocumentNode);
  443. MsgBegin(sDocCreateTitle, aMsg);
  444. LogDocInfo(aDocumentNode, document);
  445. MsgEnd();
  446. }
  447. void
  448. logging::DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
  449. DocAccessible* aDocument)
  450. {
  451. DocAccessible* document = aDocument ?
  452. aDocument : GetExistingDocAccessible(aDocumentNode);
  453. MsgBegin(sDocDestroyTitle, aMsg);
  454. LogDocInfo(aDocumentNode, document);
  455. MsgEnd();
  456. }
  457. void
  458. logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc)
  459. {
  460. MsgBegin(sDocDestroyTitle, "outerdoc shutdown");
  461. logging::Address("outerdoc", aOuterDoc);
  462. MsgEnd();
  463. }
  464. void
  465. logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
  466. Accessible* aTarget)
  467. {
  468. MsgBegin(sFocusTitle, aMsg);
  469. AccessibleNNode(aTargetDescr, aTarget);
  470. MsgEnd();
  471. }
  472. void
  473. logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
  474. nsINode* aTargetNode)
  475. {
  476. MsgBegin(sFocusTitle, aMsg);
  477. Node(aTargetDescr, aTargetNode);
  478. MsgEnd();
  479. }
  480. void
  481. logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
  482. nsISupports* aTargetThing)
  483. {
  484. MsgBegin(sFocusTitle, aMsg);
  485. if (aTargetThing) {
  486. nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTargetThing));
  487. if (targetNode)
  488. AccessibleNNode(aTargetDescr, targetNode);
  489. else
  490. printf(" %s: %p, window\n", aTargetDescr,
  491. static_cast<void*>(aTargetThing));
  492. }
  493. MsgEnd();
  494. }
  495. void
  496. logging::ActiveItemChangeCausedBy(const char* aCause, Accessible* aTarget)
  497. {
  498. SubMsgBegin();
  499. printf(" Caused by: %s\n", aCause);
  500. AccessibleNNode("Item", aTarget);
  501. SubMsgEnd();
  502. }
  503. void
  504. logging::ActiveWidget(Accessible* aWidget)
  505. {
  506. SubMsgBegin();
  507. AccessibleNNode("Widget", aWidget);
  508. printf(" Widget is active: %s, has operable items: %s\n",
  509. (aWidget && aWidget->IsActiveWidget() ? "true" : "false"),
  510. (aWidget && aWidget->AreItemsOperable() ? "true" : "false"));
  511. SubMsgEnd();
  512. }
  513. void
  514. logging::FocusDispatched(Accessible* aTarget)
  515. {
  516. SubMsgBegin();
  517. AccessibleNNode("A11y target", aTarget);
  518. SubMsgEnd();
  519. }
  520. void
  521. logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument,
  522. int16_t aReason)
  523. {
  524. nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
  525. int16_t type = 0;
  526. privSel->GetType(&type);
  527. const char* strType = 0;
  528. if (type == nsISelectionController::SELECTION_NORMAL)
  529. strType = "normal";
  530. else if (type == nsISelectionController::SELECTION_SPELLCHECK)
  531. strType = "spellcheck";
  532. else
  533. strType = "unknown";
  534. bool isIgnored = !aDocument || !aDocument->IsContentLoaded();
  535. printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
  536. strType, (isIgnored ? "ignored" : "pending"), aReason);
  537. Stack();
  538. }
  539. void
  540. logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...)
  541. {
  542. if (IsEnabledAll(logging::eTree | aExtraFlags)) {
  543. va_list vl;
  544. va_start(vl, aExtraFlags);
  545. const char* descr = va_arg(vl, const char*);
  546. if (descr) {
  547. Accessible* acc = va_arg(vl, Accessible*);
  548. MsgBegin("TREE", "%s; doc: %p", aMsg, acc ? acc->Document() : nullptr);
  549. AccessibleInfo(descr, acc);
  550. while ((descr = va_arg(vl, const char*))) {
  551. AccessibleInfo(descr, va_arg(vl, Accessible*));
  552. }
  553. }
  554. else {
  555. MsgBegin("TREE", aMsg);
  556. }
  557. va_end(vl);
  558. MsgEnd();
  559. if (aExtraFlags & eStack) {
  560. Stack();
  561. }
  562. }
  563. }
  564. void
  565. logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags,
  566. const char* aMsg1, Accessible* aAcc,
  567. const char* aMsg2, nsINode* aNode)
  568. {
  569. if (IsEnabledAll(logging::eTree | aExtraFlags)) {
  570. MsgBegin("TREE", "%s; doc: %p", aMsg, aAcc ? aAcc->Document() : nullptr);
  571. AccessibleInfo(aMsg1, aAcc);
  572. Accessible* acc = aAcc ? aAcc->Document()->GetAccessible(aNode) : nullptr;
  573. if (acc) {
  574. AccessibleInfo(aMsg2, acc);
  575. }
  576. else {
  577. Node(aMsg2, aNode);
  578. }
  579. MsgEnd();
  580. }
  581. }
  582. void
  583. logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent)
  584. {
  585. if (IsEnabledAll(logging::eTree | aExtraFlags)) {
  586. MsgBegin("TREE", "%s; doc: %p", aMsg, aParent->Document());
  587. AccessibleInfo("container", aParent);
  588. for (uint32_t idx = 0; idx < aParent->ChildCount(); idx++) {
  589. AccessibleInfo("child", aParent->GetChildAt(idx));
  590. }
  591. MsgEnd();
  592. }
  593. }
  594. void
  595. logging::Tree(const char* aTitle, const char* aMsgText,
  596. Accessible* aRoot, GetTreePrefix aPrefixFunc,
  597. void* aGetTreePrefixData)
  598. {
  599. logging::MsgBegin(aTitle, aMsgText);
  600. nsAutoString level;
  601. Accessible* root = aRoot;
  602. do {
  603. const char* prefix = aPrefixFunc ? aPrefixFunc(aGetTreePrefixData, root) : "";
  604. printf("%s", NS_ConvertUTF16toUTF8(level).get());
  605. logging::AccessibleInfo(prefix, root);
  606. if (root->FirstChild() && !root->FirstChild()->IsDoc()) {
  607. level.Append(NS_LITERAL_STRING(" "));
  608. root = root->FirstChild();
  609. continue;
  610. }
  611. int32_t idxInParent = root != aRoot && root->mParent ?
  612. root->mParent->mChildren.IndexOf(root) : -1;
  613. if (idxInParent != -1 &&
  614. idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
  615. root = root->mParent->mChildren.ElementAt(idxInParent + 1);
  616. continue;
  617. }
  618. while (root != aRoot && (root = root->Parent())) {
  619. level.Cut(0, 2);
  620. int32_t idxInParent = !root->IsDoc() && root->mParent ?
  621. root->mParent->mChildren.IndexOf(root) : -1;
  622. if (idxInParent != -1 &&
  623. idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
  624. root = root->mParent->mChildren.ElementAt(idxInParent + 1);
  625. break;
  626. }
  627. }
  628. }
  629. while (root && root != aRoot);
  630. logging::MsgEnd();
  631. }
  632. void
  633. logging::DOMTree(const char* aTitle, const char* aMsgText,
  634. DocAccessible* aDocument)
  635. {
  636. logging::MsgBegin(aTitle, aMsgText);
  637. nsAutoString level;
  638. nsINode* root = aDocument->DocumentNode();
  639. do {
  640. printf("%s", NS_ConvertUTF16toUTF8(level).get());
  641. logging::Node("", root);
  642. if (root->GetFirstChild()) {
  643. level.Append(NS_LITERAL_STRING(" "));
  644. root = root->GetFirstChild();
  645. continue;
  646. }
  647. if (root->GetNextSibling()) {
  648. root = root->GetNextSibling();
  649. continue;
  650. }
  651. while ((root = root->GetParentNode())) {
  652. level.Cut(0, 2);
  653. if (root->GetNextSibling()) {
  654. root = root->GetNextSibling();
  655. break;
  656. }
  657. }
  658. }
  659. while (root);
  660. logging::MsgEnd();
  661. }
  662. void
  663. logging::MsgBegin(const char* aTitle, const char* aMsgText, ...)
  664. {
  665. printf("\nA11Y %s: ", aTitle);
  666. va_list argptr;
  667. va_start(argptr, aMsgText);
  668. vprintf(aMsgText, argptr);
  669. va_end(argptr);
  670. PRIntervalTime time = PR_IntervalNow();
  671. uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60;
  672. uint32_t secs = PR_IntervalToSeconds(time) % 60;
  673. uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000;
  674. printf("; %02d:%02d.%03d", mins, secs, msecs);
  675. printf("\n {\n");
  676. }
  677. void
  678. logging::MsgEnd()
  679. {
  680. printf(" }\n");
  681. }
  682. void
  683. logging::SubMsgBegin()
  684. {
  685. printf(" {\n");
  686. }
  687. void
  688. logging::SubMsgEnd()
  689. {
  690. printf(" }\n");
  691. }
  692. void
  693. logging::MsgEntry(const char* aEntryText, ...)
  694. {
  695. printf(" ");
  696. va_list argptr;
  697. va_start(argptr, aEntryText);
  698. vprintf(aEntryText, argptr);
  699. va_end(argptr);
  700. printf("\n");
  701. }
  702. void
  703. logging::Text(const char* aText)
  704. {
  705. printf(" %s\n", aText);
  706. }
  707. void
  708. logging::Address(const char* aDescr, Accessible* aAcc)
  709. {
  710. if (!aAcc->IsDoc()) {
  711. printf(" %s accessible: %p, node: %p\n", aDescr,
  712. static_cast<void*>(aAcc), static_cast<void*>(aAcc->GetNode()));
  713. }
  714. DocAccessible* doc = aAcc->Document();
  715. nsIDocument* docNode = doc->DocumentNode();
  716. printf(" document: %p, node: %p\n",
  717. static_cast<void*>(doc), static_cast<void*>(docNode));
  718. printf(" ");
  719. LogDocURI(docNode);
  720. printf("\n");
  721. }
  722. void
  723. logging::Node(const char* aDescr, nsINode* aNode)
  724. {
  725. printf(" ");
  726. if (!aNode) {
  727. printf("%s: null\n", aDescr);
  728. return;
  729. }
  730. if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
  731. printf("%s: %p, document\n", aDescr, static_cast<void*>(aNode));
  732. return;
  733. }
  734. nsINode* parentNode = aNode->GetParentNode();
  735. int32_t idxInParent = parentNode ? parentNode->IndexOf(aNode) : - 1;
  736. if (aNode->IsNodeOfType(nsINode::eTEXT)) {
  737. printf("%s: %p, text node, idx in parent: %d\n",
  738. aDescr, static_cast<void*>(aNode), idxInParent);
  739. return;
  740. }
  741. if (!aNode->IsElement()) {
  742. printf("%s: %p, not accessible node type, idx in parent: %d\n",
  743. aDescr, static_cast<void*>(aNode), idxInParent);
  744. return;
  745. }
  746. dom::Element* elm = aNode->AsElement();
  747. nsAutoCString tag;
  748. elm->NodeInfo()->NameAtom()->ToUTF8String(tag);
  749. nsIAtom* idAtom = elm->GetID();
  750. nsAutoCString id;
  751. if (idAtom)
  752. idAtom->ToUTF8String(id);
  753. printf("%s: %p, %s@id='%s', idx in parent: %d\n",
  754. aDescr, static_cast<void*>(elm), tag.get(), id.get(), idxInParent);
  755. }
  756. void
  757. logging::Document(DocAccessible* aDocument)
  758. {
  759. printf(" Document: %p, document node: %p\n",
  760. static_cast<void*>(aDocument),
  761. static_cast<void*>(aDocument->DocumentNode()));
  762. printf(" Document ");
  763. LogDocURI(aDocument->DocumentNode());
  764. printf("\n");
  765. }
  766. void
  767. logging::AccessibleInfo(const char* aDescr, Accessible* aAccessible)
  768. {
  769. printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible));
  770. if (!aAccessible) {
  771. printf("\n");
  772. return;
  773. }
  774. if (aAccessible->IsDefunct()) {
  775. printf("defunct\n");
  776. return;
  777. }
  778. if (!aAccessible->Document() || aAccessible->Document()->IsDefunct()) {
  779. printf("document is shutting down, no info\n");
  780. return;
  781. }
  782. nsAutoString role;
  783. GetAccService()->GetStringRole(aAccessible->Role(), role);
  784. printf("role: %s", NS_ConvertUTF16toUTF8(role).get());
  785. nsAutoString name;
  786. aAccessible->Name(name);
  787. if (!name.IsEmpty()) {
  788. printf(", name: '%s'", NS_ConvertUTF16toUTF8(name).get());
  789. }
  790. printf(", idx: %d", aAccessible->IndexInParent());
  791. nsINode* node = aAccessible->GetNode();
  792. if (!node) {
  793. printf(", node: null\n");
  794. }
  795. else if (node->IsNodeOfType(nsINode::eDOCUMENT)) {
  796. printf(", document node: %p\n", static_cast<void*>(node));
  797. }
  798. else if (node->IsNodeOfType(nsINode::eTEXT)) {
  799. printf(", text node: %p\n", static_cast<void*>(node));
  800. }
  801. else if (node->IsElement()) {
  802. dom::Element* el = node->AsElement();
  803. nsAutoCString tag;
  804. el->NodeInfo()->NameAtom()->ToUTF8String(tag);
  805. nsIAtom* idAtom = el->GetID();
  806. nsAutoCString id;
  807. if (idAtom) {
  808. idAtom->ToUTF8String(id);
  809. }
  810. printf(", element node: %p, %s@id='%s'\n",
  811. static_cast<void*>(el), tag.get(), id.get());
  812. }
  813. }
  814. void
  815. logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible)
  816. {
  817. printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible));
  818. if (!aAccessible)
  819. return;
  820. nsAutoString role;
  821. GetAccService()->GetStringRole(aAccessible->Role(), role);
  822. nsAutoString name;
  823. aAccessible->Name(name);
  824. printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(),
  825. NS_ConvertUTF16toUTF8(name).get());
  826. nsAutoCString nodeDescr(aDescr);
  827. nodeDescr.AppendLiteral(" node");
  828. Node(nodeDescr.get(), aAccessible->GetNode());
  829. Document(aAccessible->Document());
  830. }
  831. void
  832. logging::AccessibleNNode(const char* aDescr, nsINode* aNode)
  833. {
  834. DocAccessible* document =
  835. GetAccService()->GetDocAccessible(aNode->OwnerDoc());
  836. if (document) {
  837. Accessible* accessible = document->GetAccessible(aNode);
  838. if (accessible) {
  839. AccessibleNNode(aDescr, accessible);
  840. return;
  841. }
  842. }
  843. nsAutoCString nodeDescr("[not accessible] ");
  844. nodeDescr.Append(aDescr);
  845. Node(nodeDescr.get(), aNode);
  846. if (document) {
  847. Document(document);
  848. return;
  849. }
  850. printf(" [contained by not accessible document]:\n");
  851. LogDocInfo(aNode->OwnerDoc(), document);
  852. printf("\n");
  853. }
  854. void
  855. logging::DOMEvent(const char* aDescr, nsINode* aOrigTarget,
  856. const nsAString& aEventType)
  857. {
  858. logging::MsgBegin("DOMEvents", "event '%s' %s",
  859. NS_ConvertUTF16toUTF8(aEventType).get(), aDescr);
  860. logging::AccessibleNNode("Target", aOrigTarget);
  861. logging::MsgEnd();
  862. }
  863. void
  864. logging::Stack()
  865. {
  866. if (IsEnabled(eStack)) {
  867. printf(" stack: \n");
  868. nsTraceRefcnt::WalkTheStack(stdout);
  869. }
  870. }
  871. ////////////////////////////////////////////////////////////////////////////////
  872. // namespace logging:: initialization
  873. bool
  874. logging::IsEnabled(uint32_t aModules)
  875. {
  876. return sModules & aModules;
  877. }
  878. bool
  879. logging::IsEnabledAll(uint32_t aModules)
  880. {
  881. return (sModules & aModules) == aModules;
  882. }
  883. bool
  884. logging::IsEnabled(const nsAString& aModuleStr)
  885. {
  886. for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) {
  887. if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr))
  888. return sModules & sModuleMap[idx].mModule;
  889. }
  890. return false;
  891. }
  892. void
  893. logging::Enable(const nsAFlatCString& aModules)
  894. {
  895. EnableLogging(aModules.get());
  896. }
  897. void
  898. logging::CheckEnv()
  899. {
  900. EnableLogging(PR_GetEnv("A11YLOG"));
  901. }