AccessibilityCallbacksAtk.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright (C) 2011 Igalia S.L.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  14. * its contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  18. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  21. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include "config.h"
  29. #include "AccessibilityCallbacks.h"
  30. #if HAVE(ACCESSIBILITY)
  31. #include "AccessibilityController.h"
  32. #include "DumpRenderTree.h"
  33. #include <atk/atk.h>
  34. #include <wtf/gobject/GOwnPtr.h>
  35. #if PLATFORM(GTK)
  36. #include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
  37. #include <webkit/webkit.h>
  38. #endif
  39. #if PLATFORM(EFL)
  40. #include "DumpRenderTreeChrome.h"
  41. #include "WebCoreSupport/DumpRenderTreeSupportEfl.h"
  42. #endif
  43. static guint stateChangeListenerId = 0;
  44. static guint focusEventListenerId = 0;
  45. static guint activeDescendantChangedListenerId = 0;
  46. static guint childrenChangedListenerId = 0;
  47. static guint propertyChangedListenerId = 0;
  48. static guint visibleDataChangedListenerId = 0;
  49. static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName, const gchar* signalValue)
  50. {
  51. // Do not handle state-change:defunct signals, as the AtkObject
  52. // associated to them will not be valid at this point already.
  53. if (!signalName || !g_strcmp0(signalName, "state-change:defunct"))
  54. return;
  55. if (!accessible || !ATK_IS_OBJECT(accessible))
  56. return;
  57. const gchar* objectName = atk_object_get_name(accessible);
  58. AtkRole objectRole = atk_object_get_role(accessible);
  59. // Try to always provide a name to be logged for the object.
  60. if (!objectName || *objectName == '\0')
  61. objectName = "(No name)";
  62. GOwnPtr<gchar> signalNameAndValue(signalValue ? g_strdup_printf("%s = %s", signalName, signalValue) : g_strdup(signalName));
  63. printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n", signalNameAndValue.get(), objectName, objectRole);
  64. }
  65. static gboolean axObjectEventListener(GSignalInvocationHint *signalHint, guint numParamValues, const GValue *paramValues, gpointer data)
  66. {
  67. // At least we should receive the instance emitting the signal.
  68. if (numParamValues < 1)
  69. return TRUE;
  70. AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
  71. if (!accessible || !ATK_IS_OBJECT(accessible))
  72. return TRUE;
  73. GSignalQuery signalQuery;
  74. GOwnPtr<gchar> signalName;
  75. GOwnPtr<gchar> signalValue;
  76. g_signal_query(signalHint->signal_id, &signalQuery);
  77. if (!g_strcmp0(signalQuery.signal_name, "state-change")) {
  78. signalName.set(g_strdup_printf("state-change:%s", g_value_get_string(&paramValues[1])));
  79. signalValue.set(g_strdup_printf("%d", g_value_get_boolean(&paramValues[2])));
  80. } else if (!g_strcmp0(signalQuery.signal_name, "focus-event")) {
  81. signalName.set(g_strdup("focus-event"));
  82. signalValue.set(g_strdup_printf("%d", g_value_get_boolean(&paramValues[1])));
  83. } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
  84. signalName.set(g_strdup("children-changed"));
  85. signalValue.set(g_strdup_printf("%d", g_value_get_uint(&paramValues[1])));
  86. } else if (!g_strcmp0(signalQuery.signal_name, "property-change"))
  87. signalName.set(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
  88. else
  89. signalName.set(g_strdup(signalQuery.signal_name));
  90. printAccessibilityEvent(accessible, signalName.get(), signalValue.get());
  91. return TRUE;
  92. }
  93. void connectAccessibilityCallbacks()
  94. {
  95. // Ensure no callbacks are connected before.
  96. disconnectAccessibilityCallbacks();
  97. // Ensure that accessibility is initialized for the WebView by querying for
  98. // the root accessible object, which will create the full hierarchy.
  99. #if PLATFORM(GTK)
  100. DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
  101. #elif PLATFORM(EFL)
  102. DumpRenderTreeSupportEfl::rootAccessibleElement(browser->mainFrame());
  103. #endif
  104. // Add global listeners for AtkObject's signals.
  105. stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:state-change");
  106. focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:focus-event");
  107. activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:active-descendant-changed");
  108. childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:children-changed");
  109. propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:property-change");
  110. visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "ATK:AtkObject:visible-data-changed");
  111. // Ensure the Atk interface types are registered, otherwise
  112. // the AtkDocument signal handlers below won't get registered.
  113. GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
  114. AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
  115. g_object_unref(G_OBJECT(dummyNoOpAxObject));
  116. g_object_unref(dummyAxObject);
  117. }
  118. void disconnectAccessibilityCallbacks()
  119. {
  120. // AtkObject signals.
  121. if (stateChangeListenerId) {
  122. atk_remove_global_event_listener(stateChangeListenerId);
  123. stateChangeListenerId = 0;
  124. }
  125. if (focusEventListenerId) {
  126. atk_remove_global_event_listener(focusEventListenerId);
  127. focusEventListenerId = 0;
  128. }
  129. if (activeDescendantChangedListenerId) {
  130. atk_remove_global_event_listener(activeDescendantChangedListenerId);
  131. activeDescendantChangedListenerId = 0;
  132. }
  133. if (childrenChangedListenerId) {
  134. atk_remove_global_event_listener(childrenChangedListenerId);
  135. childrenChangedListenerId = 0;
  136. }
  137. if (propertyChangedListenerId) {
  138. atk_remove_global_event_listener(propertyChangedListenerId);
  139. propertyChangedListenerId = 0;
  140. }
  141. if (visibleDataChangedListenerId) {
  142. atk_remove_global_event_listener(visibleDataChangedListenerId);
  143. visibleDataChangedListenerId = 0;
  144. }
  145. }
  146. #endif