Changeset 67383 in webkit


Ignore:
Timestamp:
Sep 13, 2010 5:29:26 AM (14 years ago)
Author:
commit-queue@webkit.org
Message:

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

Reviewed by Martin Robinson.

[GTK] ATs should be able to select/unselect text
https://bugs.webkit.org/show_bug.cgi?id=25673

Implement AtkText's setSelection and removeSelection functions

  • accessibility/AccessibilityObject.cpp: (WebCore::AccessibilityObject::visiblePositionRangeForRange): Moved some GTK specific code from a ifdef-endif region to AccessibilityObjectAtk.cpp
  • accessibility/AccessibilityObject.h:
  • accessibility/gtk/AccessibilityObjectAtk.cpp: (WebCore::AccessibilityObject::getLengthForTextRange): New.
  • accessibility/gtk/AccessibilityObjectWrapperAtk.cpp: (webkit_accessible_text_remove_selection): Implemented following the lead of GAIL's implementation of the AtkText interface. (webkit_accessible_text_set_selection): Implemented following the lead of GAIL's implementation of the AtkText interface. (webkit_accessible_text_set_caret_offset): Changed to directly use visiblePositionRangeForRange now that there's no longer a problem with that, as it was in the past (only worked for text controls).

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

Reviewed by Martin Robinson.

[GTK] Provide unit tests for AtkText's text selection functions
https://bugs.webkit.org/show_bug.cgi?id=43919

New tests to check getting, setting and removing text selections

  • tests/testatk.c: (testWekitAtkTextSelections): New unit tests to check all the text selection related functions altogether through a single test function. (main):

Make sure that code dependant on getting information from the
clipboard gets executed only when there's a GDK window associated
to the webview widget, as that's not the case when executing the
unit tests (the wedbview is not inside of any toplevel window) and
will make the tests crash if not taken into account.

  • WebCoreSupport/EditorClientGtk.cpp: (WebKit::EditorClient::respondToChangedSelection):
Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r67376 r67383  
     12010-09-13  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [GTK] ATs should be able to select/unselect text
     6        https://bugs.webkit.org/show_bug.cgi?id=25673
     7
     8        Implement AtkText's setSelection and removeSelection functions
     9
     10        * accessibility/AccessibilityObject.cpp:
     11        (WebCore::AccessibilityObject::visiblePositionRangeForRange):
     12        Moved some GTK specific code from a ifdef-endif region to
     13        AccessibilityObjectAtk.cpp
     14        * accessibility/AccessibilityObject.h:
     15        * accessibility/gtk/AccessibilityObjectAtk.cpp:
     16        (WebCore::AccessibilityObject::getLengthForTextRange): New.
     17        * accessibility/gtk/AccessibilityObjectWrapperAtk.cpp:
     18        (webkit_accessible_text_remove_selection): Implemented following
     19        the lead of GAIL's implementation of the AtkText interface.
     20        (webkit_accessible_text_set_selection): Implemented following
     21        the lead of GAIL's implementation of the AtkText interface.
     22        (webkit_accessible_text_set_caret_offset): Changed to directly use
     23        visiblePositionRangeForRange now that there's no longer a problem
     24        with that, as it was in the past (only worked for text controls).
     25
    1262010-08-27  Kenneth Rohde Christiansen  <kenneth@webkit.org>
    227
  • trunk/WebCore/accessibility/AccessibilityObject.cpp

    r65016 r67383  
    374374VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
    375375{
    376     unsigned textLength = text().length();
    377 #if PLATFORM(GTK)
    378     // Gtk ATs need this for all text objects; not just text controls.
    379     if (!textLength) {
    380         Node* node = this->node();
    381         RenderObject* renderer = node ? node->renderer() : 0;
    382         if (renderer && renderer->isText()) {
    383             RenderText* renderText = toRenderText(renderer);
    384             textLength = renderText ? renderText->textLength() : 0;
    385         }
    386         // Get the text length from the elements under the
    387         // accessibility object if the value is still zero.
    388         if (!textLength && allowsTextRanges())
    389             textLength = textUnderElement().length();
    390     }
    391 #endif
     376    unsigned textLength = getLengthForTextRange();
    392377    if (range.start + range.length > textLength)
    393378        return VisiblePositionRange();
  • trunk/WebCore/accessibility/AccessibilityObject.h

    r65021 r67383  
    575575#if PLATFORM(GTK)
    576576    bool allowsTextRanges() const;
     577    unsigned getLengthForTextRange() const;
    577578#else
    578579    bool allowsTextRanges() const { return isTextControl(); }
     580    unsigned getLengthForTextRange() const { return text().length(); }
    579581#endif
    580582
  • trunk/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp

    r66964 r67383  
    2121#include "config.h"
    2222#include "AccessibilityObject.h"
     23#include "RenderObject.h"
     24#include "RenderText.h"
    2325
    2426#include <glib-object.h>
     
    103105}
    104106
     107unsigned AccessibilityObject::getLengthForTextRange() const
     108{
     109    unsigned textLength = text().length();
     110
     111    if (textLength)
     112        return textLength;
     113
     114    // Gtk ATs need this for all text objects; not just text controls.
     115    Node* node = this->node();
     116    RenderObject* renderer = node ? node->renderer() : 0;
     117    if (renderer && renderer->isText()) {
     118        RenderText* renderText = toRenderText(renderer);
     119        textLength = renderText ? renderText->textLength() : 0;
     120    }
     121
     122    // Get the text length from the elements under the
     123    // accessibility object if the value is still zero.
     124    if (!textLength && allowsTextRanges())
     125        textLength = textUnderElement().length();
     126
     127    return textLength;
     128}
     129
    105130} // namespace WebCore
    106131
  • trunk/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp

    r67320 r67383  
    14601460}
    14611461
    1462 static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selection_num)
    1463 {
    1464     notImplemented();
    1465     return FALSE;
    1466 }
    1467 
    1468 static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selection_num, gint start_offset, gint end_offset)
    1469 {
    1470     notImplemented();
    1471     return FALSE;
     1462static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selectionNum, gint startOffset, gint endOffset)
     1463{
     1464    // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
     1465    if (selectionNum)
     1466        return FALSE;
     1467
     1468    // Consider -1 and out-of-bound values and correct them to length
     1469    gint textCount = webkit_accessible_text_get_character_count(text);
     1470    if (startOffset < 0 || startOffset > textCount)
     1471        startOffset = textCount;
     1472    if (endOffset < 0 || endOffset > textCount)
     1473        endOffset = textCount;
     1474
     1475    AccessibilityObject* coreObject = core(text);
     1476    PlainTextRange textRange(startOffset, endOffset - startOffset);
     1477    VisiblePositionRange range = coreObject->visiblePositionRangeForRange(textRange);
     1478    coreObject->setSelectedVisiblePositionRange(range);
     1479
     1480    return TRUE;
     1481}
     1482
     1483static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selectionNum)
     1484{
     1485    // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
     1486    if (selectionNum)
     1487        return FALSE;
     1488
     1489    // Do nothing if current selection doesn't belong to the object
     1490    if (!webkit_accessible_text_get_n_selections(text))
     1491        return FALSE;
     1492
     1493    // Set a new 0-sized selection to the caret position, in order
     1494    // to simulate selection removal (GAIL style)
     1495    gint caretOffset = webkit_accessible_text_get_caret_offset(text);
     1496    return webkit_accessible_text_set_selection(text, selectionNum, caretOffset, caretOffset);
    14721497}
    14731498
     
    14761501    AccessibilityObject* coreObject = core(text);
    14771502
    1478     // FIXME: We need to reimplement visiblePositionRangeForRange here
    1479     // because the actual function checks the offset is within the
    1480     // boundaries of text().length(), but text() only works for text
    1481     // controls...
    1482     VisiblePosition startPosition = coreObject->visiblePositionForIndex(offset);
    1483     startPosition.setAffinity(DOWNSTREAM);
    1484     VisiblePosition endPosition = coreObject->visiblePositionForIndex(offset);
    1485     VisiblePositionRange range = VisiblePositionRange(startPosition, endPosition);
    1486 
     1503    PlainTextRange textRange(offset, 0);
     1504    VisiblePositionRange range = coreObject->visiblePositionRangeForRange(textRange);
    14871505    coreObject->setSelectedVisiblePositionRange(range);
     1506
    14881507    return TRUE;
    14891508}
  • trunk/WebKit/gtk/ChangeLog

    r67300 r67383  
     12010-09-13  Mario Sanchez Prada  <msanchez@igalia.com>
     2
     3        Reviewed by Martin Robinson.
     4
     5        [GTK] Provide unit tests for AtkText's text selection functions
     6        https://bugs.webkit.org/show_bug.cgi?id=43919
     7
     8        New tests to check getting, setting and removing text selections
     9
     10        * tests/testatk.c:
     11        (testWekitAtkTextSelections): New unit tests to check all the text
     12        selection related functions altogether through a single test
     13        function.
     14        (main):
     15
     16        Make sure that code dependant on getting information from the
     17        clipboard gets executed only when there's a GDK window associated
     18        to the webview widget, as that's not the case when executing the
     19        unit tests (the wedbview is not inside of any toplevel window) and
     20        will make the tests crash if not taken into account.
     21
     22        * WebCoreSupport/EditorClientGtk.cpp:
     23        (WebKit::EditorClient::respondToChangedSelection):
     24
    1252010-09-11  Xan Lopez  <xlopez@igalia.com>
    226
  • trunk/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp

    r65209 r67383  
    342342}
    343343
     344#if PLATFORM(X11)
     345static void setSelectionPrimaryClipboardIfNeeded(WebKitWebView* webView)
     346{
     347    if (!gtk_widget_has_screen(GTK_WIDGET(webView)))
     348        return;
     349
     350    GtkClipboard* clipboard = gtk_widget_get_clipboard(GTK_WIDGET(webView), GDK_SELECTION_PRIMARY);
     351    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
     352    WebCore::Page* corePage = core(webView);
     353    Frame* targetFrame = corePage->focusController()->focusedOrMainFrame();
     354
     355    if (!targetFrame->selection()->isRange())
     356        return;
     357
     358    dataObject->clear();
     359    dataObject->setRange(targetFrame->selection()->toNormalizedRange());
     360
     361    viewSettingClipboard = webView;
     362    GClosure* callback = g_cclosure_new_object(G_CALLBACK(collapseSelection), G_OBJECT(webView));
     363    g_closure_set_marshal(callback, g_cclosure_marshal_VOID__VOID);
     364    pasteboardHelperInstance()->writeClipboardContents(clipboard, callback);
     365    viewSettingClipboard = 0;
     366}
     367#endif
     368
    344369void EditorClient::respondToChangedSelection()
    345370{
     
    355380
    356381#if PLATFORM(X11)
    357     GtkClipboard* clipboard = gtk_widget_get_clipboard(GTK_WIDGET(m_webView), GDK_SELECTION_PRIMARY);
    358     DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
    359 
    360     if (targetFrame->selection()->isRange()) {
    361         dataObject->clear();
    362         dataObject->setRange(targetFrame->selection()->toNormalizedRange());
    363 
    364         viewSettingClipboard = m_webView;
    365         GClosure* callback = g_cclosure_new_object(G_CALLBACK(collapseSelection), G_OBJECT(m_webView));
    366         g_closure_set_marshal(callback, g_cclosure_marshal_VOID__VOID);
    367         pasteboardHelperInstance()->writeClipboardContents(clipboard, callback);
    368         viewSettingClipboard = 0;
    369     }
     382    setSelectionPrimaryClipboardIfNeeded(m_webView);
    370383#endif
    371384
  • trunk/WebKit/gtk/tests/testatk.c

    r67270 r67383  
    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* 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>";
     48
     49static const char* textForSelections = "<html><body><p>A paragraph with plain text</p><p>A paragraph with <a href='http://webkit.org'>a link</a> in the middle</p></body></html>";
     50
    4751static const char* textWithAttributes = "<html><head><style>.st1 {font-family: monospace; color:rgb(120,121,122);} .st2 {text-decoration:underline; background-color:rgb(80,81,82);}</style></head><body><p style=\"font-size:14; text-align:right;\">This is the <i>first</i><b> sentence of this text.</b></p><p class=\"st1\">This sentence should have an style applied <span class=\"st2\">and this part should have another one</span>.</p><p>x<sub>1</sub><sup>2</sup>=x<sub>2</sub><sup>3</sup></p><p style=\"text-align:center;\">This sentence is the <strike>last</strike> one.</p></body></html>";
    48 
    49 static 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>";
    5052
    5153static gboolean bail_out(GMainLoop* loop)
     
    741743    atk_attribute_set_free(set2);
    742744    atk_attribute_set_free(set3);
     745}
     746
     747static void testWekitAtkTextSelections(void)
     748{
     749    WebKitWebView* webView;
     750    AtkObject* obj;
     751    GMainLoop* loop;
     752    gchar* selectedText;
     753    gint startOffset;
     754    gint endOffset;
     755    gboolean result;
     756
     757    webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     758    g_object_ref_sink(webView);
     759    GtkAllocation alloc = { 0, 0, 800, 600 };
     760    gtk_widget_size_allocate(GTK_WIDGET(webView), &alloc);
     761    webkit_web_view_load_string(webView, textForSelections, NULL, NULL, NULL);
     762    loop = g_main_loop_new(NULL, TRUE);
     763
     764    g_timeout_add(100, (GSourceFunc)bail_out, loop);
     765    g_main_loop_run(loop);
     766
     767    obj = gtk_widget_get_accessible(GTK_WIDGET(webView));
     768    g_assert(obj);
     769
     770    AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(obj, 0));
     771    g_assert(ATK_IS_TEXT(paragraph1));
     772    AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(obj, 1));
     773    g_assert(ATK_IS_TEXT(paragraph2));
     774    AtkText* link = ATK_TEXT(atk_object_ref_accessible_child(ATK_OBJECT(paragraph2), 0));
     775    g_assert(ATK_IS_TEXT(link));
     776
     777    // First paragraph (simple text)
     778
     779    // Basic initial checks
     780    g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0);
     781    selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
     782    g_assert_cmpint(startOffset, ==, 0);
     783    g_assert_cmpint(endOffset, ==, 0);
     784    g_assert_cmpstr(selectedText, ==, NULL);
     785    g_free (selectedText);
     786    // Try removing a non existing (yet) selection
     787    result = atk_text_remove_selection(paragraph1, 0);
     788    g_assert(!result);
     789    // Try setting a 0-char selection
     790    result = atk_text_set_selection(paragraph1, 0, 5, 5);
     791    g_assert(result);
     792
     793    // Make a selection and test it
     794    result = atk_text_set_selection(paragraph1, 0, 5, 25);
     795    g_assert(result);
     796    g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 1);
     797    selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
     798    g_assert_cmpint(startOffset, ==, 5);
     799    g_assert_cmpint(endOffset, ==, 25);
     800    g_assert_cmpstr(selectedText, ==, "agraph with plain te");
     801    g_free (selectedText);
     802    // Try removing the selection from other AtkText object (should fail)
     803    result = atk_text_remove_selection(paragraph2, 0);
     804    g_assert(!result);
     805
     806    // Remove the selection and test everything again
     807    result = atk_text_remove_selection(paragraph1, 0);
     808    g_assert(result);
     809    g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0);
     810    selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset);
     811    // Now offsets should be the same, set to the last position of the caret
     812    g_assert_cmpint(startOffset, ==, endOffset);
     813    g_assert_cmpint(startOffset, ==, 25);
     814    g_assert_cmpint(endOffset, ==, 25);
     815    g_assert_cmpstr(selectedText, ==, NULL);
     816    g_free (selectedText);
     817
     818    // Second paragraph (text + link + text)
     819
     820    // Set a selection partially covering the link and test it
     821    result = atk_text_set_selection(paragraph2, 0, 7, 21);
     822    g_assert(result);
     823
     824    // Test the paragraph first
     825    g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 1);
     826    selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset);
     827    g_assert_cmpint(startOffset, ==, 7);
     828    g_assert_cmpint(endOffset, ==, 21);
     829    g_assert_cmpstr(selectedText, ==, "raph with a li");
     830    g_free (selectedText);
     831
     832    // Now test just the link
     833    g_assert_cmpint(atk_text_get_n_selections(link), ==, 1);
     834    selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset);
     835    g_assert_cmpint(startOffset, ==, 0);
     836    g_assert_cmpint(endOffset, ==, 4);
     837    g_assert_cmpstr(selectedText, ==, "a li");
     838    g_free (selectedText);
     839
     840    // Remove selections and text everything again
     841    result = atk_text_remove_selection(paragraph2, 0);
     842    g_assert(result);
     843    g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 0);
     844    selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset);
     845    // Now offsets should be the same (no selection)
     846    g_assert_cmpint(startOffset, ==, endOffset);
     847    g_assert_cmpstr(selectedText, ==, NULL);
     848    g_free (selectedText);
     849
     850    g_assert_cmpint(atk_text_get_n_selections(link), ==, 0);
     851    selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset);
     852    // Now offsets should be the same (no selection)
     853    g_assert_cmpint(startOffset, ==, endOffset);
     854    g_assert_cmpstr(selectedText, ==, NULL);
     855    g_free (selectedText);
     856
     857    g_object_unref(paragraph1);
     858    g_object_unref(paragraph2);
     859    g_object_unref(webView);
    743860}
    744861
     
    9371054    g_test_add_func("/webkit/atk/getHeadersInTable", testWebkitAtkGetHeadersInTable);
    9381055    g_test_add_func("/webkit/atk/textAttributes", testWebkitAtkTextAttributes);
     1056    g_test_add_func("/webkit/atk/textSelections", testWekitAtkTextSelections);
    9391057    g_test_add_func("/webkit/atk/get_extents", test_webkit_atk_get_extents);
    9401058    g_test_add_func("/webkit/atk/listsOfItems", testWebkitAtkListsOfItems);
Note: See TracChangeset for help on using the changeset viewer.