Changeset 89591 in webkit


Ignore:
Timestamp:
Jun 23, 2011 10:59:48 AM (13 years ago)
Author:
Chris Fleizach
Message:

ARIA live regions don't trigger notifications for elements that aren't in the AX tree
https://bugs.webkit.org/show_bug.cgi?id=62289

Reviewed by Darin Adler.

Source/WebCore:

If an ARIA Live region udpates an element that is not in the AX object cache, then the Live region
notification is not sent. To fix this, I think the childrenChanged() method needs to actually create
the appropriate objects, but since that method gets called during a render tree update, we've learned
that it's generally not safe to create objects.

Instead a one shot timer can be fired that will update and create the necessary objects so that the
correct notification can be sent.

Test: platform/mac/accessibility/aria-liveregion-without-element-access.html

  • accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::AXObjectCache):
(WebCore::AXObjectCache::remove):
(WebCore::AXObjectCache::childrenUpdateTimerFired):
(WebCore::AXObjectCache::childrenChanged):

  • accessibility/AXObjectCache.h:
  • accessibility/AccessibilityMenuList.cpp:

(WebCore::AccessibilityMenuList::childrenChanged):

  • accessibility/AccessibilityMenuList.h:
  • accessibility/AccessibilityMenuListPopup.cpp:

(WebCore::AccessibilityMenuListPopup::childrenChanged):

  • accessibility/AccessibilityMenuListPopup.h:
  • accessibility/AccessibilityObject.h:

(WebCore::AccessibilityObject::childrenChanged):

  • accessibility/AccessibilityRenderObject.cpp:

(WebCore::startOfContinuations):

This changed exposed a case where an object was inlineElementContinuation, but not renderInlined,
which led to an assert.

(WebCore::AccessibilityRenderObject::updateAccessibilityRole):
(WebCore::AccessibilityRenderObject::childrenChanged):

  • accessibility/AccessibilityRenderObject.h:

LayoutTests:

  • platform/mac/accessibility/aria-liveregion-without-element-access-expected.txt: Added.
  • platform/mac/accessibility/aria-liveregion-without-element-access.html: Added.
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r89590 r89591  
     12011-06-23  Chris Fleizach  <cfleizach@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        ARIA live regions don't trigger notifications for elements that aren't in the AX tree
     6        https://bugs.webkit.org/show_bug.cgi?id=62289
     7
     8        * platform/mac/accessibility/aria-liveregion-without-element-access-expected.txt: Added.
     9        * platform/mac/accessibility/aria-liveregion-without-element-access.html: Added.
     10
    1112011-06-23  Pavel Feldman  <pfeldman@google.com>
    212
  • trunk/Source/WebCore/ChangeLog

    r89587 r89591  
     12011-06-23  Chris Fleizach  <cfleizach@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        ARIA live regions don't trigger notifications for elements that aren't in the AX tree
     6        https://bugs.webkit.org/show_bug.cgi?id=62289
     7
     8        If an ARIA Live region udpates an element that is not in the AX object cache, then the Live region
     9        notification is not sent. To fix this, I think the childrenChanged() method needs to actually create
     10        the appropriate objects, but since that method gets called during a render tree update, we've learned
     11        that it's generally not safe to create objects.
     12 
     13        Instead a one shot timer can be fired that will update and create the necessary objects so that the
     14        correct notification can be sent.
     15
     16        Test: platform/mac/accessibility/aria-liveregion-without-element-access.html
     17
     18        * accessibility/AXObjectCache.cpp:
     19        (WebCore::AXObjectCache::AXObjectCache):
     20        (WebCore::AXObjectCache::remove):
     21        (WebCore::AXObjectCache::childrenUpdateTimerFired):
     22        (WebCore::AXObjectCache::childrenChanged):
     23        * accessibility/AXObjectCache.h:
     24        * accessibility/AccessibilityMenuList.cpp:
     25        (WebCore::AccessibilityMenuList::childrenChanged):
     26        * accessibility/AccessibilityMenuList.h:
     27        * accessibility/AccessibilityMenuListPopup.cpp:
     28        (WebCore::AccessibilityMenuListPopup::childrenChanged):
     29        * accessibility/AccessibilityMenuListPopup.h:
     30        * accessibility/AccessibilityObject.h:
     31        (WebCore::AccessibilityObject::childrenChanged):
     32        * accessibility/AccessibilityRenderObject.cpp:
     33        (WebCore::startOfContinuations):
     34           This changed exposed a case where an object was inlineElementContinuation, but not renderInlined,
     35           which led to an assert.
     36        (WebCore::AccessibilityRenderObject::updateAccessibilityRole):
     37        (WebCore::AccessibilityRenderObject::childrenChanged):
     38        * accessibility/AccessibilityRenderObject.h:
     39
    1402011-06-23  Dirk Schulze  <krit@webkit.org>
    241
  • trunk/Source/WebCore/accessibility/AXObjectCache.cpp

    r89440 r89591  
    8383AXObjectCache::AXObjectCache(const Document* doc)
    8484    : m_notificationPostTimer(this, &AXObjectCache::notificationPostTimerFired)
     85    , m_childrenUpdateTimer(this, &AXObjectCache::childrenUpdateTimerFired)
    8586{
    8687    m_document = const_cast<Document*>(doc);
     
    368369    remove(axID);
    369370    m_renderObjectMapping.remove(renderer);
     371    m_childrenToUpdate.remove(renderer);
    370372}
    371373
     
    437439}
    438440#endif
     441   
     442void AXObjectCache::childrenUpdateTimerFired(Timer<AXObjectCache>*)
     443{
     444    if (m_childrenToUpdate.isEmpty())
     445        return;
     446   
     447    // Make a local copy in case childrenChanged() alters m_childrenToUpdate
     448    // (which might happen if the client asks to update the render tree).
     449    HashSet<RenderObject*> updateChildren;
     450    m_childrenToUpdate.swap(updateChildren);
     451    m_childrenToUpdate.clear();
     452   
     453    HashSet<RenderObject*>::iterator end = updateChildren.end();
     454    for (HashSet<RenderObject*>::iterator it = updateChildren.begin(); it != end; ++it) {
     455        if (AccessibilityObject* object = getOrCreate(*it))
     456            object->childrenChanged(AccessibilityObject::CreateParentObjects);
     457    }   
     458}
    439459
    440460void AXObjectCache::childrenChanged(RenderObject* renderer)
     
    444464 
    445465    AXID axID = m_renderObjectMapping.get(renderer);
    446     if (!axID)
    447         return;
    448    
    449     AccessibilityObject* obj = m_objects.get(axID).get();
    450     if (obj)
    451         obj->childrenChanged();
     466    if (!axID) {
     467        // If there's no AX object, creating one right now can be dangerous (because we're in the middle of adding/destroying a tree).
     468        // Instead the update should be postponed and updated later.
     469        m_childrenToUpdate.add(renderer);
     470        if (!m_childrenUpdateTimer.isActive())
     471            m_childrenUpdateTimer.startOneShot(0);
     472    } else {
     473        if (AccessibilityObject* object = m_objects.get(axID).get())
     474            object->childrenChanged(AccessibilityObject::DoNotCreateParentObjects);
     475    }
    452476}
    453477   
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

    r83049 r89591  
    167167    Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost;
    168168    void notificationPostTimerFired(Timer<AXObjectCache>*);
    169    
     169
     170    Timer<AXObjectCache> m_childrenUpdateTimer;
     171    HashSet<RenderObject*> m_childrenToUpdate;
     172    void childrenUpdateTimerFired(Timer<AXObjectCache>*);
     173
    170174    static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*);
    171175   
  • trunk/Source/WebCore/accessibility/AccessibilityMenuList.cpp

    r83064 r89591  
    6969}
    7070
    71 void AccessibilityMenuList::childrenChanged()
     71void AccessibilityMenuList::childrenChanged(ChildrenChangeOptions options)
    7272{
    7373    if (m_children.isEmpty())
     
    7575
    7676    ASSERT(m_children.size() == 1);
    77     m_children[0]->childrenChanged();
     77    m_children[0]->childrenChanged(options);
    7878}
    7979
  • trunk/Source/WebCore/accessibility/AccessibilityMenuList.h

    r83064 r89591  
    5252
    5353    virtual void addChildren();
    54     virtual void childrenChanged();
     54    virtual void childrenChanged(ChildrenChangeOptions);
    5555};
    5656
  • trunk/Source/WebCore/accessibility/AccessibilityMenuListPopup.cpp

    r78150 r89591  
    106106}
    107107
    108 void AccessibilityMenuListPopup::childrenChanged()
     108void AccessibilityMenuListPopup::childrenChanged(ChildrenChangeOptions)
    109109{
    110110    for (size_t i = m_children.size(); i > 0 ; --i) {
  • trunk/Source/WebCore/accessibility/AccessibilityMenuListPopup.h

    r53512 r89591  
    5757    virtual bool press() const;
    5858    virtual void addChildren();
    59     virtual void childrenChanged();
     59    virtual void childrenChanged(ChildrenChangeOptions);
    6060
    6161    AccessibilityMenuListOption* menuListOptionAccessibilityObject(HTMLElement*) const;
  • trunk/Source/WebCore/accessibility/AccessibilityObject.h

    r87856 r89591  
    465465    virtual void decrement() { }
    466466
    467     virtual void childrenChanged() { }
     467    enum ChildrenChangeOptions { DoNotCreateParentObjects, CreateParentObjects };
     468    virtual void childrenChanged(ChildrenChangeOptions) { }
    468469    virtual void contentChanged() { }
    469470    virtual const AccessibilityChildrenVector& children() { return m_children; }
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r89293 r89591  
    223223static inline RenderInline* startOfContinuations(RenderObject* r)
    224224{
    225     if (r->isInlineElementContinuation())
     225    if (r->isInlineElementContinuation() && r->node()->renderer() && r->isRenderInline())
    226226        return toRenderInline(r->node()->renderer());
    227227
     
    30313031    // The AX hierarchy only needs to be updated if the ignored status of an element has changed.
    30323032    if (ignoredStatus != accessibilityIsIgnored())
    3033         childrenChanged();
     3033        childrenChanged(DoNotCreateParentObjects);
    30343034}
    30353035   
     
    33083308}
    33093309   
    3310 void AccessibilityRenderObject::childrenChanged()
     3310void AccessibilityRenderObject::childrenChanged(ChildrenChangeOptions options)
    33113311{
    33123312    // This method is meant as a quick way of marking a portion of the accessibility tree dirty.
     
    33203320    // If AX elements are created now, they could interrogate the render tree while it's in a funky state.
    33213321    // At the same time, process ARIA live region changes.
    3322     for (AccessibilityObject* parent = this; parent; parent = parent->parentObjectIfExists()) {
     3322    for (AccessibilityObject* parent = this; parent; parent = (options == CreateParentObjects) ? parent->parentObject() : parent->parentObjectIfExists()) {
    33233323        if (!parent->isAccessibilityRenderObject())
    33243324            continue;
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h

    r87856 r89591  
    208208   
    209209    virtual void detach();
    210     virtual void childrenChanged();
     210    virtual void childrenChanged(ChildrenChangeOptions);
    211211    virtual void contentChanged();
    212212    virtual void addChildren();
Note: See TracChangeset for help on using the changeset viewer.