Changeset 74025 in webkit


Ignore:
Timestamp:
Dec 14, 2010 7:35:22 AM (13 years ago)
Author:
mario@webkit.org
Message:

2010-12-14 Mario Sanchez Prada <msanchez@igalia.com>

Reviewed by Xan Lopez.

[Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
https://bugs.webkit.org/show_bug.cgi?id=27048

Added a new GTK-specific test to check focus{able|ed} states are
properly set when moving the caret across text objects.

  • platform/gtk/accessibility/caret-browsing-text-focus-expected.txt: Added.
  • platform/gtk/accessibility/caret-browsing-text-focus.html: Added.

2010-12-14 Mario Sanchez Prada <msanchez@igalia.com>

Reviewed by Xan Lopez.

[Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
https://bugs.webkit.org/show_bug.cgi?id=27048

Handle focus change for text objects based in caret changes.

As text objects (such as paragraphs) seem not to accept focus in
WebCore in the same way other objects (text controls) do, a
Gtk-specific workaround is needed to expose this states and the
related events to ATK-based assistive technologies.

Test: platform/gtk/accessibility/caret-browsing-text-focus.html

Ensure that text objects are exposed with the ATK_STATE_FOCUSABLE
state, and that the ATK_STATE_FOCUSED state is added to those
text objects containing the currently active caret selection.

  • accessibility/gtk/AccessibilityObjectWrapperAtk.cpp: (selectionBelongsToObject): Moved upwards to use it from the new isTextWithCaret() function. (isTextWithCaret): New, checks whether an accessibility object represents a text object with the current caret selection on it. (setAtkStateSetFromCoreObject): Add the ATK_STATE_FOCUSED state when also when isTextWithCaret(coreObject) returns true. (webkit_accessible_ref_state_set): Add the ATK_STATE_FOCUSABLE state to text objects and those with the ATK_ROLE_PARAGRAPH role. (webkit_accessible_text_get_n_selections): Optimize return expression.

Make sure the proper events associated to a change of focus are
emitted, based on caret changes across different accessibility
objects. Also, refactored the code in more manageable and
understandable helper functions.

  • editing/gtk/SelectionControllerGtk.cpp: (WebCore::emitTextSelectionChange): New, includes the specific code formerly placed in notifyAccessibilityForSelectionChange() to emit the 'text-caret-moved' and 'text-selection-change' signals. (WebCore::maybeEmitTextFocusChange): New, takes care of emitting the 'focus-event' and 'state-changed::focused' signals when needed, that is, when a change in the selection happens across different accessible objects. (WebCore::SelectionController::notifyAccessibilityForSelectionChange): Refactored some code here, by using the new helper functions.

2010-12-14 Mario Sanchez Prada <msanchez@igalia.com>

Reviewed by Xan Lopez.

[Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
https://bugs.webkit.org/show_bug.cgi?id=27048

Add support in DRT for checking whether an accessibility UI
element is focusable and/or focused. Implemented for GTK.

  • DumpRenderTree/AccessibilityUIElement.cpp: (getIsFocusedCallback): New. (getIsFocusableCallback): New. (AccessibilityUIElement::getJSClass): Add the new available callbacks for isFocused and isFocusable.
  • DumpRenderTree/AccessibilityUIElement.h:
  • DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp: (AccessibilityUIElement::isFocused): New, implemented by checking whether the related AtkState value is in the object's state set. (AccessibilityUIElement::isFocusable): Ditto.
  • DumpRenderTree/mac/AccessibilityUIElementMac.mm: (AccessibilityUIElement::isFocused): New, dummy implementation. (AccessibilityUIElement::isFocusable): Ditto.
  • DumpRenderTree/win/AccessibilityUIElementWin.cpp: (AccessibilityUIElement::isFocused): Ditto. (AccessibilityUIElement::isFocusable): Ditto.
Location:
trunk
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r74021 r74025  
     12010-12-14  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
     6        https://bugs.webkit.org/show_bug.cgi?id=27048
     7
     8        Added a new GTK-specific test to check focus{able|ed} states are
     9        properly set when moving the caret across text objects.
     10
     11        * platform/gtk/accessibility/caret-browsing-text-focus-expected.txt: Added.
     12        * platform/gtk/accessibility/caret-browsing-text-focus.html: Added.
     13
    1142010-12-14  Pavel Feldman  <pfeldman@chromium.org>
    215
  • trunk/WebCore/ChangeLog

    r74022 r74025  
     12010-12-14  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
     6        https://bugs.webkit.org/show_bug.cgi?id=27048
     7
     8        Handle focus change for text objects based in caret changes.
     9
     10        As text objects (such as paragraphs) seem not to accept focus in
     11        WebCore in the same way other objects (text controls) do, a
     12        Gtk-specific workaround is needed to expose this states and the
     13        related events to ATK-based assistive technologies.
     14
     15        Test: platform/gtk/accessibility/caret-browsing-text-focus.html
     16
     17        Ensure that text objects are exposed with the ATK_STATE_FOCUSABLE
     18        state, and that the ATK_STATE_FOCUSED state is added to those
     19        text objects containing the currently active caret selection.
     20
     21        * accessibility/gtk/AccessibilityObjectWrapperAtk.cpp:
     22        (selectionBelongsToObject): Moved upwards to use it from
     23        the new isTextWithCaret() function.
     24        (isTextWithCaret): New, checks whether an accessibility object
     25        represents a text object with the current caret selection on it.
     26        (setAtkStateSetFromCoreObject): Add the ATK_STATE_FOCUSED state
     27        when also when isTextWithCaret(coreObject) returns true.
     28        (webkit_accessible_ref_state_set): Add the ATK_STATE_FOCUSABLE
     29        state to text objects and those with the ATK_ROLE_PARAGRAPH role.
     30        (webkit_accessible_text_get_n_selections): Optimize return expression.
     31
     32        Make sure the proper events associated to a change of focus are
     33        emitted, based on caret changes across different accessibility
     34        objects. Also, refactored the code in more manageable and
     35        understandable helper functions.
     36
     37        * editing/gtk/SelectionControllerGtk.cpp:
     38        (WebCore::emitTextSelectionChange): New, includes the specific
     39        code formerly placed in notifyAccessibilityForSelectionChange() to
     40        emit the 'text-caret-moved' and 'text-selection-change' signals.
     41        (WebCore::maybeEmitTextFocusChange): New, takes care of emitting
     42        the 'focus-event' and 'state-changed::focused' signals when
     43        needed, that is, when a change in the selection happens across
     44        different accessible objects.
     45        (WebCore::SelectionController::notifyAccessibilityForSelectionChange):
     46        Refactored some code here, by using the new helper functions.
     47
    1482010-12-14  Ilya Tikhonovsky  <loislo@chromium.org>
    249
  • trunk/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp

    r73825 r74025  
    6060#include "RenderText.h"
    6161#include "SelectElement.h"
     62#include "Settings.h"
    6263#include "TextEncoding.h"
    6364#include "TextIterator.h"
     
    478479}
    479480
     481static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
     482{
     483    if (!coreObject || !coreObject->isAccessibilityRenderObject())
     484        return false;
     485
     486    if (selection.isNone())
     487        return false;
     488
     489    RefPtr<Range> range = selection.toNormalizedRange();
     490    if (!range)
     491        return false;
     492
     493    // We want to check that both the selection intersects the node
     494    // AND that the selection is not just "touching" one of the
     495    // boundaries for the selected node. We want to check whether the
     496    // node is actually inside the region, at least partially.
     497    Node* node = coreObject->node();
     498    Node* lastDescendant = node->lastDescendant();
     499    ExceptionCode ec = 0;
     500    return (range->intersectsNode(node, ec)
     501            && (range->endContainer() != node || range->endOffset())
     502            && (range->startContainer() != lastDescendant || range->startOffset() != lastOffsetInNode(lastDescendant)));
     503}
     504
     505static bool isTextWithCaret(AccessibilityObject* coreObject)
     506{
     507    if (!coreObject || !coreObject->isAccessibilityRenderObject())
     508        return false;
     509
     510    Document* document = coreObject->document();
     511    if (!document)
     512        return false;
     513
     514    Frame* frame = document->frame();
     515    if (!frame)
     516        return false;
     517
     518    Settings* settings = frame->settings();
     519    if (!settings || !settings->caretBrowsingEnabled())
     520        return false;
     521
     522    // Check text objects and paragraphs only.
     523    AtkObject* axObject = coreObject->wrapper();
     524    AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
     525    if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
     526        return false;
     527
     528    // Finally, check whether the caret is set in the current object.
     529    VisibleSelection selection = coreObject->selection();
     530    if (!selection.isCaret())
     531        return false;
     532
     533    return selectionBelongsToObject(coreObject, selection);
     534}
     535
    480536static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
    481537{
     
    511567        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
    512568
    513     if (coreObject->isFocused())
     569    if (coreObject->isFocused() || isTextWithCaret(coreObject))
    514570        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
    515571
     
    580636    }
    581637
     638    // Text objects must be focusable.
     639    AtkRole role = atk_object_get_role(object);
     640    if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
     641        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
     642
    582643    setAtkStateSetFromCoreObject(coreObject, stateSet);
    583 
    584644    return stateSet;
    585645}
     
    14861546}
    14871547
    1488 static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
    1489 {
    1490     if (!coreObject->isAccessibilityRenderObject())
    1491         return false;
    1492 
    1493     RefPtr<Range> range = selection.toNormalizedRange();
    1494     if (!range)
    1495         return false;
    1496 
    1497     // We want to check that both the selection intersects the node
    1498     // AND that the selection is not just "touching" one of the
    1499     // boundaries for the selected node. We want to check whether the
    1500     // node is actually inside the region, at least partially
    1501     Node* node = coreObject->node();
    1502     Node* lastDescendant = node->lastDescendant();
    1503     ExceptionCode ec = 0;
    1504     return (range->intersectsNode(node, ec)
    1505             && (range->endContainer() != node || range->endOffset())
    1506             && (range->startContainer() != lastDescendant || range->startOffset() != lastOffsetInNode(lastDescendant)));
    1507 }
    1508 
    15091548static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, VisibleSelection& selection, gint& startOffset, gint& endOffset)
    15101549{
     
    15701609    // there's no way to get the selection for a given object, only
    15711610    // the global one (the API is a bit confusing)
    1572     return !selectionBelongsToObject(coreObject, selection) || selection.isNone() ? 0 : 1;
     1611    return selectionBelongsToObject(coreObject, selection) ? 1 : 0;
    15731612}
    15741613
  • trunk/WebCore/editing/gtk/SelectionControllerGtk.cpp

    r68665 r74025  
    2424#include "AXObjectCache.h"
    2525#include "Frame.h"
     26#include "RefPtr.h"
    2627
    2728#include <gtk/gtk.h>
     
    2930namespace WebCore {
    3031
     32static void emitTextSelectionChange(AccessibilityObject* object, VisibleSelection selection, int offset)
     33{
     34    AtkObject* axObject = object->wrapper();
     35    if (!axObject || !ATK_IS_TEXT(axObject))
     36        return;
     37
     38    g_signal_emit_by_name(axObject, "text-caret-moved", offset);
     39    if (selection.isRange())
     40        g_signal_emit_by_name(axObject, "text-selection-changed");
     41}
     42
     43static void maybeEmitTextFocusChange(PassRefPtr<AccessibilityObject> prpObject)
     44{
     45    // This static variable is needed to keep track of the old object
     46    // as per previous calls to this function, in order to properly
     47    // decide whether to emit some signals or not.
     48    DEFINE_STATIC_LOCAL(RefPtr<AccessibilityObject>, oldObject, ());
     49
     50    RefPtr<AccessibilityObject> object = prpObject;
     51
     52    // Ensure the oldObject belongs to the same document that the
     53    // current object so further comparisons make sense. Otherwise,
     54    // just reset oldObject to 0 so it won't be taken into account in
     55    // the immediately following call to this function.
     56    if (object && oldObject && oldObject->document() != object->document())
     57        oldObject = 0;
     58
     59    AtkObject* axObject = object ? object->wrapper() : 0;
     60    AtkObject* oldAxObject = oldObject ? oldObject->wrapper() : 0;
     61
     62    if (axObject != oldAxObject) {
     63        if (oldAxObject && ATK_IS_TEXT(oldAxObject)) {
     64            g_signal_emit_by_name(oldAxObject, "focus-event", false);
     65            g_signal_emit_by_name(oldAxObject, "state-change", "focused", false);
     66        }
     67        if (axObject && ATK_IS_TEXT(axObject)) {
     68            g_signal_emit_by_name(axObject, "focus-event", true);
     69            g_signal_emit_by_name(axObject, "state-change", "focused", true);
     70        }
     71    }
     72
     73    // Update pointer to last focused object.
     74    oldObject = object;
     75}
     76
     77
    3178void SelectionController::notifyAccessibilityForSelectionChange()
    3279{
    33     if (AXObjectCache::accessibilityEnabled() && m_selection.start().isNotNull() && m_selection.end().isNotNull()) {
    34         RenderObject* focusedNode = m_selection.end().node()->renderer();
    35         AccessibilityObject* accessibilityObject = m_frame->document()->axObjectCache()->getOrCreate(focusedNode);
     80    if (!AXObjectCache::accessibilityEnabled())
     81        return;
    3682
    37         // need to check this as getOrCreate could return 0
    38         if (!accessibilityObject)
    39             return;
     83    // Reset lastFocuseNode and return for no valid selections.
     84    if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull())
     85        return;
    4086
    41         int offset;
    42         // Always report the events w.r.t. the non-linked unignored parent. (i.e. ignoreLinks == true)
    43         AccessibilityObject* object = objectAndOffsetUnignored(accessibilityObject, offset, true);
    44         if (!object)
    45             return;
     87    RenderObject* focusedNode = m_selection.end().node()->renderer();
     88    AccessibilityObject* accessibilityObject = m_frame->document()->axObjectCache()->getOrCreate(focusedNode);
    4689
    47         AtkObject* wrapper = object->wrapper();
    48         if (ATK_IS_TEXT(wrapper)) {
    49             g_signal_emit_by_name(wrapper, "text-caret-moved", offset);
    50             if (m_selection.isRange())
    51                 g_signal_emit_by_name(wrapper, "text-selection-changed");
    52         }
    53     }
     90    // Need to check this as getOrCreate could return 0,
     91    if (!accessibilityObject)
     92        return;
     93
     94    int offset;
     95    // Always report the events w.r.t. the non-linked unignored parent. (i.e. ignoreLinks == true).
     96    RefPtr<AccessibilityObject> object = objectAndOffsetUnignored(accessibilityObject, offset, true);
     97    if (!object)
     98        return;
     99
     100    // Emit relatedsignals.
     101    emitTextSelectionChange(object.get(), m_selection, offset);
     102    maybeEmitTextFocusChange(object.release());
    54103}
    55104
  • trunk/WebKitTools/ChangeLog

    r74008 r74025  
     12010-12-14  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
     6        https://bugs.webkit.org/show_bug.cgi?id=27048
     7
     8        Add support in DRT for checking whether an accessibility UI
     9        element is focusable and/or focused. Implemented for GTK.
     10
     11        * DumpRenderTree/AccessibilityUIElement.cpp:
     12        (getIsFocusedCallback): New.
     13        (getIsFocusableCallback): New.
     14        (AccessibilityUIElement::getJSClass): Add the new available
     15        callbacks for isFocused and isFocusable.
     16        * DumpRenderTree/AccessibilityUIElement.h:
     17        * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
     18        (AccessibilityUIElement::isFocused): New, implemented by checking
     19        whether the related AtkState value is in the object's state set.
     20        (AccessibilityUIElement::isFocusable): Ditto.
     21        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
     22        (AccessibilityUIElement::isFocused): New, dummy implementation.
     23        (AccessibilityUIElement::isFocusable): Ditto.
     24        * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
     25        (AccessibilityUIElement::isFocused): Ditto.
     26        (AccessibilityUIElement::isFocusable): Ditto.
     27
    1282010-12-14  Eric Seidel  <eric@webkit.org>
    229
  • trunk/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp

    r71792 r74025  
    663663{
    664664    return JSValueMakeBoolean(context, toAXElement(thisObject)->isRequired());
     665}
     666
     667static JSValueRef getIsFocusedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
     668{
     669    return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocused());
     670}
     671
     672static JSValueRef getIsFocusableCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
     673{
     674    return JSValueMakeBoolean(context, toAXElement(thisObject)->isFocusable());
    665675}
    666676
     
    876886        { "isEnabled", getIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    877887        { "isRequired", getIsRequiredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     888        { "isFocused", getIsFocusedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
     889        { "isFocusable", getIsFocusableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    878890        { "isSelected", getIsSelectedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    879891        { "isSelectable", getIsSelectableCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
  • trunk/WebKitTools/DumpRenderTree/AccessibilityUIElement.h

    r71792 r74025  
    132132    bool isRequired() const;
    133133   
     134    bool isFocused() const;
     135    bool isFocusable() const;
    134136    bool isSelected() const;
    135137    bool isSelectable() const;
  • trunk/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp

    r73732 r74025  
    404404}
    405405
     406bool AccessibilityUIElement::isFocused() const
     407{
     408    if (!ATK_IS_OBJECT(m_element))
     409        return false;
     410
     411    PlatformRefPtr<AtkStateSet> stateSet = adoptPlatformRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
     412    gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED);
     413
     414    return isFocused;
     415}
     416
    406417bool AccessibilityUIElement::isSelected() const
    407418{
     
    655666}
    656667
     668bool AccessibilityUIElement::isFocusable() const
     669{
     670    if (!ATK_IS_OBJECT(m_element))
     671        return false;
     672
     673    PlatformRefPtr<AtkStateSet> stateSet = adoptPlatformRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
     674    gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE);
     675
     676    return isFocusable;
     677}
     678
    657679bool AccessibilityUIElement::isSelectable() const
    658680{
  • trunk/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm

    r70792 r74025  
    762762}
    763763
     764bool AccessibilityUIElement::isFocused() const
     765{
     766    // FIXME: implement
     767    return false;
     768}
     769
    764770bool AccessibilityUIElement::isSelected() const
    765771{
     
    11821188}
    11831189
     1190bool AccessibilityUIElement::isFocusable() const
     1191{
     1192    // FIXME: implement
     1193    return false;
     1194}
     1195
    11841196bool AccessibilityUIElement::isSelectable() const
    11851197{
  • trunk/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp

    r71792 r74025  
    330330}
    331331
     332bool AccessibilityUIElement::isFocused() const
     333{
     334    // FIXME: implement
     335    return false;
     336}
     337
    332338bool AccessibilityUIElement::isSelected() const
    333339{
     
    606612}
    607613
     614bool AccessibilityUIElement::isFocusable() const
     615{
     616    // FIXME: implement
     617    return false;
     618}
     619
    608620bool AccessibilityUIElement::isSelectable() const
    609621{
Note: See TracChangeset for help on using the changeset viewer.