Changeset 58150 in webkit


Ignore:
Timestamp:
Apr 22, 2010 10:47:06 PM (14 years ago)
Author:
mjs@apple.com
Message:

2010-04-22 Maciej Stachowiak <mjs@apple.com>

Reviewed by Dan Bernstein.

Links around blocks (e.g. divs) results in too many VoiceOver call outs
https://bugs.webkit.org/show_bug.cgi?id=37079

The basic change is to modify the AccessibilityRenderObject tree
traversal methods to account for inline continuations in the
render tree and make the accessibility tree look as if
continuations didn't exist - the same as if CSS blocks could just
sit in CSS inlines. This is slightly tricky code but creates a
much saner accessibility tree.


Tests: accessibility/image-link-inline-cont.html

accessibility/image-link.html
accessibility/inline-continuations.html

  • accessibility/AccessibilityRenderObject.cpp: (WebCore::isInlineWithContinuation): Helper function for traversal functions to use in accounting for continuations. (WebCore::firstChildInContinuation): ditto (WebCore::firstChildConsideringContinuation): ditto (WebCore::lastChildConsideringContinuation): ditto (WebCore::startOfContinuations): ditto (WebCore::endOfContinuations): ditto (WebCore::childBeforeConsideringContinuations): ditto (WebCore::firstChildIsInlineContinuation): ditto (WebCore::lastChildHasContinuation): ditto (WebCore::AccessibilityRenderObject::firstChild): Account for inline continuations. (WebCore::AccessibilityRenderObject::lastChild): ditto (WebCore::AccessibilityRenderObject::previousSibling): Account for inline continuations and their anonymous block parents. (WebCore::AccessibilityRenderObject::nextSibling): ditto (WebCore::AccessibilityRenderObject::parentObjectIfExists): Account for inline continuations. (WebCore::AccessibilityRenderObject::parentObject): Account for inline continuations.
  • rendering/RenderInline.h: Make RenderInline::inlineContinuation public.

2010-04-22 Maciej Stachowiak <mjs@apple.com>

Reviewed by Dan Bernstein.

Links around blocks (e.g. divs) results in too many VoiceOver call outs
https://bugs.webkit.org/show_bug.cgi?id=37079


The new test cases verify the accessibility tree created by an image inside a link, and verify
that adding a div with role=presentation now has no effect on the accessibility tree (as expected).

  • accessibility/image-link-inline-cont-expected.txt: Added.
  • accessibility/image-link-inline-cont.html: Added.
  • accessibility/image-link.html: Added.
  • platform/gtk/Skipped:
  • platform/mac/accessibility/image-link-expected.txt: Added.
  • platform/win/Skipped:


Test to check that accessibility tree doesn't get duplicate content in the presence
of inline continuations (this was a bug in an earlier version of this patch).

  • accessibility/inline-continuations-expected.txt: Added.
  • accessibility/inline-continuations.html: Added.
Location:
trunk
Files:
6 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r58149 r58150  
     12010-04-22  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     4
     5        Links around blocks (e.g. divs) results in too many VoiceOver call outs
     6        https://bugs.webkit.org/show_bug.cgi?id=37079
     7       
     8        The new test cases verify the accessibility tree created by an image inside a link, and verify
     9        that adding a div with role=presentation now has no effect on the accessibility tree (as expected).
     10
     11        * accessibility/image-link-inline-cont-expected.txt: Added.
     12        * accessibility/image-link-inline-cont.html: Added.
     13        * accessibility/image-link.html: Added.
     14        * platform/gtk/Skipped:
     15        * platform/mac/accessibility/image-link-expected.txt: Added.
     16        * platform/win/Skipped:
     17       
     18        Test to check that accessibility tree doesn't get duplicate content in the presence
     19        of inline continuations (this was a bug in an earlier version of this patch).
     20
     21        * accessibility/inline-continuations-expected.txt: Added.
     22        * accessibility/inline-continuations.html: Added.
     23
    1242010-04-22  Shinichiro Hamaji  <hamaji@chromium.org>
    225
  • trunk/LayoutTests/platform/gtk/Skipped

    r58111 r58150  
    8585accessibility/aria-roles.html
    8686accessibility/aria-tables.html
     87accessibility/image-link.html
     88accessibility/image-link-inline-cont.html
    8789accessibility/image-map1.html
    8890accessibility/image-map2.html
     91accessibility/inline-continuations.html
    8992accessibility/internal-link-anchors2.html
    9093accessibility/label-for-control-hittest.html
  • trunk/LayoutTests/platform/win/Skipped

    r58021 r58150  
    393393accessibility/iframe-bastardization.html
    394394accessibility/ignore-spacer-elements.html
     395accessibility/image-link.html
    395396accessibility/image-map1.html
    396397accessibility/image-map2.html
  • trunk/WebCore/ChangeLog

    r58149 r58150  
     12010-04-22  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     4
     5        Links around blocks (e.g. divs) results in too many VoiceOver call outs
     6        https://bugs.webkit.org/show_bug.cgi?id=37079
     7
     8        The basic change is to modify the AccessibilityRenderObject tree
     9        traversal methods to account for inline continuations in the
     10        render tree and make the accessibility tree look as if
     11        continuations didn't exist - the same as if CSS blocks could just
     12        sit in CSS inlines. This is slightly tricky code but creates a
     13        much saner accessibility tree.
     14       
     15        Tests: accessibility/image-link-inline-cont.html
     16               accessibility/image-link.html
     17               accessibility/inline-continuations.html
     18
     19        * accessibility/AccessibilityRenderObject.cpp:
     20        (WebCore::isInlineWithContinuation): Helper function for traversal functions to use in accounting for continuations.
     21        (WebCore::firstChildInContinuation): ditto
     22        (WebCore::firstChildConsideringContinuation): ditto
     23        (WebCore::lastChildConsideringContinuation): ditto
     24        (WebCore::startOfContinuations): ditto
     25        (WebCore::endOfContinuations): ditto
     26        (WebCore::childBeforeConsideringContinuations): ditto
     27        (WebCore::firstChildIsInlineContinuation): ditto
     28        (WebCore::lastChildHasContinuation): ditto
     29        (WebCore::AccessibilityRenderObject::firstChild): Account for inline continuations.
     30        (WebCore::AccessibilityRenderObject::lastChild): ditto
     31        (WebCore::AccessibilityRenderObject::previousSibling): Account for inline continuations
     32        and their anonymous block parents.
     33        (WebCore::AccessibilityRenderObject::nextSibling): ditto
     34        (WebCore::AccessibilityRenderObject::parentObjectIfExists): Account for inline continuations.
     35        (WebCore::AccessibilityRenderObject::parentObject): Account for inline continuations.
     36        * rendering/RenderInline.h: Make RenderInline::inlineContinuation public.
     37
    1382010-04-22  Shinichiro Hamaji  <hamaji@chromium.org>
    239
  • trunk/WebCore/accessibility/AccessibilityRenderObject.cpp

    r58037 r58150  
    119119}
    120120
     121static inline bool isInlineWithContinuation(RenderObject* renderer)
     122{
     123    if (!renderer->isRenderInline())
     124        return false;
     125
     126    return toRenderInline(renderer)->continuation();
     127}
     128
     129static inline RenderObject* firstChildInContinuation(RenderObject* renderer)
     130{
     131    RenderObject* r = toRenderInline(renderer)->continuation();
     132
     133    while (r) {
     134        if (r->isRenderBlock())
     135            return r;
     136        if (RenderObject* child = r->firstChild())
     137            return child;
     138        r = toRenderInline(r)->continuation();
     139    }
     140
     141    return 0;
     142}
     143
     144static inline RenderObject* firstChildConsideringContinuation(RenderObject* renderer)
     145{
     146    RenderObject* firstChild = renderer->firstChild();
     147
     148    if (!firstChild && isInlineWithContinuation(renderer))
     149        firstChild = firstChildInContinuation(renderer);
     150
     151    return firstChild;
     152}
     153
     154
     155static inline RenderObject* lastChildConsideringContinuation(RenderObject* renderer)
     156{
     157    RenderObject* lastChild = renderer->lastChild();
     158    RenderObject* prev = renderer;
     159    RenderObject* cur = renderer;
     160
     161    if (!cur->isRenderInline() && !cur->isRenderBlock())
     162        return renderer;
     163
     164    while (cur) {
     165        prev = cur;
     166
     167        if (RenderObject* lc = cur->lastChild())
     168            lastChild = lc;
     169
     170        if (cur->isRenderInline()) {
     171            cur = toRenderInline(cur)->inlineContinuation();
     172            ASSERT(cur || !toRenderInline(prev)->continuation());
     173        } else
     174            cur = toRenderBlock(cur)->inlineContinuation();
     175    }
     176
     177    return lastChild;
     178}
     179
    121180AccessibilityObject* AccessibilityRenderObject::firstChild() const
    122181{
     
    124183        return 0;
    125184   
    126     RenderObject* firstChild = m_renderer->firstChild();
     185    RenderObject* firstChild = firstChildConsideringContinuation(m_renderer);
     186
    127187    if (!firstChild)
    128188        return 0;
     
    135195    if (!m_renderer)
    136196        return 0;
    137    
    138     RenderObject* lastChild = m_renderer->lastChild();
     197
     198    RenderObject* lastChild = lastChildConsideringContinuation(m_renderer);
     199
    139200    if (!lastChild)
    140201        return 0;
     
    143204}
    144205
     206static inline RenderInline* startOfContinuations(RenderObject* r)
     207{
     208    if (r->isInlineContinuation())
     209        return toRenderInline(r->node()->renderer());
     210
     211    // Blocks with a previous continuation always have a next continuation
     212    if (r->isRenderBlock() && toRenderBlock(r)->inlineContinuation())
     213        return toRenderInline(toRenderBlock(r)->inlineContinuation()->node()->renderer());
     214
     215    return 0;
     216}
     217
     218static inline RenderObject* endOfContinuations(RenderObject* renderer)
     219{
     220    RenderObject* prev = renderer;
     221    RenderObject* cur = renderer;
     222
     223    if (!cur->isRenderInline() && !cur->isRenderBlock())
     224        return renderer;
     225
     226    while (cur) {
     227        prev = cur;
     228        if (cur->isRenderInline()) {
     229            cur = toRenderInline(cur)->inlineContinuation();
     230            ASSERT(cur || !toRenderInline(prev)->continuation());
     231        } else
     232            cur = toRenderBlock(cur)->inlineContinuation();
     233    }
     234
     235    return prev;
     236}
     237
     238
     239static inline RenderObject* childBeforeConsideringContinuations(RenderInline* r, RenderObject* child)
     240{
     241    RenderBoxModelObject* curContainer = r;
     242    RenderObject* cur = 0;
     243    RenderObject* prev = 0;
     244
     245    while (curContainer) {
     246        if (curContainer->isRenderInline()) {
     247            cur = curContainer->firstChild();
     248            while (cur) {
     249                if (cur == child)
     250                    return prev;
     251                prev = cur;
     252                cur = cur->nextSibling();
     253            }
     254
     255            curContainer = toRenderInline(curContainer)->continuation();
     256        } else if (curContainer->isRenderBlock()) {
     257            if (curContainer == child)
     258                return prev;
     259
     260            prev = curContainer;
     261            curContainer = toRenderBlock(curContainer)->inlineContinuation();
     262        }
     263    }
     264
     265    ASSERT_NOT_REACHED();
     266
     267    return 0;
     268}
     269
     270static inline bool firstChildIsInlineContinuation(RenderObject* renderer)
     271{
     272    return renderer->firstChild() && renderer->firstChild()->isInlineContinuation();
     273}
     274
    145275AccessibilityObject* AccessibilityRenderObject::previousSibling() const
    146276{
    147277    if (!m_renderer)
    148278        return 0;
    149    
    150     RenderObject* previousSibling = m_renderer->previousSibling();
     279
     280    RenderObject* previousSibling = 0;
     281
     282    // Case 1: The node is a block and is an inline's continuation. In that case, the inline's
     283    // last child is our previous sibling (or further back in the continuation chain)
     284    RenderInline* startOfConts;
     285    if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer)))
     286        previousSibling = childBeforeConsideringContinuations(startOfConts, m_renderer);
     287
     288    // Case 2: Anonymous block parent of the end of a continuation - skip all the way to before
     289    // the parent of the start, since everything in between will be linked up via the continuation.
     290    else if (m_renderer->isAnonymousBlock() && firstChildIsInlineContinuation(m_renderer))
     291        previousSibling = startOfContinuations(m_renderer->firstChild())->parent()->previousSibling();
     292
     293    // Case 3: The node has an actual previous sibling
     294    else if (RenderObject* ps = m_renderer->previousSibling())
     295        previousSibling = ps;
     296
     297    // Case 4: This node has no previous siblings, but its parent is an inline,
     298    // and is another node's inline continutation. Follow the continuation chain.
     299    else if (m_renderer->parent()->isRenderInline() && (startOfConts = startOfContinuations(m_renderer->parent())))
     300        previousSibling = childBeforeConsideringContinuations(startOfConts, m_renderer->parent()->firstChild());
     301
    151302    if (!previousSibling)
    152303        return 0;
     
    155306}
    156307
     308static inline bool lastChildHasContinuation(RenderObject* renderer)
     309{
     310    return renderer->lastChild() && isInlineWithContinuation(renderer->lastChild());
     311}
     312
    157313AccessibilityObject* AccessibilityRenderObject::nextSibling() const
    158314{
    159315    if (!m_renderer)
    160316        return 0;
    161    
    162     RenderObject* nextSibling = m_renderer->nextSibling();
     317
     318    RenderObject* nextSibling = 0;
     319
     320    // Case 1: node is a block and has an inline continuation. Next sibling is the inline continuation's
     321    // first child.
     322    RenderInline* inlineContinuation;
     323    if (m_renderer->isRenderBlock() && (inlineContinuation = toRenderBlock(m_renderer)->inlineContinuation()))
     324        nextSibling = firstChildConsideringContinuation(inlineContinuation);
     325
     326    // Case 2: Anonymous block parent of the start of a continuation - skip all the way to
     327    // after the parent of the end, since everything in between will be linked up via the continuation.
     328    else if (m_renderer->isAnonymousBlock() && lastChildHasContinuation(m_renderer))
     329        nextSibling = endOfContinuations(m_renderer->lastChild())->parent()->nextSibling();
     330
     331    // Case 3: node has an actual next sibling
     332    else if (RenderObject* ns = m_renderer->nextSibling())
     333        nextSibling = ns;
     334
     335    // Case 4: node is an inline with a continuation. Next sibling is the next sibling of the end
     336    // of the continuation chain.
     337    else if (isInlineWithContinuation(m_renderer))
     338        nextSibling = endOfContinuations(m_renderer)->nextSibling();
     339
     340    // Case 5: node has no next sibling, and its parent is an inline with a continuation.
     341    else if (isInlineWithContinuation(m_renderer->parent())) {
     342        RenderObject* continuation = toRenderInline(m_renderer->parent())->continuation();
     343       
     344        // Case 4a: continuation is a block - in this case the block itself is the next sibling.
     345        if (continuation->isRenderBlock())
     346            nextSibling = continuation;
     347        // Case 4b: continuation is an inline - in this case the inline's first child is the next sibling
     348        else
     349            nextSibling = firstChildConsideringContinuation(continuation);
     350    }
     351
    163352    if (!nextSibling)
    164353        return 0;
     
    171360    if (!m_renderer)
    172361        return 0;
    173    
     362
    174363    RenderObject* parent = m_renderer->parent();
     364
     365    // Case 1: node is a block and is an inline's continuation. Parent
     366    // is the start of the continuation chain.
     367    RenderInline* startOfConts = 0;
     368    if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer)))
     369        parent = startOfConts;
     370
     371    // Case 2: node's parent is an inline which is some node's continuation; parent is
     372    // the earliest node in the continuation chain.
     373    else if (parent && parent->isRenderInline() && (startOfConts = startOfContinuations(parent)))
     374        parent = startOfConts;
     375
    175376    if (!parent)
    176377        return 0;
     
    185386   
    186387    RenderObject* parent = m_renderer->parent();
     388
     389    // Case 1: node is a block and is an inline's continuation. Parent
     390    // is the start of the continuation chain.
     391    RenderInline* startOfConts = 0;
     392    if (m_renderer->isRenderBlock() && (startOfConts = startOfContinuations(m_renderer)))
     393        parent = startOfConts;
     394
     395    // Case 2: node's parent is an inline which is some node's continuation; parent is
     396    // the earliest node in the continuation chain.
     397    else if (parent && parent->isRenderInline() && (startOfConts = startOfContinuations(parent)))
     398        parent = startOfConts;
     399
    187400    if (!parent)
    188401        return 0;
  • trunk/WebCore/rendering/RenderInline.h

    r54784 r58150  
    7272    void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; }
    7373
     74    RenderInline* inlineContinuation() const;
     75
    7476private:
    7577    virtual RenderObjectChildList* virtualChildren() { return children(); }
     
    127129    virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const;
    128130
    129     RenderInline* inlineContinuation() const;
    130131    void setContinuation(RenderBoxModelObject* c) { m_continuation = c; }
    131132   
Note: See TracChangeset for help on using the changeset viewer.