Changeset 96340 in webkit


Ignore:
Timestamp:
Sep 29, 2011 10:46:14 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

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

Reviewed by Darin Adler.

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

  • accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::AXObjectCache):
(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):
(WebCore::AccessibilityRenderObject::updateAccessibilityRole):
(WebCore::AccessibilityRenderObject::childrenChanged):

  • accessibility/AccessibilityRenderObject.h:
  • rendering/RenderObject.cpp:

(WebCore::RenderObject::willBeDestroyed):

LayoutTests:

Reviewed by Darin Adler.

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

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r96336 r96340  
     12011-09-29  Chris Fleizach  <cfleizach@apple.com>
     2
     3        ARIA live regions don't trigger notifications for elements that aren't in the AX tree
     4        https://bugs.webkit.org/show_bug.cgi?id=62289
     5
     6        Reviewed by Darin Adler.
     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-09-29  David Reveman  <reveman@chromium.org>
    212
  • trunk/Source/WebCore/ChangeLog

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

    r95901 r96340  
    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);
     
    8990AXObjectCache::~AXObjectCache()
    9091{
     92    m_childrenUpdateTimer.stop();
     93    m_notificationPostTimer.stop();
     94   
    9195    HashMap<AXID, RefPtr<AccessibilityObject> >::iterator end = m_objects.end();
    9296    for (HashMap<AXID, RefPtr<AccessibilityObject> >::iterator it = m_objects.begin(); it != end; ++it) {
     
    368372    remove(axID);
    369373    m_renderObjectMapping.remove(renderer);
     374    m_childrenToUpdate.remove(renderer);
    370375}
    371376
     
    437442}
    438443#endif
     444   
     445void AXObjectCache::childrenUpdateTimerFired(Timer<AXObjectCache>*)
     446{
     447    if (m_childrenToUpdate.isEmpty())
     448        return;
     449   
     450    // Make a local copy in case childrenChanged() alters m_childrenToUpdate
     451    // (which might happen if the client asks to update the render tree).
     452    HashSet<RenderObject*> updateChildren;
     453    m_childrenToUpdate.swap(updateChildren);
     454    m_childrenToUpdate.clear();
     455   
     456    HashSet<RenderObject*>::iterator end = updateChildren.end();
     457    for (HashSet<RenderObject*>::iterator it = updateChildren.begin(); it != end; ++it) {
     458        if (AccessibilityObject* object = getOrCreate(*it))
     459            object->childrenChanged(AccessibilityObject::CreateParentObjects);
     460    }   
     461}
    439462
    440463void AXObjectCache::childrenChanged(RenderObject* renderer)
     
    444467 
    445468    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();
     469    if (!axID) {
     470        // If there's no AX object, creating one right now can be dangerous (because we're in the middle of adding/destroying a tree).
     471        // Instead the update should be postponed and updated later.
     472        m_childrenToUpdate.add(renderer);
     473
     474        if (!m_childrenUpdateTimer.isActive())
     475            m_childrenUpdateTimer.startOneShot(0);
     476    } else {
     477        if (AccessibilityObject* object = m_objects.get(axID).get())
     478            object->childrenChanged(AccessibilityObject::DoNotCreateParentObjects);
     479    }
     480
    452481}
    453482   
  • trunk/Source/WebCore/accessibility/AXObjectCache.h

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

    r95901 r96340  
    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

    r95901 r96340  
    5454
    5555    virtual void addChildren();
    56     virtual void childrenChanged();
     56    virtual void childrenChanged(ChildrenChangeOptions);
    5757};
    5858
  • trunk/Source/WebCore/accessibility/AccessibilityMenuListPopup.cpp

    r95901 r96340  
    104104}
    105105
    106 void AccessibilityMenuListPopup::childrenChanged()
     106void AccessibilityMenuListPopup::childrenChanged(ChildrenChangeOptions)
    107107{
    108108    for (size_t i = m_children.size(); i > 0 ; --i) {
  • trunk/Source/WebCore/accessibility/AccessibilityMenuListPopup.h

    r95901 r96340  
    6060    virtual bool press() const;
    6161    virtual void addChildren();
    62     virtual void childrenChanged();
     62    virtual void childrenChanged(ChildrenChangeOptions);
    6363
    6464    AccessibilityMenuListOption* menuListOptionAccessibilityObject(HTMLElement*) const;
  • trunk/Source/WebCore/accessibility/AccessibilityObject.h

    r95901 r96340  
    551551    virtual void decrement() { }
    552552
    553     virtual void childrenChanged() { }
     553    enum ChildrenChangeOptions { DoNotCreateParentObjects, CreateParentObjects };
     554    virtual void childrenChanged(ChildrenChangeOptions) { }
    554555    virtual void contentChanged() { }
    555556    virtual const AccessibilityChildrenVector& children() { return m_children; }
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp

    r95901 r96340  
    224224static inline RenderInline* startOfContinuations(RenderObject* r)
    225225{
    226     if (r->isInlineElementContinuation())
     226    if (r->isInlineElementContinuation() && r->node()->renderer() && r->isRenderInline())
    227227        return toRenderInline(r->node()->renderer());
    228228
     
    30883088    // The AX hierarchy only needs to be updated if the ignored status of an element has changed.
    30893089    if (ignoredStatus != accessibilityIsIgnored())
    3090         childrenChanged();
     3090        childrenChanged(DoNotCreateParentObjects);
    30913091}
    30923092   
     
    33713371}
    33723372   
    3373 void AccessibilityRenderObject::childrenChanged()
     3373void AccessibilityRenderObject::childrenChanged(ChildrenChangeOptions options)
    33743374{
    33753375    // This method is meant as a quick way of marking a portion of the accessibility tree dirty.
     
    33833383    // If AX elements are created now, they could interrogate the render tree while it's in a funky state.
    33843384    // At the same time, process ARIA live region changes.
    3385     for (AccessibilityObject* parent = this; parent; parent = parent->parentObjectIfExists()) {
     3385    for (AccessibilityObject* parent = this; parent; parent = (options == CreateParentObjects) ? parent->parentObject() : parent->parentObjectIfExists()) {
    33863386        if (!parent->isAccessibilityRenderObject())
    33873387            continue;
  • trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h

    r95901 r96340  
    216216   
    217217    virtual void detach();
    218     virtual void childrenChanged();
     218    virtual void childrenChanged(ChildrenChangeOptions);
    219219    virtual void contentChanged();
    220220    virtual void addChildren();
  • trunk/Source/WebCore/rendering/RenderObject.cpp

    r96187 r96340  
    21772177        frame()->eventHandler()->stopAutoscrollTimer(true);
    21782178
    2179     if (AXObjectCache::accessibilityEnabled()) {
    2180         document()->axObjectCache()->childrenChanged(this->parent());
    2181         document()->axObjectCache()->remove(this);
    2182     }
    21832179    animation()->cancelAnimations(this);
    21842180
     
    21982194        setHasLayer(false);
    21992195        toRenderBoxModelObject(this)->destroyLayer();
     2196    }
     2197   
     2198    // Update accessibility at the end, so that all children nodes have been disassociated first.
     2199    // This ordering allows us to call childrenChanged() on the parent without worrying that the parent has been destroyed.
     2200    if (AXObjectCache::accessibilityEnabled()) {
     2201        document()->axObjectCache()->childrenChanged(this->parent());
     2202        document()->axObjectCache()->remove(this);
    22002203    }
    22012204}
Note: See TracChangeset for help on using the changeset viewer.