Changeset 68078 in webkit


Ignore:
Timestamp:
Sep 22, 2010 1:43:26 PM (14 years ago)
Author:
commit-queue@webkit.org
Message:

2010-09-22 Mario Sanchez Prada <msanchez@igalia.com>

Reviewed by Martin Robinson.

[Gtk] object:text-changed events should be emitted for entries and password text
https://bugs.webkit.org/show_bug.cgi?id=25898

Implement proper 'text-changed' signal emission for the GTK port

Call deleteTextFromNode() when needed while removing text nodes.
Do it even when removeNode() is going to be called afterwards, in
order to allow accessibility to get properly notified about the
text being removed alongside with that node.

  • editing/DeleteSelectionCommand.cpp: (WebCore::DeleteSelectionCommand::handleGeneralDelete):

New function in AXObjectCache to call when text changes in a node.
Added one new function to allow notifying something changed in a
text node through the associated RenderObject, making such a
function dependant on the platform-specific implementation,
provided through a protected function (provided a proper
implementation for the GTK port and a dummy one for the others).

  • accessibility/AXObjectCache.cpp: (WebCore::AXObjectCache::nodeTextChangeNotification): New
  • accessibility/AXObjectCache.h: (WebCore::AXObjectCache::AXTextChange): New enumeration (WebCore::AXObjectCache::nodeTextChangeNotification): New (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
  • accessibility/AccessibilityRenderObject.h: (WebCore::toAccessibilityRenderObject):
  • accessibility/chromium/AXObjectCacheChromium.cpp: (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
  • accessibility/gtk/AXObjectCacheAtk.cpp: (WebCore::emitTextChanged): (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
  • accessibility/mac/AXObjectCacheMac.mm: (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
  • accessibility/win/AXObjectCacheWin.cpp: (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New

Notify accessibility when something changes in a text node.
Call to AXObjectCache::nodeTextChangeNotification() to notify when
text was inserted/deleted when applying/unapplying a text edition
command, along with the offset in the original text where the
change took place and the number of characters that got affected.

  • editing/AppendNodeCommand.cpp: (WebCore::sendAXTextChangedIgnoringLineBreaks): (WebCore::AppendNodeCommand::doApply): (WebCore::AppendNodeCommand::doUnapply):
  • editing/DeleteFromTextNodeCommand.cpp: (WebCore::DeleteFromTextNodeCommand::doApply): (WebCore::DeleteFromTextNodeCommand::doUnapply):
  • editing/InsertIntoTextNodeCommand.cpp: (WebCore::InsertIntoTextNodeCommand::doApply): (WebCore::InsertIntoTextNodeCommand::doUnapply):
  • editing/InsertNodeBeforeCommand.cpp: (WebCore::InsertNodeBeforeCommand::doApply): (WebCore::InsertNodeBeforeCommand::doUnapply): (WebCore::DeleteSelectionCommand::handleGeneralDelete):

2010-09-22 Mario Sanchez Prada <msanchez@igalia.com>

Reviewed by Martin Robinson.

[Gtk] object:text-changed events should be emitted for entries and password text
https://bugs.webkit.org/show_bug.cgi?id=25898

New unit test to make sure text-changed signals are emitted

  • tests/testatk.c: (textChangedCb): New. Signal handler for the text-changed::insert and text-changed::delete signals. (checkTextChangesAndBailOut): New. Source function to check the global result of the test and quit from the main loop. (testWebkitAtkTextChangedNotifications): New test. (main):
Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r68077 r68078  
     12010-09-22 Mario Sanchez Prada <msanchez@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [Gtk] object:text-changed events should be emitted for entries and password text
     6        https://bugs.webkit.org/show_bug.cgi?id=25898
     7
     8        Implement proper 'text-changed' signal emission for the GTK port
     9
     10        Call deleteTextFromNode() when needed while removing text nodes.
     11        Do it even when removeNode() is going to be called afterwards, in
     12        order to allow accessibility to get properly notified about the
     13        text being removed alongside with that node.
     14
     15        * editing/DeleteSelectionCommand.cpp:
     16        (WebCore::DeleteSelectionCommand::handleGeneralDelete):
     17
     18        New function in AXObjectCache to call when text changes in a node.
     19        Added one new function to allow notifying something changed in a
     20        text node through the associated RenderObject, making such a
     21        function dependant on the platform-specific implementation,
     22        provided through a protected function (provided a proper
     23        implementation for the GTK port and a dummy one for the others).
     24
     25        * accessibility/AXObjectCache.cpp:
     26        (WebCore::AXObjectCache::nodeTextChangeNotification): New
     27        * accessibility/AXObjectCache.h:
     28        (WebCore::AXObjectCache::AXTextChange): New enumeration
     29        (WebCore::AXObjectCache::nodeTextChangeNotification): New
     30        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
     31        * accessibility/AccessibilityRenderObject.h:
     32        (WebCore::toAccessibilityRenderObject):
     33        * accessibility/chromium/AXObjectCacheChromium.cpp:
     34        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
     35        * accessibility/gtk/AXObjectCacheAtk.cpp:
     36        (WebCore::emitTextChanged):
     37        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
     38        * accessibility/mac/AXObjectCacheMac.mm:
     39        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
     40        * accessibility/win/AXObjectCacheWin.cpp:
     41        (WebCore::AXObjectCache::nodeTextChangePlatformNotification): New
     42
     43        Notify accessibility when something changes in a text node.
     44        Call to AXObjectCache::nodeTextChangeNotification() to notify when
     45        text was inserted/deleted when applying/unapplying a text edition
     46        command, along with the offset in the original text where the
     47        change took place and the number of characters that got affected.
     48
     49        * editing/AppendNodeCommand.cpp:
     50        (WebCore::sendAXTextChangedIgnoringLineBreaks):
     51        (WebCore::AppendNodeCommand::doApply):
     52        (WebCore::AppendNodeCommand::doUnapply):
     53        * editing/DeleteFromTextNodeCommand.cpp:
     54        (WebCore::DeleteFromTextNodeCommand::doApply):
     55        (WebCore::DeleteFromTextNodeCommand::doUnapply):
     56        * editing/InsertIntoTextNodeCommand.cpp:
     57        (WebCore::InsertIntoTextNodeCommand::doApply):
     58        (WebCore::InsertIntoTextNodeCommand::doUnapply):
     59        * editing/InsertNodeBeforeCommand.cpp:
     60        (WebCore::InsertNodeBeforeCommand::doApply):
     61        (WebCore::InsertNodeBeforeCommand::doUnapply):
     62        (WebCore::DeleteSelectionCommand::handleGeneralDelete):
     63
    1642010-09-22  David Hyatt  <hyatt@apple.com>
    265
  • trunk/WebCore/accessibility/AXObjectCache.cpp

    r64874 r68078  
    466466    postNotification(renderer, AXSelectedChildrenChanged, false);
    467467}
     468
     469void AXObjectCache::nodeTextChangeNotification(RenderObject* renderer, AXTextChange textChange, unsigned offset, unsigned count)
     470{
     471    if (!renderer)
     472        return;
     473
     474    // Delegate on the right platform
     475    AccessibilityObject* obj = getOrCreate(renderer);
     476    nodeTextChangePlatformNotification(obj, textChange, offset, count);
     477}
    468478#endif
    469479
  • trunk/WebCore/accessibility/AXObjectCache.h

    r66305 r68078  
    126126    void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously);
    127127
     128    enum AXTextChange {
     129        AXTextInserted,
     130        AXTextDeleted,
     131    };
     132
     133    void nodeTextChangeNotification(RenderObject*, AXTextChange, unsigned offset, unsigned count);
     134
     135    bool nodeHasRole(Node*, const AtomicString& role);
     136
    128137protected:
    129138    void postPlatformNotification(AccessibilityObject*, AXNotification);
     139    void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, unsigned count);
    130140
    131141private:
     
    157167inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType) { }
    158168inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
     169inline void AXObjectCache::nodeTextChangeNotification(RenderObject*, AXTextChange, unsigned, unsigned) { }
     170inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, unsigned) { }
    159171inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { }
    160172inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
  • trunk/WebCore/accessibility/AccessibilityRenderObject.h

    r65021 r68078  
    312312    mutable AccessibilityRole m_roleForMSAA;
    313313};
    314    
     314
     315inline AccessibilityRenderObject* toAccessibilityRenderObject(AccessibilityObject* object)
     316{
     317    ASSERT(!object || object->isAccessibilityRenderObject());
     318    return static_cast<AccessibilityRenderObject*>(object);
     319}
     320
     321inline const AccessibilityRenderObject* toAccessibilityRenderObject(const AccessibilityObject* object)
     322{
     323    ASSERT(!object || object->isAccessibilityRenderObject());
     324    return static_cast<const AccessibilityRenderObject*>(object);
     325}
     326
     327// This will catch anyone doing an unnecessary cast.
     328void toAccessibilityRenderObject(const AccessibilityRenderObject*);
     329
    315330} // namespace WebCore
    316331
  • trunk/WebCore/accessibility/chromium/AXObjectCacheChromium.cpp

    r68031 r68078  
    8282}
    8383
     84void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, unsigned)
     85{
     86}
     87
    8488void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*)
    8589{
  • trunk/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp

    r50282 r68078  
    2323#include "AccessibilityObject.h"
    2424#include "AccessibilityObjectWrapperAtk.h"
     25#include "AccessibilityRenderObject.h"
     26#include "GOwnPtr.h"
     27#include "Range.h"
     28#include "TextIterator.h"
    2529
    2630namespace WebCore {
     
    5155}
    5256
     57static void emitTextChanged(AccessibilityRenderObject* object, AXObjectCache::AXTextChange textChange, unsigned offset, unsigned count)
     58{
     59    // Get the axObject for the parent object
     60    AtkObject* wrapper = object->parentObjectUnignored()->wrapper();
     61    if (!wrapper || !ATK_IS_TEXT(wrapper))
     62        return;
     63
     64    // Select the right signal to be emitted
     65    CString detail;
     66    switch (textChange) {
     67    case AXObjectCache::AXTextInserted:
     68        detail = "text-changed::insert";
     69        break;
     70    case AXObjectCache::AXTextDeleted:
     71        detail = "text-changed::delete";
     72        break;
     73    }
     74
     75    if (!detail.isNull())
     76        g_signal_emit_by_name(wrapper, detail.data(), offset, count);
     77}
     78
     79void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, unsigned count)
     80{
     81    // Sanity check
     82    if (count < 1 || !object || !object->isAccessibilityRenderObject())
     83        return;
     84
     85    Node* node = object->node();
     86    RefPtr<Range> range = Range::create(node->document(),  Position(node->parentNode(), 0), Position(node, 0));
     87    emitTextChanged(toAccessibilityRenderObject(object), textChange, offset + TextIterator::rangeLength(range.get()), count);
     88}
     89
    5390void AXObjectCache::handleFocusedUIElementChanged(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
    5491{
  • trunk/WebCore/accessibility/mac/AXObjectCacheMac.mm

    r64517 r68078  
    115115}
    116116
     117void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, unsigned)
     118{
     119}
     120
    117121void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*)
    118122{
  • trunk/WebCore/accessibility/win/AXObjectCacheWin.cpp

    r54078 r68078  
    104104}
    105105
     106void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, unsigned)
     107{
     108}
     109
    106110AXID AXObjectCache::platformGenerateAXID() const
    107111{
  • trunk/WebCore/editing/AppendNodeCommand.cpp

    r51645 r68078  
    2727#include "AppendNodeCommand.h"
    2828
     29#include "AXObjectCache.h"
    2930#include "htmlediting.h"
    3031
     
    4344}
    4445
     46static void sendAXTextChangedIgnoringLineBreaks(Node* node, AXObjectCache::AXTextChange textChange)
     47{
     48    String nodeValue = node->nodeValue();
     49    unsigned len = nodeValue.length();
     50    // Don't consider linebreaks in this command
     51    if (nodeValue == "\n")
     52      return;
     53
     54    node->document()->axObjectCache()->nodeTextChangeNotification(node->renderer(), textChange, 0, len);
     55}
     56
    4557void AppendNodeCommand::doApply()
    4658{
     
    5062    ExceptionCode ec;
    5163    m_parent->appendChild(m_node.get(), ec);
     64
     65    if (AXObjectCache::accessibilityEnabled())
     66        sendAXTextChangedIgnoringLineBreaks(m_node.get(), AXObjectCache::AXTextInserted);
    5267}
    5368
     
    5772        return;
    5873       
     74    // Need to notify this before actually deleting the text
     75    if (AXObjectCache::accessibilityEnabled())
     76        sendAXTextChangedIgnoringLineBreaks(m_node.get(), AXObjectCache::AXTextDeleted);
     77
    5978    ExceptionCode ec;
    6079    m_node->remove(ec);
  • trunk/WebCore/editing/DeleteFromTextNodeCommand.cpp

    r51645 r68078  
    2727#include "DeleteFromTextNodeCommand.h"
    2828
     29#include "AXObjectCache.h"
    2930#include "Text.h"
    3031
     
    5455        return;
    5556   
     57    // Need to notify this before actually deleting the text
     58    if (AXObjectCache::accessibilityEnabled())
     59        document()->axObjectCache()->nodeTextChangeNotification(m_node->renderer(), AXObjectCache::AXTextDeleted, m_offset, m_count);
     60
    5661    m_node->deleteData(m_offset, m_count, ec);
    5762}
     
    6671    ExceptionCode ec;
    6772    m_node->insertData(m_offset, m_text, ec);
     73
     74    if (AXObjectCache::accessibilityEnabled())
     75        document()->axObjectCache()->nodeTextChangeNotification(m_node->renderer(), AXObjectCache::AXTextInserted, m_offset, m_count);
    6876}
    6977
  • trunk/WebCore/editing/DeleteSelectionCommand.cpp

    r67238 r68078  
    444444
    445445    if (startNode == m_downstreamEnd.node()) {
    446         // The selection to delete is all in one node.
    447         if (!startNode->renderer() || (startOffset == 0 && m_downstreamEnd.atLastEditingPositionForNode())) {
    448             // just delete
    449             removeNode(startNode);
    450         } else if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) {
     446        if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) {
    451447            if (startNode->isTextNode()) {
    452448                // in a text node that needs to be trimmed
     
    458454            }
    459455        }
     456
     457        // The selection to delete is all in one node.
     458        if (!startNode->renderer() || (!startOffset && m_downstreamEnd.atLastEditingPositionForNode()))
     459            removeNode(startNode);
    460460    }
    461461    else {
     
    473473                node = startNode->childNode(startOffset);
    474474            }
     475        } else if (startNode == m_upstreamEnd.node() && startNode->isTextNode()) {
     476            Text* text = static_cast<Text*>(m_upstreamEnd.node());
     477            deleteTextFromNode(text, 0, m_upstreamEnd.deprecatedEditingOffset());
    475478        }
    476479       
  • trunk/WebCore/editing/InsertIntoTextNodeCommand.cpp

    r51645 r68078  
    2727#include "InsertIntoTextNodeCommand.h"
    2828
     29#include "AXObjectCache.h"
    2930#include "Text.h"
    3031
     
    4950    ExceptionCode ec;
    5051    m_node->insertData(m_offset, m_text, ec);
     52
     53    if (AXObjectCache::accessibilityEnabled())
     54        document()->axObjectCache()->nodeTextChangeNotification(m_node->renderer(), AXObjectCache::AXTextInserted, m_offset, m_text.length());
    5155}
    5256
     
    5660        return;
    5761       
     62    // Need to notify this before actually deleting the text
     63    if (AXObjectCache::accessibilityEnabled())
     64        document()->axObjectCache()->nodeTextChangeNotification(m_node->renderer(), AXObjectCache::AXTextDeleted, m_offset, m_text.length());
     65
    5866    ExceptionCode ec;
    5967    m_node->deleteData(m_offset, m_text.length(), ec);
  • trunk/WebCore/editing/InsertNodeBeforeCommand.cpp

    r51645 r68078  
    2727#include "InsertNodeBeforeCommand.h"
    2828
     29#include "AXObjectCache.h"
    2930#include "htmlediting.h"
    3031
     
    5253    ExceptionCode ec;
    5354    parent->insertBefore(m_insertChild.get(), m_refChild.get(), ec);
     55
     56    if (AXObjectCache::accessibilityEnabled())
     57        document()->axObjectCache()->nodeTextChangeNotification(m_insertChild->renderer(), AXObjectCache::AXTextInserted, 0, m_insertChild->nodeValue().length());
    5458}
    5559
     
    5963        return;
    6064       
     65    // Need to notify this before actually deleting the text
     66    if (AXObjectCache::accessibilityEnabled())
     67        document()->axObjectCache()->nodeTextChangeNotification(m_insertChild->renderer(), AXObjectCache::AXTextDeleted, 0, m_insertChild->nodeValue().length());
     68
    6169    ExceptionCode ec;
    6270    m_insertChild->remove(ec);
  • trunk/WebKit/gtk/ChangeLog

    r68043 r68078  
     12010-09-22  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [Gtk] object:text-changed events should be emitted for entries and password text
     6        https://bugs.webkit.org/show_bug.cgi?id=25898
     7
     8        New unit test to make sure text-changed signals are emitted
     9
     10        * tests/testatk.c:
     11        (textChangedCb): New. Signal handler for the
     12        text-changed::insert and text-changed::delete signals.
     13        (checkTextChangesAndBailOut): New. Source function to check
     14        the global result of the test and quit from the main loop.
     15        (testWebkitAtkTextChangedNotifications): New test.
     16        (main):
     17
    1182010-09-22  Martin Robinson  <mrobinson@igalia.com>
    219
  • trunk/WebKit/gtk/tests/testatk.c

    r67383 r68078  
    4545static const char* contentsInTableWithHeaders = "<html><body><table><tr><th>foo</th><th>bar</th><th colspan='2'>baz</th></tr><tr><th>qux</th><td>1</td><td>2</td><td>3</td></tr><tr><th rowspan='2'>quux</th><td>4</td><td>5</td><td>6</td></tr><tr><td>6</td><td>7</td><td>8</td></tr><tr><th>corge</th><td>9</td><td>10</td><td>11</td></tr></table><table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table></body></html>";
    4646
     47static const char* formWithTextInputs = "<html><body><form><input type='text' name='entry' /></form></body></html>";
     48
    4749static const char* listsOfItems = "<html><body><ul><li>text only</li><li><a href='foo'>link only</a></li><li>text and a <a href='bar'>link</a></li></ul><ol><li>text only</li><li><a href='foo'>link only</a></li><li>text and a <a href='bar'>link</a></li></ol></body></html>";
    4850
     
    10351037    g_object_unref(uList);
    10361038    g_object_unref(oList);
     1039    g_object_unref(webView);
     1040}
     1041
     1042static gboolean textInserted = FALSE;
     1043static gboolean textDeleted = FALSE;
     1044
     1045static void textChangedCb(AtkText* text, gint pos, gint len, const gchar* detail)
     1046{
     1047    g_assert(text && ATK_IS_OBJECT(text));
     1048
     1049    if (!g_strcmp0(detail, "insert"))
     1050        textInserted = TRUE;
     1051    else if (!g_strcmp0(detail, "delete"))
     1052        textDeleted = TRUE;
     1053}
     1054
     1055static gboolean checkTextChanges(gpointer unused)
     1056{
     1057    g_assert_cmpint(textInserted, ==, TRUE);
     1058    g_assert_cmpint(textDeleted, ==, TRUE);
     1059    return FALSE;
     1060}
     1061
     1062static void testWebkitAtkTextChangedNotifications(void)
     1063{
     1064    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     1065    g_object_ref_sink(webView);
     1066    GtkAllocation alloc = { 0, 0, 800, 600 };
     1067    gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc);
     1068    webkit_web_view_load_string(webView, formWithTextInputs, 0, 0, 0);
     1069
     1070    // Manually spin the main context to get the accessible objects
     1071    while (g_main_context_pending(0))
     1072        g_main_context_iteration(0, TRUE);
     1073
     1074    AtkObject* obj = gtk_widget_get_accessible(GTK_WIDGET(webView));
     1075    g_assert(obj);
     1076
     1077    AtkObject* form = atk_object_ref_accessible_child(obj, 0);
     1078    g_assert(ATK_IS_OBJECT(form));
     1079
     1080    AtkObject* textEntry = atk_object_ref_accessible_child(form, 0);
     1081    g_assert(ATK_IS_EDITABLE_TEXT(textEntry));
     1082    g_assert(atk_object_get_role(ATK_OBJECT(textEntry)) == ATK_ROLE_ENTRY);
     1083
     1084    g_signal_connect(textEntry, "text-changed::insert",
     1085                     G_CALLBACK(textChangedCb),
     1086                     (gpointer)"insert");
     1087    g_signal_connect(textEntry, "text-changed::delete",
     1088                     G_CALLBACK(textChangedCb),
     1089                     (gpointer)"delete");
     1090
     1091    gint pos = 0;
     1092    atk_editable_text_insert_text(ATK_EDITABLE_TEXT(textEntry), "foo bar baz", 11, &pos);
     1093    atk_editable_text_delete_text(ATK_EDITABLE_TEXT(textEntry), 4, 7);
     1094    textInserted = FALSE;
     1095    textDeleted = FALSE;
     1096
     1097    g_idle_add((GSourceFunc)checkTextChanges, 0);
     1098
     1099    g_object_unref(form);
     1100    g_object_unref(textEntry);
    10371101    g_object_unref(webView);
    10381102}
     
    10571121    g_test_add_func("/webkit/atk/get_extents", test_webkit_atk_get_extents);
    10581122    g_test_add_func("/webkit/atk/listsOfItems", testWebkitAtkListsOfItems);
     1123    g_test_add_func("/webkit/atk/textChangedNotifications", testWebkitAtkTextChangedNotifications);
    10591124    return g_test_run ();
    10601125}
Note: See TracChangeset for help on using the changeset viewer.