Changeset 160417 in webkit


Ignore:
Timestamp:
Dec 11, 2013 2:28:21 AM (10 years ago)
Author:
mario.prada@samsung.com
Message:

Programmatically-inserted children lack accessibility events
https://bugs.webkit.org/show_bug.cgi?id=100275

Reviewed by Chris Fleizach.

Source/WebCore:

Test: accessibility/children-changed-sends-notification.html

Emit children-changed::add and children-changed::remove whenever
an object has been added/removed to the accessibility hierarchy,
that is, when a new AtkObject is being attached/detached.

  • accessibility/AXObjectCache.h: Added new enumeration to know

when we are detaching a wrapper because of the cache or the
element is being destroyed, so we can use that information.
(WebCore::AXObjectCache::detachWrapper): Added a new parameter and
updated all the prototypes in different ports.

  • accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::~AXObjectCache): Call detachWrapper()
specifying that we do it because the cache is being destroyed.
(WebCore::AXObjectCache::remove): Call detachWrapper() specifying
that we do it because an accessible element is being destroyed.

  • accessibility/atk/AXObjectCacheAtk.cpp:

(WebCore::AXObjectCache::detachWrapper): Emit the children-changed
signal when needed. We rely on the cached reference to the parent
AtkObject (using the implementation of atk_object_get_parent from
the AtkObject class) to find the right object to emit the signal
from here, since the accessibility hierarchy from WebCore will no
longer be accessible at this point.
(WebCore::AXObjectCache::attachWrapper): Emit the children-change
signal from here unless we are in the middle of a layout update,
trying to provide as much information (e.g. the offset) as possible.
(WebCore::AXObjectCache::postPlatformNotification): Make sure we
update (touch) the subtree under an accessibility object whenever
we receive AXChildrenChanded from WebCore, to ensure that those
objects will also be visible rightaway to ATs, and that those get
properly notified of the event at that very same moment.

  • accessibility/ios/AXObjectCacheIOS.mm:

(WebCore::AXObjectCache::detachWrapper): Updated function signature.

  • accessibility/mac/AXObjectCacheMac.mm:

(WebCore::AXObjectCache::detachWrapper): Ditto.

  • accessibility/win/AXObjectCacheWin.cpp:

(WebCore::AXObjectCache::detachWrapper): Ditto.

Tools:

Update DRT and WebKitTestRunner to handle the children-changed
signal properly, considering the detail and optional parameters.

  • DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp: Updated.

(axObjectEventListener):

  • WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp: Updated.

LayoutTests:

Add new test to chack that children-changed signals are properly
emitted when adding/removing elements in the accessibility hierarchy.

  • accessibility/children-changed-sends-notification-expected.txt: Added.
  • accessibility/children-changed-sends-notification.html: Added.

Update test to filter out unrelated non-loading events.

  • accessibility/loading-iframe-sends-notification.html: Updated.

Skip the test on the Mac as it does not expose these kind of
notifications when children are being added or removed.

  • platform/mac/TestExpectations: Skip newly added test.
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r160410 r160417  
     12013-12-11  Mario Sanchez Prada  <mario.prada@samsung.com>
     2
     3        Programmatically-inserted children lack accessibility events
     4        https://bugs.webkit.org/show_bug.cgi?id=100275
     5
     6        Reviewed by Chris Fleizach.
     7
     8        Add new test to chack that children-changed signals are properly
     9        emitted when adding/removing elements in the accessibility hierarchy.
     10
     11        * accessibility/children-changed-sends-notification-expected.txt: Added.
     12        * accessibility/children-changed-sends-notification.html: Added.
     13
     14        Update test to filter out unrelated non-loading events.
     15        * accessibility/loading-iframe-sends-notification.html: Updated.
     16
     17        Skip the test on the Mac as it does not expose these kind of
     18        notifications when children are being added or removed.
     19        * platform/mac/TestExpectations: Skip newly added test.
     20
    1212013-12-10  Gurpreet Kaur  <k.gurpreet@samsung.com>
    222
  • trunk/LayoutTests/accessibility/loading-iframe-sends-notification.html

    r155410 r160417  
    5454
    5555            window.accessibilityController.addNotificationListener(function (target, notification) {
    56                 // Ignore this notification if it's not on the iframe.
    57                 if (target.description.indexOf("InnerFrame") == -1)
     56                // Ignore this notification if it's not on the iframe or not about the iframe being loaded.
     57                if (target.description.indexOf("InnerFrame") == -1
     58                    || (notification != "AXLoadComplete" && notification != "AXLayoutComplete"))
    5859                    return;
    5960
  • trunk/LayoutTests/platform/mac/TestExpectations

    r160249 r160417  
    4141# Accessibility tests for notifications that don't exist or aren't needed on Mac OS X.
    4242accessibility/aria-checkbox-sends-notification.html
     43accessibility/children-changed-sends-notification.html
    4344accessibility/menu-list-sends-change-notification.html
    4445accessibility/multiselect-list-reports-active-option.html
  • trunk/Source/WebCore/ChangeLog

    r160415 r160417  
     12013-12-11  Mario Sanchez Prada  <mario.prada@samsung.com>
     2
     3        Programmatically-inserted children lack accessibility events
     4        https://bugs.webkit.org/show_bug.cgi?id=100275
     5
     6        Reviewed by Chris Fleizach.
     7
     8        Test: accessibility/children-changed-sends-notification.html
     9
     10        Emit children-changed::add and children-changed::remove whenever
     11        an object has been added/removed to the accessibility hierarchy,
     12        that is, when a new AtkObject is being attached/detached.
     13
     14        * accessibility/AXObjectCache.h: Added new enumeration to know
     15        when we are detaching a wrapper because of the cache or the
     16        element is being destroyed, so we can use that information.
     17        (WebCore::AXObjectCache::detachWrapper): Added a new parameter and
     18        updated all the prototypes in different ports.
     19        * accessibility/AXObjectCache.cpp:
     20        (WebCore::AXObjectCache::~AXObjectCache): Call detachWrapper()
     21        specifying that we do it because the cache is being destroyed.
     22        (WebCore::AXObjectCache::remove): Call detachWrapper() specifying
     23        that we do it because an accessible element is being destroyed.
     24
     25        * accessibility/atk/AXObjectCacheAtk.cpp:
     26        (WebCore::AXObjectCache::detachWrapper): Emit the children-changed
     27        signal when needed. We rely on the cached reference to the parent
     28        AtkObject (using the implementation of atk_object_get_parent from
     29        the AtkObject class) to find the right object to emit the signal
     30        from here, since the accessibility hierarchy from WebCore will no
     31        longer be accessible at this point.
     32        (WebCore::AXObjectCache::attachWrapper): Emit the children-change
     33        signal from here unless we are in the middle of a layout update,
     34        trying to provide as much information (e.g. the offset) as possible.
     35        (WebCore::AXObjectCache::postPlatformNotification): Make sure we
     36        update (touch) the subtree under an accessibility object whenever
     37        we receive AXChildrenChanded from WebCore, to ensure that those
     38        objects will also be visible rightaway to ATs, and that those get
     39        properly notified of the event at that very same moment.
     40
     41        * accessibility/ios/AXObjectCacheIOS.mm:
     42        (WebCore::AXObjectCache::detachWrapper): Updated function signature.
     43        * accessibility/mac/AXObjectCacheMac.mm:
     44        (WebCore::AXObjectCache::detachWrapper): Ditto.
     45        * accessibility/win/AXObjectCacheWin.cpp:
     46        (WebCore::AXObjectCache::detachWrapper): Ditto.
     47
    1482013-12-11  Andreas Kling  <akling@apple.com>
    249
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r159500 r160417  
    122122    for (HashMap<AXID, RefPtr<AccessibilityObject>>::iterator it = m_objects.begin(); it != end; ++it) {
    123123        AccessibilityObject* obj = (*it).value.get();
    124         detachWrapper(obj);
     124        detachWrapper(obj, CacheDestroyed);
    125125        obj->detach();
    126126        removeAXID(obj);
     
    494494        return;
    495495   
    496     detachWrapper(obj);
     496    detachWrapper(obj, ElementDestroyed);
    497497    obj->detach();
    498498    removeAXID(obj);
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

    r159500 r160417  
    7272enum PostType { PostSynchronously, PostAsynchronously };
    7373
     74enum DetachmentType { CacheDestroyed, ElementDestroyed };
     75
    7476class AXObjectCache {
    7577    WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
     
    103105    void remove(AXID);
    104106
    105     void detachWrapper(AccessibilityObject*);
     107    void detachWrapper(AccessibilityObject*, DetachmentType);
    106108    void attachWrapper(AccessibilityObject*);
    107109    void childrenChanged(Node*);
     
    285287inline void AXObjectCache::textChanged(AccessibilityObject*) { }
    286288inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { }
    287 inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
     289inline void AXObjectCache::detachWrapper(AccessibilityObject*, DetachmentType) { }
    288290inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
    289291inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { }
  • trunk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp

    r157718 r160417  
    3232#include "WebKitAccessibleWrapperAtk.h"
    3333#include <wtf/gobject/GOwnPtr.h>
     34#include <wtf/gobject/GRefPtr.h>
    3435#include <wtf/text/CString.h>
    3536
    3637namespace WebCore {
    3738
    38 void AXObjectCache::detachWrapper(AccessibilityObject* obj)
    39 {
    40     webkitAccessibleDetach(WEBKIT_ACCESSIBLE(obj->wrapper()));
     39void AXObjectCache::detachWrapper(AccessibilityObject* obj, DetachmentType detachmentType)
     40{
     41    AtkObject* wrapper = obj->wrapper();
     42    ASSERT(wrapper);
     43
     44    // If an object is being detached NOT because of the AXObjectCache being destroyed,
     45    // then it's being removed from the accessibility tree and we should emit a signal.
     46    if (detachmentType != CacheDestroyed) {
     47        if (obj->document()) {
     48            // Look for the right object to emit the signal from, but using the implementation
     49            // of atk_object_get_parent from AtkObject class (which uses a cached pointer if set)
     50            // since the accessibility hierarchy in WebCore will no longer be navigable.
     51            gpointer webkitAccessibleClass = g_type_class_peek_parent(WEBKIT_ACCESSIBLE_GET_CLASS(wrapper));
     52            gpointer atkObjectClass = g_type_class_peek_parent(webkitAccessibleClass);
     53            AtkObject* atkParent = ATK_OBJECT_CLASS(atkObjectClass)->get_parent(ATK_OBJECT(wrapper));
     54
     55            // We don't want to emit any signal from an object outside WebKit's world.
     56            if (WEBKIT_IS_ACCESSIBLE(atkParent)) {
     57                // The accessibility hierarchy is already invalid, so the parent-children relationships
     58                // in the AccessibilityObject tree are not there anymore, so we can't know the offset.
     59                g_signal_emit_by_name(atkParent, "children-changed::remove", -1, wrapper);
     60            }
     61        }
     62    }
     63
     64    webkitAccessibleDetach(WEBKIT_ACCESSIBLE(wrapper));
    4165}
    4266
     
    4670    obj->setWrapper(atkObj);
    4771    g_object_unref(atkObj);
     72
     73    // If an object is being attached and we are not in the middle of a layout update, then
     74    // we should report ATs by emitting the children-changed::add signal from the parent.
     75    Document* document = obj->document();
     76    if (!document || document->childNeedsStyleRecalc())
     77        return;
     78
     79    // Don't emit the signal for objects that we already know won't be exposed directly.
     80    AccessibilityObject* coreParent = obj->parentObjectUnignored();
     81    if (!coreParent || coreParent->accessibilityIsIgnoredByDefault())
     82        return;
     83
     84    // Look for the right object to emit the signal from.
     85    AtkObject* atkParent = coreParent ? coreParent->wrapper() : 0;
     86    if (!atkParent)
     87        return;
     88
     89    size_t index = coreParent->children().find(obj);
     90    g_signal_emit_by_name(atkParent, "children-changed::add", index, atkObj);
    4891}
    4992
     
    144187        return;
    145188
    146     if (notification == AXCheckedStateChanged) {
     189    switch (notification) {
     190    case AXCheckedStateChanged:
    147191        if (!coreObject->isCheckboxOrRadio())
    148192            return;
    149193        atk_object_notify_state_change(axObject, ATK_STATE_CHECKED, coreObject->isChecked());
    150     } else if (notification == AXSelectedChildrenChanged || notification == AXMenuListValueChanged) {
     194        break;
     195
     196    case AXChildrenChanged:
     197        // We need to make sure that the children AtkObjects are created at this moment,
     198        // so the children-changed::add signal gets properly emitted in attachWrapper().
     199        if (int numOfChildren = atk_object_get_n_accessible_children(axObject)) {
     200            for (int i = 0; i < numOfChildren; ++i)
     201                GRefPtr<AtkObject> child(atk_object_ref_accessible_child(axObject, i));
     202        }
     203        break;
     204
     205    case AXSelectedChildrenChanged:
     206    case AXMenuListValueChanged:
    151207        if (notification == AXMenuListValueChanged && coreObject->isMenuList()) {
    152208            g_signal_emit_by_name(axObject, "focus-event", true);
     
    154210        }
    155211        notifyChildrenSelectionChange(coreObject);
    156     } else if (notification == AXValueChanged) {
    157         if (!ATK_IS_VALUE(axObject))
    158             return;
    159 
    160         AtkPropertyValues propertyValues;
    161         propertyValues.property_name = "accessible-value";
    162 
    163         memset(&propertyValues.new_value,  0, sizeof(GValue));
    164         atk_value_get_current_value(ATK_VALUE(axObject), &propertyValues.new_value);
    165 
    166         g_signal_emit_by_name(ATK_OBJECT(axObject), "property-change::accessible-value", &propertyValues, NULL);
    167     } else if (notification == AXInvalidStatusChanged)
     212        break;
     213
     214    case AXValueChanged:
     215        if (ATK_IS_VALUE(axObject)) {
     216            AtkPropertyValues propertyValues;
     217            propertyValues.property_name = "accessible-value";
     218
     219            memset(&propertyValues.new_value,  0, sizeof(GValue));
     220            atk_value_get_current_value(ATK_VALUE(axObject), &propertyValues.new_value);
     221
     222            g_signal_emit_by_name(ATK_OBJECT(axObject), "property-change::accessible-value", &propertyValues, NULL);
     223        }
     224        break;
     225
     226    case AXInvalidStatusChanged:
    168227        atk_object_notify_state_change(axObject, ATK_STATE_INVALID_ENTRY, coreObject->invalidStatus() != "false");
     228        break;
     229
     230    default:
     231        break;
     232    }
    169233}
    170234
  • trunk/Source/WebCore/accessibility/ios/AXObjectCacheIOS.mm

    r149255 r160417  
    3838namespace WebCore {
    3939   
    40 void AXObjectCache::detachWrapper(AccessibilityObject* obj)
     40void AXObjectCache::detachWrapper(AccessibilityObject* obj, DetachmentType)
    4141{
    4242    [obj->wrapper() detach];
  • trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm

    r156698 r160417  
    4444namespace WebCore {
    4545
    46 void AXObjectCache::detachWrapper(AccessibilityObject* obj)
     46void AXObjectCache::detachWrapper(AccessibilityObject* obj, DetachmentType)
    4747{
    4848    [obj->wrapper() detach];
  • trunk/Source/WebCore/accessibility/win/AXObjectCacheWin.cpp

    r154877 r160417  
    4343namespace WebCore {
    4444
    45 void AXObjectCache::detachWrapper(AccessibilityObject* obj)
     45void AXObjectCache::detachWrapper(AccessibilityObject* obj, DetachmentType)
    4646{
    4747    // On Windows, AccessibilityObjects are created when get_accChildCount is
  • trunk/Tools/ChangeLog

    r160414 r160417  
     12013-12-11  Mario Sanchez Prada  <mario.prada@samsung.com>
     2
     3        Programmatically-inserted children lack accessibility events
     4        https://bugs.webkit.org/show_bug.cgi?id=100275
     5
     6        Reviewed by Chris Fleizach.
     7
     8        Update DRT and WebKitTestRunner to handle the children-changed
     9        signal properly, considering the detail and optional parameters.
     10
     11        * DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp: Updated.
     12        (axObjectEventListener):
     13        * WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp: Updated.
     14
    1152013-12-03  Mark Rowe  <mrowe@apple.com>
    216
  • trunk/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp

    r157631 r160417  
    114114            notificationName = "AXFocusedUIElementChanged";
    115115    } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
    116         signalName.set(g_strdup("children-changed"));
     116        const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail);
     117        signalName.set(g_strdup_printf("children-changed:%s", childrenChangedDetail));
    117118        signalValue.set(g_strdup_printf("%d", g_value_get_uint(&paramValues[1])));
     119        notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved";
    118120    } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) {
    119121        signalName.set(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
  • trunk/Tools/WebKitTestRunner/InjectedBundle/atk/AccessibilityNotificationHandlerAtk.cpp

    r159287 r160417  
    103103            notificationName = "AXFocusedUIElementChanged";
    104104    } else if (!g_strcmp0(signalQuery.signal_name, "children-changed")) {
    105         signalName.set(g_strdup("children-changed"));
     105        const gchar* childrenChangedDetail = g_quark_to_string(signalHint->detail);
     106        signalName.set(g_strdup_printf("children-changed:%s", childrenChangedDetail));
    106107        signalValue.set(g_strdup_printf("%d", g_value_get_uint(&paramValues[1])));
     108        notificationName = !g_strcmp0(childrenChangedDetail, "add") ? "AXChildrenAdded" : "AXChildrenRemoved";
    107109    } else if (!g_strcmp0(signalQuery.signal_name, "property-change")) {
    108110        signalName.set(g_strdup_printf("property-change:%s", g_quark_to_string(signalHint->detail)));
Note: See TracChangeset for help on using the changeset viewer.