Changeset 160903 in webkit


Ignore:
Timestamp:
Dec 20, 2013 3:52:17 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:

(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.

  • accessibility/AccessibilityObject.cpp:

(WebCore::AccessibilityObject::children): Add the option ot
request the AccessibilityChildrenVector without updating it if
needed, to avoid maybe recreating the child subtree when trying to
get the offset of a newly attached element from attachWrapper.

  • accessibility/AccessibilityObject.h:

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
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r160896 r160903  
     12013-12-20  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-19  Ryosuke Niwa  <rniwa@webkit.org>
    222
  • trunk/LayoutTests/accessibility/loading-iframe-sends-notification.html

    r160485 r160903  
    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

    r160840 r160903  
    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

    r160901 r160903  
     12013-12-20  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:
     15        (WebCore::AXObjectCache::detachWrapper): Added a new parameter and
     16        updated all the prototypes in different ports.
     17        * accessibility/AXObjectCache.cpp:
     18        (WebCore::AXObjectCache::~AXObjectCache): Call detachWrapper()
     19        specifying that we do it because the cache is being destroyed.
     20        (WebCore::AXObjectCache::remove): Call detachWrapper() specifying
     21        that we do it because an accessible element is being destroyed.
     22
     23        * accessibility/atk/AXObjectCacheAtk.cpp:
     24        (WebCore::AXObjectCache::detachWrapper): Emit the children-changed
     25        signal when needed. We rely on the cached reference to the parent
     26        AtkObject (using the implementation of atk_object_get_parent from
     27        the AtkObject class) to find the right object to emit the signal
     28        from here, since the accessibility hierarchy from WebCore will no
     29        longer be accessible at this point.
     30        (WebCore::AXObjectCache::attachWrapper): Emit the children-change
     31        signal from here unless we are in the middle of a layout update,
     32        trying to provide as much information (e.g. the offset) as possible.
     33        (WebCore::AXObjectCache::postPlatformNotification): Make sure we
     34        update (touch) the subtree under an accessibility object whenever
     35        we receive AXChildrenChanded from WebCore, to ensure that those
     36        objects will also be visible rightaway to ATs, and that those get
     37        properly notified of the event at that very same moment.
     38
     39        * accessibility/ios/AXObjectCacheIOS.mm:
     40        (WebCore::AXObjectCache::detachWrapper): Updated function signature.
     41        * accessibility/mac/AXObjectCacheMac.mm:
     42        (WebCore::AXObjectCache::detachWrapper): Ditto.
     43        * accessibility/win/AXObjectCacheWin.cpp:
     44        (WebCore::AXObjectCache::detachWrapper): Ditto.
     45
     46        * accessibility/AccessibilityObject.cpp:
     47        (WebCore::AccessibilityObject::children): Add the option ot
     48        request the AccessibilityChildrenVector without updating it if
     49        needed, to avoid maybe recreating the child subtree when trying to
     50        get the offset of a newly attached element from attachWrapper.
     51        * accessibility/AccessibilityObject.h:
     52
    1532013-12-20  Laszlo Vidacs  <lvidacs.u-szeged@partner.samsung.com>
    254
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r160789 r160903  
    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(CacheDestroyed);
    126126        removeAXID(obj);
     
    494494        return;
    495495   
    496     detachWrapper(obj);
     496    detachWrapper(obj, ElementDestroyed);
    497497    obj->detach(ElementDestroyed, this);
    498498    removeAXID(obj);
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

    r160778 r160903  
    103103    void remove(AXID);
    104104
    105     void detachWrapper(AccessibilityObject*);
     105    void detachWrapper(AccessibilityObject*, AccessibilityDetachmentType);
    106106    void attachWrapper(AccessibilityObject*);
    107107    void childrenChanged(Node*);
     
    288288inline void AXObjectCache::textChanged(AccessibilityObject*) { }
    289289inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { }
    290 inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
     290inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { }
    291291inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
    292292inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { }
  • trunk/Source/WebCore/accessibility/AccessibilityObject.cpp

    r160778 r160903  
    12641264
    12651265#if HAVE(ACCESSIBILITY)
    1266 const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children()
    1267 {
    1268     updateChildrenIfNecessary();
     1266const AccessibilityObject::AccessibilityChildrenVector& AccessibilityObject::children(bool updateChildrenIfNeeded)
     1267{
     1268    if (updateChildrenIfNeeded)
     1269        updateChildrenIfNecessary();
    12691270
    12701271    return m_children;
  • trunk/Source/WebCore/accessibility/AccessibilityObject.h

    r160778 r160903  
    692692    virtual void textChanged() { }
    693693    virtual void updateAccessibilityRole() { }
    694     const AccessibilityChildrenVector& children();
     694    const AccessibilityChildrenVector& children(bool updateChildrenIfNeeded = true);
    695695    virtual void addChildren() { }
    696696    virtual void addChild(AccessibilityObject*) { }
  • trunk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp

    r160485 r160903  
    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, AccessibilityDetachmentType 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->wrapper();
     86    if (!atkParent)
     87        return;
     88
     89    size_t index = coreParent->children(false).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        {
     200            int numOfChildren = atk_object_get_n_accessible_children(axObject);
     201            for (int i = 0; i < numOfChildren; ++i)
     202                GRefPtr<AtkObject> child(atk_object_ref_accessible_child(axObject, i));
     203        }
     204        break;
     205
     206    case AXSelectedChildrenChanged:
     207    case AXMenuListValueChanged:
    151208        if (notification == AXMenuListValueChanged && coreObject->isMenuList()) {
    152209            g_signal_emit_by_name(axObject, "focus-event", true);
     
    154211        }
    155212        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)
     213        break;
     214
     215    case AXValueChanged:
     216        if (ATK_IS_VALUE(axObject)) {
     217            AtkPropertyValues propertyValues;
     218            propertyValues.property_name = "accessible-value";
     219
     220            memset(&propertyValues.new_value,  0, sizeof(GValue));
     221            atk_value_get_current_value(ATK_VALUE(axObject), &propertyValues.new_value);
     222
     223            g_signal_emit_by_name(ATK_OBJECT(axObject), "property-change::accessible-value", &propertyValues, NULL);
     224        }
     225        break;
     226
     227    case AXInvalidStatusChanged:
    168228        atk_object_notify_state_change(axObject, ATK_STATE_INVALID_ENTRY, coreObject->invalidStatus() != "false");
     229        break;
     230
     231    default:
     232        break;
     233    }
    169234}
    170235
  • trunk/Source/WebCore/accessibility/ios/AXObjectCacheIOS.mm

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

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

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

    r160902 r160903  
     12013-12-20  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-20  Peter Molnar  <pmolnar.u-szeged@partner.samsung.com>
    216
  • trunk/Tools/DumpRenderTree/atk/AccessibilityCallbacksAtk.cpp

    r160485 r160903  
    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

    r160485 r160903  
    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.