[ATK] Implement new API in AtkText: atk_text_get_string_at_offset()
authormario@webkit.org <mario@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 Oct 2013 14:16:34 +0000 (14:16 +0000)
committermario@webkit.org <mario@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 Oct 2013 14:16:34 +0000 (14:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=120638

Reviewed by Gustavo Noronha Silva.

Source/WebCore:

Implemented new atk_text_get_string_at_offset() API, introduced in
ATK 2.9.4 to simplify how text at a given offset is retrieved.

* accessibility/atk/WebKitAccessibleInterfaceText.cpp:
(webkitAccessibleTextGetStringAtOffset): New function implementing
the new API, which basically translates calls to the new API to
calls to the old API using 'at' positions and START boundaries.
(webkitAccessibleTextInterfaceInit): Hook the new function.

Source/WebKit/gtk:

Update ATK unit test to check the new API as well if the version
of ATK is new enough.

* tests/testatk.c:
(testGetStringFunction): New helper function, to check the new API.
(runGetStringTests): Ditto.
(testWebkitAtkGetStringAtOffset): New unit test, similar to the
one already present to check the old API but focused in the new one.
(testWebkitAtkGetStringAtOffsetNewlines): Ditto.
(testWebkitAtkGetStringAtOffsetTextarea): Ditto.
(testWebkitAtkGetStringAtOffsetTextInput): Ditto.
(testWebkitAtkGetStringAtOffsetWithPreformattedText): Ditto.
(testWebkitAtkGetStringAtOffsetWithSpecialCharacters): Ditto.
(testWebkitAtkGetStringAtOffsetWithWrappedLines): Ditto.
(testWebkitAtkGetStringAtOffsetWithEmbeddedObjects): Ditto.
(testWebkitAtkGetExtents): Add checks for the new API, if possible.
(testWebkitAtkLinksWithInlineImages): Ditto.
(main): Add the new unit tests to check the new API, if possible.

Tools:

* gtk/jhbuild.modules: Raised ATK and AT-SPI versions to 2.10.0, so we
can check both the old and new APIs to retrieve text at a given offset.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@157165 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/tests/testatk.c
Tools/ChangeLog
Tools/gtk/jhbuild.modules
Tools/gtk/patches/at-spi2-atk-2.8.0-null-check-after-cleanup.patch [deleted file]

index a65cc66..899d175 100644 (file)
@@ -1,3 +1,19 @@
+2013-10-09  Mario Sanchez Prada  <mario.prada@samsung.com>
+
+        [ATK] Implement new API in AtkText: atk_text_get_string_at_offset()
+        https://bugs.webkit.org/show_bug.cgi?id=120638
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Implemented new atk_text_get_string_at_offset() API, introduced in
+        ATK 2.9.4 to simplify how text at a given offset is retrieved.
+
+        * accessibility/atk/WebKitAccessibleInterfaceText.cpp:
+        (webkitAccessibleTextGetStringAtOffset): New function implementing
+        the new API, which basically translates calls to the new API to
+        calls to the old API using 'at' positions and START boundaries.
+        (webkitAccessibleTextInterfaceInit): Hook the new function.
+
 2013-10-09  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] mouse wheel events are not considered to be mouse events
index 72c5cdb..6c854c9 100644 (file)
@@ -1368,6 +1368,48 @@ static gboolean webkitAccessibleTextSetCaretOffset(AtkText* text, gint offset)
     return TRUE;
 }
 
+#if ATK_CHECK_VERSION(2, 10, 0)
+static gchar* webkitAccessibleTextGetStringAtOffset(AtkText* text, gint offset, AtkTextGranularity granularity, gint* startOffset, gint* endOffset)
+{
+    // This new API has been designed to simplify the AtkText interface and it has been
+    // designed to keep exactly the same behaviour the atk_text_get_text_at_text() for
+    // ATK_TEXT_BOUNDARY_*_START boundaries, so for now we just need to translate the
+    // granularity to the right old boundary and reuse the code for the old API.
+    // However, this should be simplified later on (and a lot of code removed) once
+    // WebKitGTK+ depends on ATK >= 2.9.4 *and* can safely assume that a version of
+    // AT-SPI2 new enough not to include the old APIs is being used. But until then,
+    // we will have to live with both the old and new APIs implemented here.
+    AtkTextBoundary boundaryType = ATK_TEXT_BOUNDARY_CHAR;
+    switch (granularity) {
+    case ATK_TEXT_GRANULARITY_CHAR:
+        break;
+
+    case ATK_TEXT_GRANULARITY_WORD:
+        boundaryType = ATK_TEXT_BOUNDARY_WORD_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_SENTENCE:
+        boundaryType = ATK_TEXT_BOUNDARY_SENTENCE_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_LINE:
+        boundaryType = ATK_TEXT_BOUNDARY_LINE_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_PARAGRAPH:
+        // FIXME: This has not been a need with the old AtkText API, which means ATs won't
+        // need it yet for some time, so we can skip it for now.
+        notImplemented();
+        return g_strdup("");
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    return webkitAccessibleTextGetTextForOffset(text, offset, boundaryType, GetTextPositionAt, startOffset, endOffset);
+}
+#endif
+
 void webkitAccessibleTextInterfaceInit(AtkTextIface* iface)
 {
     iface->get_text = webkitAccessibleTextGetText;
@@ -1388,6 +1430,10 @@ void webkitAccessibleTextInterfaceInit(AtkTextIface* iface)
     iface->remove_selection = webkitAccessibleTextRemoveSelection;
     iface->set_selection = webkitAccessibleTextSetSelection;
     iface->set_caret_offset = webkitAccessibleTextSetCaretOffset;
+
+#if ATK_CHECK_VERSION(2, 10, 0)
+    iface->get_string_at_offset = webkitAccessibleTextGetStringAtOffset;
+#endif
 }
 
 #endif
index dde1d2a..dc11512 100644 (file)
@@ -1,3 +1,29 @@
+2013-10-09  Mario Sanchez Prada  <mario.prada@samsung.com>
+
+        [ATK] Implement new API in AtkText: atk_text_get_string_at_offset()
+        https://bugs.webkit.org/show_bug.cgi?id=120638
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Update ATK unit test to check the new API as well if the version
+        of ATK is new enough.
+
+        * tests/testatk.c:
+        (testGetStringFunction): New helper function, to check the new API.
+        (runGetStringTests): Ditto.
+        (testWebkitAtkGetStringAtOffset): New unit test, similar to the
+        one already present to check the old API but focused in the new one.
+        (testWebkitAtkGetStringAtOffsetNewlines): Ditto.
+        (testWebkitAtkGetStringAtOffsetTextarea): Ditto.
+        (testWebkitAtkGetStringAtOffsetTextInput): Ditto.
+        (testWebkitAtkGetStringAtOffsetWithPreformattedText): Ditto.
+        (testWebkitAtkGetStringAtOffsetWithSpecialCharacters): Ditto.
+        (testWebkitAtkGetStringAtOffsetWithWrappedLines): Ditto.
+        (testWebkitAtkGetStringAtOffsetWithEmbeddedObjects): Ditto.
+        (testWebkitAtkGetExtents): Add checks for the new API, if possible.
+        (testWebkitAtkLinksWithInlineImages): Ditto.
+        (main): Add the new unit tests to check the new API, if possible.
+
 2013-10-07  Sam Weinig  <sam@webkit.org>
 
         Consolidate findString functions
index a74d697..55a0011 100644 (file)
@@ -96,197 +96,6 @@ static AtkObject* getWebAreaObject(WebKitWebView* webView)
     return webAreaObject;
 }
 
-typedef gchar* (*AtkGetTextFunction) (AtkText*, gint, AtkTextBoundary, gint*, gint*);
-
-static void testGetTextFunction(AtkText* textObject, AtkGetTextFunction fn, AtkTextBoundary boundary, gint offset, const char* textResult, gint startOffsetResult, gint endOffsetResult)
-{
-    gint startOffset;
-    gint endOffset;
-    char* text = fn(textObject, offset, boundary, &startOffset, &endOffset);
-    g_assert_cmpstr(text, ==, textResult);
-    g_assert_cmpint(startOffset, ==, startOffsetResult);
-    g_assert_cmpint(endOffset, ==, endOffsetResult);
-    g_free(text);
-}
-
-static void runGetTextTests(AtkText* textObject)
-{
-    char* text = atk_text_get_text(textObject, 0, -1);
-    g_assert_cmpstr(text, ==, "This is a test. This is the second sentence. And this the third.");
-    g_free(text);
-
-    /* ATK_TEXT_BOUNDARY_CHAR */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR,
-                        0, "T", 0, 1);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR,
-                        0, "h", 1, 2);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR,
-                        0, "", 0, 0);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR,
-                        1, "T", 0, 1);
-
-    /* ATK_TEXT_BOUNDARY_WORD_START */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        0, "This ", 0, 5);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        4, "This ", 0, 5);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        10, "test. ", 10, 16);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        58, "third.", 58, 64);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        64, "third.", 58, 64);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        0, "", 0, 0);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        5, "This ", 0, 5);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        7, "This ", 0, 5);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        64, "the ", 54, 58);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        0, "is ", 5, 8);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        4, "is ", 5, 8);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        3, "is ", 5, 8);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
-                        64, "", 64, 64);
-
-    /* ATK_TEXT_BOUNDARY_WORD_END */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        0, "This", 0, 4);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        4, " is", 4, 7);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        5, " is", 4, 7);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        9, " test", 9, 14);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        58, " third", 57, 63);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        64, ".", 63, 64);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        0, "", 0, 0);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        5, "This", 0, 4);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        4, "This", 0, 4);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        7, " is", 4, 7);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        64, " third", 57, 63);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        0, " is", 4, 7);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        5, " a", 7, 9);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        4, " a", 7, 9);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
-                        64, "", 64, 64);
-
-    /* ATK_TEXT_BOUNDARY_SENTENCE_START */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        0, "This is a test. ", 0, 16);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        15, "This is a test. ", 0, 16);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        0, "This is the second sentence. ", 16, 45);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        15, "This is the second sentence. ", 16, 45);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        16, "This is a test. ", 0, 16);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        44, "This is a test. ", 0, 16);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
-                        15, "", 0, 0);
-
-    /* ATK_TEXT_BOUNDARY_SENTENCE_END */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        0, "This is a test.", 0, 15);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        15, " This is the second sentence.", 15, 44);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        16, " This is the second sentence.", 15, 44);
-
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        17, " This is the second sentence.", 15, 44);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        0, " This is the second sentence.", 15, 44);
-
-    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        15, " And this the third.", 44, 64);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        16, "This is a test.", 0, 15);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        15, "This is a test.", 0, 15);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        14, "", 0, 0);
-
-    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
-                        44, " This is the second sentence.", 15, 44);
-
-    /* It's tricky to test these properly right now, since our a11y
-       implementation splits different lines in different a11y items. */
-    /* ATK_TEXT_BOUNDARY_LINE_START */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START,
-                        0, "This is a test. This is the second sentence. And this the third.", 0, 64);
-
-    /* ATK_TEXT_BOUNDARY_LINE_END */
-    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END,
-                        0, "This is a test. This is the second sentence. And this the third.", 0, 64);
-
-    /* For objects implementing AtkEditableText, try to change the
-       exposed text and retrieve it again as a full line.
-       (see https://bugs.webkit.org/show_bug.cgi?id=72830) */
-    if (ATK_IS_EDITABLE_TEXT(textObject)) {
-        atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(textObject), "foo bar baz");
-        testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, "foo bar baz", 0, 11);
-        testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "foo bar baz", 0, 11);
-    }
-}
-
 static gchar* textCaretMovedResult = 0;
 
 static void textCaretMovedCallback(AtkText* text, gint pos, gpointer data)
@@ -524,7 +333,6 @@ static void testWebkitAtkCaretOffsetsAndExtranousWhiteSpaces()
     /* Enable caret browsing. */
     WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
     g_object_set(G_OBJECT(settings), "enable-caret-browsing", TRUE, NULL);
-    webkit_web_view_set_settings(webView, settings);
 
     /* Get to the inner AtkText object. */
     AtkObject* object = getWebAreaObject(webView);
@@ -694,106 +502,693 @@ static void testWebkitAtkDocumentLoadingEvents()
     /* Connect globally to see those events during a future load. */
     guint loadCompleteListenerId = atk_add_global_event_listener(documentLoadingEventCallback, "ATK:AtkDocument:load-complete");
 
-    /* Do the load, so we can see those events happening. */
-    loadingEventsResult = g_strdup("");
-    webkit_web_view_load_string(webView, contents, 0, 0, 0);
+    /* Do the load, so we can see those events happening. */
+    loadingEventsResult = g_strdup("");
+    webkit_web_view_load_string(webView, contents, 0, 0, 0);
+
+    /* Trigger the creation of the full accessibility hierarchy by
+       asking for the webArea object, so we can listen to events. */
+    getWebAreaObject(webView);
+
+    atk_remove_global_event_listener(loadCompleteListenerId);
+
+    g_assert_cmpstr(loadingEventsResult, ==, "|load-complete");
+
+    g_free(loadingEventsResult);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkEmbeddedObjects()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, embeddedObjects, 0, 0, 0);
+
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+
+    AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
+    g_assert(ATK_IS_TEXT(paragraph1));
+    g_assert(ATK_IS_HYPERTEXT(paragraph1));
+
+    const gchar* expectedText = "Choose: \357\277\274foo \357\277\274bar (pick one)";
+    char* text = atk_text_get_text(paragraph1, 0, -1);
+    g_assert_cmpstr(text, ==, expectedText);
+    g_free(text);
+
+    gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1));
+    g_assert_cmpint(nLinks, ==, 2);
+
+    AtkHyperlink* hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph1), 0);
+    g_assert(ATK_HYPERLINK(hLink));
+    AtkObject* hLinkObject = atk_hyperlink_get_object(hLink, 0);
+    g_assert(ATK_OBJECT(hLinkObject));
+    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_CHECK_BOX);
+    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
+    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
+    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
+    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+
+    AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
+    g_assert(ATK_IS_TEXT(paragraph2));
+    g_assert(ATK_IS_HYPERTEXT(paragraph2));
+
+    expectedText = "Choose: \357\277\274 (pick one)";
+    text = atk_text_get_text(paragraph2, 0, -1);
+    g_assert_cmpstr(text, ==, expectedText);
+    g_free(text);
+
+    nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2));
+    g_assert_cmpint(nLinks, ==, 1);
+
+    hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0);
+    g_assert(ATK_HYPERLINK(hLink));
+    hLinkObject = atk_hyperlink_get_object(hLink, 0);
+    g_assert(ATK_OBJECT(hLinkObject));
+    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_COMBO_BOX);
+    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
+    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
+    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
+    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+
+    AtkText* paragraph3 = ATK_TEXT(atk_object_ref_accessible_child(object, 2));
+    g_assert(ATK_IS_TEXT(paragraph3));
+    g_assert(ATK_IS_HYPERTEXT(paragraph3));
+
+    expectedText = "\357\277\274";
+    text = atk_text_get_text(paragraph3, 0, -1);
+    g_assert_cmpstr(text, ==, expectedText);
+    g_free(text);
+
+    nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph3));
+    g_assert_cmpint(nLinks, ==, 1);
+
+    hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph3), 0);
+    g_assert(ATK_HYPERLINK(hLink));
+    hLinkObject = atk_hyperlink_get_object(hLink, 0);
+    g_assert(ATK_OBJECT(hLinkObject));
+    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_PUSH_BUTTON);
+    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 0);
+    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 1);
+    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
+    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+
+    g_object_unref(paragraph1);
+    g_object_unref(paragraph2);
+    g_object_unref(paragraph3);
+    g_object_unref(webView);
+}
+
+#if !ATK_CHECK_VERSION(2, 10, 0)
+typedef gchar* (*AtkGetTextFunction) (AtkText*, gint, AtkTextBoundary, gint*, gint*);
+
+static void testGetTextFunction(AtkText* textObject, AtkGetTextFunction fn, AtkTextBoundary boundary, gint offset, const char* textResult, gint startOffsetResult, gint endOffsetResult)
+{
+    gint startOffset;
+    gint endOffset;
+    char* text = fn(textObject, offset, boundary, &startOffset, &endOffset);
+    g_assert_cmpstr(text, ==, textResult);
+    g_assert_cmpint(startOffset, ==, startOffsetResult);
+    g_assert_cmpint(endOffset, ==, endOffsetResult);
+    g_free(text);
+}
+
+static void runGetTextTests(AtkText* textObject)
+{
+    char* text = atk_text_get_text(textObject, 0, -1);
+    g_assert_cmpstr(text, ==, "This is a test. This is the second sentence. And this the third.");
+    g_free(text);
+
+    /* ATK_TEXT_BOUNDARY_CHAR */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR,
+                        0, "T", 0, 1);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR,
+                        0, "h", 1, 2);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR,
+                        0, "", 0, 0);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR,
+                        1, "T", 0, 1);
+
+    /* ATK_TEXT_BOUNDARY_WORD_START */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        0, "This ", 0, 5);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        4, "This ", 0, 5);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        10, "test. ", 10, 16);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        58, "third.", 58, 64);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        64, "third.", 58, 64);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        0, "", 0, 0);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        5, "This ", 0, 5);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        7, "This ", 0, 5);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        64, "the ", 54, 58);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        0, "is ", 5, 8);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        4, "is ", 5, 8);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        3, "is ", 5, 8);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START,
+                        64, "", 64, 64);
+
+    /* ATK_TEXT_BOUNDARY_WORD_END */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        0, "This", 0, 4);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        4, " is", 4, 7);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        5, " is", 4, 7);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        9, " test", 9, 14);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        58, " third", 57, 63);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        64, ".", 63, 64);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        0, "", 0, 0);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        5, "This", 0, 4);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        4, "This", 0, 4);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        7, " is", 4, 7);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        64, " third", 57, 63);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        0, " is", 4, 7);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        5, " a", 7, 9);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        4, " a", 7, 9);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END,
+                        64, "", 64, 64);
+
+    /* ATK_TEXT_BOUNDARY_SENTENCE_START */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        0, "This is a test. ", 0, 16);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        15, "This is a test. ", 0, 16);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        0, "This is the second sentence. ", 16, 45);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        15, "This is the second sentence. ", 16, 45);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        16, "This is a test. ", 0, 16);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        44, "This is a test. ", 0, 16);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START,
+                        15, "", 0, 0);
+
+    /* ATK_TEXT_BOUNDARY_SENTENCE_END */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        0, "This is a test.", 0, 15);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        15, " This is the second sentence.", 15, 44);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        16, " This is the second sentence.", 15, 44);
+
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        17, " This is the second sentence.", 15, 44);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        0, " This is the second sentence.", 15, 44);
+
+    testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        15, " And this the third.", 44, 64);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        16, "This is a test.", 0, 15);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        15, "This is a test.", 0, 15);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        14, "", 0, 0);
+
+    testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END,
+                        44, " This is the second sentence.", 15, 44);
+
+    /* It's tricky to test these properly right now, since our a11y
+       implementation splits different lines in different a11y items. */
+    /* ATK_TEXT_BOUNDARY_LINE_START */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START,
+                        0, "This is a test. This is the second sentence. And this the third.", 0, 64);
+
+    /* ATK_TEXT_BOUNDARY_LINE_END */
+    testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END,
+                        0, "This is a test. This is the second sentence. And this the third.", 0, 64);
+
+    /* For objects implementing AtkEditableText, try to change the
+       exposed text and retrieve it again as a full line.
+       (see https://bugs.webkit.org/show_bug.cgi?id=72830) */
+    if (ATK_IS_EDITABLE_TEXT(textObject)) {
+        atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(textObject), "foo bar baz");
+        testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, "foo bar baz", 0, 11);
+        testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "foo bar baz", 0, 11);
+    }
+}
+
+static void testWebkitAtkGetTextAtOffset()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contents, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+    object = atk_object_ref_accessible_child(object, 0);
+    g_assert(object);
+
+    AtkText* textObject = ATK_TEXT(object);
+    g_assert(ATK_IS_TEXT(textObject));
+
+    runGetTextTests(textObject);
+
+    g_object_unref(object);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetNewlines()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsWithNewlines, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+    object = atk_object_ref_accessible_child(object, 0);
+    g_assert(object);
+
+    AtkText* textObject = ATK_TEXT(object);
+    g_assert(ATK_IS_TEXT(textObject));
+
+    runGetTextTests(textObject);
+
+    g_object_unref(object);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetTextarea()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsInTextarea, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+    AtkObject* child = atk_object_ref_accessible_child(object, 0);
+    g_assert(child);
+    AtkObject* grandchild = atk_object_ref_accessible_child(child, 0);
+    g_assert(grandchild);
+
+    AtkText* textObject = ATK_TEXT(grandchild);
+    g_assert(ATK_IS_TEXT(textObject));
+
+    runGetTextTests(textObject);
+
+    g_object_unref(child);
+    g_object_unref(grandchild);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetTextInput()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsInTextInput, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+    AtkObject* child = atk_object_ref_accessible_child(object, 0);
+    g_assert(child);
+    AtkObject* grandchild = atk_object_ref_accessible_child(child, 0);
+    g_assert(grandchild);
+
+    AtkText* textObject = ATK_TEXT(grandchild);
+    g_assert(ATK_IS_TEXT(textObject));
+
+    runGetTextTests(textObject);
+
+    g_object_unref(child);
+    g_object_unref(grandchild);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetWithPreformattedText()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsWithPreformattedText, 0, 0, 0);
+
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+
+    AtkObject* preformattedText = atk_object_ref_accessible_child(object, 0);
+    g_assert(ATK_IS_OBJECT(preformattedText));
+    g_assert(atk_object_get_role(preformattedText) == ATK_ROLE_PANEL);
+    g_assert(ATK_IS_TEXT(preformattedText));
+    char* text = atk_text_get_text(ATK_TEXT(preformattedText), 0, -1);
+    g_assert_cmpstr(text, ==, "\t\n\tfirst line\n\tsecond line\n\t\n");
+    g_free(text);
+
+    /* Try retrieving all the lines indicating the position of the offsets at the beginning of each of them. */
+    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, "\t\n", 0, 2);
+    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 2, "\tfirst line\n", 2, 14);
+    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 14, "\tsecond line\n", 14, 27);
+
+    g_object_unref(preformattedText);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsWithSpecialChars, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+
+    AtkObject* paragraph = atk_object_ref_accessible_child(object, 0);
+    g_assert(ATK_IS_TEXT(paragraph));
+
+    gchar* expectedText = g_strdup("\302\253\302\240This is a paragraph with \342\200\234special\342\200\235 characters inside.\302\240\302\273");
+    char* text = atk_text_get_text(ATK_TEXT(paragraph), 0, -1);
+    g_assert_cmpstr(text, ==, expectedText);
+    g_free(text);
+
+    /* Check that getting the text with ATK_TEXT_BOUNDARY_LINE_START
+       and ATK_TEXT_BOUNDARY_LINE_END does not crash because of not
+       properly handling characters inside the UTF-8 string. */
+    testGetTextFunction(ATK_TEXT(paragraph), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, expectedText, 0, 57);
+    testGetTextFunction(ATK_TEXT(paragraph), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, expectedText, 0, 57);
+    g_free(expectedText);
+
+    AtkObject* list = atk_object_ref_accessible_child(object, 1);
+    g_assert(ATK_OBJECT(list));
+
+    AtkText* listItem = ATK_TEXT(atk_object_ref_accessible_child(list, 0));
+    g_assert(ATK_IS_TEXT(listItem));
+
+    text = atk_text_get_text(ATK_TEXT(listItem), 0, -1);
+    g_assert_cmpstr(text, ==, "\342\200\242 List item with some text that wraps across different lines.");
+    g_free(text);
+
+    /* Check that getting the text with ATK_TEXT_BOUNDARY_LINE_START
+       and ATK_TEXT_BOUNDARY_LINE_END for line items with bullets
+       (special character) and wrapped text always return the right
+       piece of text for each line. */
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 3, "\342\200\242 List item ", 0, 12);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 13, "with some ", 12, 22);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "\342\200\242 List item", 0, 11);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 12, " with some", 11, 21);
+
+    g_object_unref(listItem);
+
+    listItem = ATK_TEXT(atk_object_ref_accessible_child(list, 1));
+    g_assert(ATK_IS_TEXT(listItem));
+
+    /* Check that placing the same text in a paragraph doesn't break things. */
+    text = atk_text_get_text(ATK_TEXT(listItem), 0, -1);
+    g_assert_cmpstr(text, ==, "\342\200\242 List item with some text that wraps across different lines.");
+    g_free(text);
+
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 3, "\342\200\242 List item ", 0, 12);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 13, "with some ", 12, 22);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "\342\200\242 List item", 0, 11);
+    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 12, " with some", 11, 21);
+
+    g_object_unref(list);
+    g_object_unref(listItem);
+    g_object_unref(paragraph);
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetWithWrappedLines()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsWithWrappedLines, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+
+    /* Check the paragraph with the text wrapped because of max-width. */
+    AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
+    g_assert(ATK_IS_TEXT(paragraph1));
+
+    gchar* text = atk_text_get_text(paragraph1, 0, -1);
+    g_assert_cmpstr(text, ==, "This is one line wrapped because of the maximum width of its container.");
+    g_free(text);
+
+    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 16, "e", 15, 16);
+    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 16, " ", 16, 17);
+    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 16, "w", 17, 18);
+
+    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "one ", 8, 12);
+    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "line ", 12, 17);
+    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "wrapped ", 17, 25);
+
+    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " line", 11, 16);
+    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " wrapped", 16, 24);
+    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " because", 24, 32);
+
+    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "This is one line ", 0, 17);
+    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "wrapped because ", 17, 33);
+    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "of the maximum ", 33, 48);
+
+    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, "This is one line", 0, 16);
+    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, " wrapped because", 16, 32);
+    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, " of the maximum", 32, 47);
+
+    g_object_unref(paragraph1);
+
+    /* Check the paragraph with the text wrapped because of <br> elements. */
+    AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
+    g_assert(ATK_IS_TEXT(paragraph2));
+
+    text = atk_text_get_text(paragraph2, 0, -1);
+    g_assert_cmpstr(text, ==, "This is another line wrapped\nbecause of one forced\nline break in the middle.");
+    g_free(text);
+
+    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "d", 27, 28);
+    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "\n", 28, 29);
+    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "b", 29, 30);
+
+    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "line ", 16, 21);
+    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "wrapped\n", 21, 29);
+    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "because ", 29, 37);
+
+    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, " wrapped", 20, 28);
+    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, "\nbecause", 28, 36);
+    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, " of", 36, 39);
+
+    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "This is another line wrapped\n", 0, 29);
+    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "because of one forced\n", 29, 51);
+    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "line break in the middle.", 51, 76);
+
+    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "This is another line wrapped", 0, 28);
+    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "\nbecause of one forced", 28, 50);
+    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "\nline break in the middle.", 50, 76);
+
+    g_object_unref(paragraph2);
+
+    g_object_unref(webView);
+}
+
+static void testWebkitAtkGetTextAtOffsetWithEmbeddedObjects()
+{
+    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+    g_object_ref_sink(webView);
+    GtkAllocation allocation = { 0, 0, 800, 600 };
+    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
+    webkit_web_view_load_string(webView, contentsWithEmbeddedObjects, 0, 0, 0);
+
+    /* Get to the inner AtkText object. */
+    AtkObject* object = getWebAreaObject(webView);
+    g_assert(object);
+
+    /* Check the paragraph with the text wrapped because of max-width. */
+    AtkText* paragraph = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
+    g_assert(ATK_IS_TEXT(paragraph));
+
+    gchar* text = atk_text_get_text(paragraph, 0, -1);
+    g_assert_cmpstr(text, ==, "This is one line containing two \357\277\274 embedded objects \357\277\274 in the middle.");
+    g_free(text);
+
+    /* Check right before the first embedded object */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 32, "\357\277\274", 32, 33);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 32, "two \357\277\274 ", 28, 34);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 32, " \357\277\274 embedded", 31, 42);
+
+    /* Check right after the first embedded object (and before the first word after it) */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 33, " ", 33, 34);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 33, "two \357\277\274 ", 28, 34);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 33, " \357\277\274 embedded", 31, 42);
+
+    /* Check at the beginning of the first word between the two embedded objects */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 34, "e", 34, 35);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 34, "embedded ", 34, 43);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 34, " \357\277\274 embedded", 31, 42);
+
+    /* Check at the end of the first word between the two embedded objects */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 42, " ", 42, 43);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 42, "embedded ", 34, 43);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 42, " objects", 42, 50);
 
-    /* Trigger the creation of the full accessibility hierarchy by
-       asking for the webArea object, so we can listen to events. */
-    getWebAreaObject(webView);
+    /* Check right before the second embedded object */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 51, "\357\277\274", 51, 52);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 51, "objects \357\277\274 ", 43, 53);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 51, " \357\277\274 in", 50, 55);
 
-    atk_remove_global_event_listener(loadCompleteListenerId);
+    /* Check right after the second embedded object (and before the first word after it) */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 52, " ", 52, 53);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 52, "objects \357\277\274 ", 43, 53);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 52, " \357\277\274 in", 50, 55);
 
-    g_assert_cmpstr(loadingEventsResult, ==, "|load-complete");
+    /* Check at the beginning of the first word after the two embedded objects */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 53, "i", 53, 54);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 53, "in ", 53, 56);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 53, " \357\277\274 in", 50, 55);
 
-    g_free(loadingEventsResult);
+    /* Check at the end of the first word after the two embedded objects */
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 55, " ", 55, 56);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 55, "in ", 53, 56);
+    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 55, " the", 55, 59);
+
+    g_object_unref(paragraph);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkEmbeddedObjects()
-{
-    WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
-    g_object_ref_sink(webView);
-    GtkAllocation allocation = { 0, 0, 800, 600 };
-    gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
-    webkit_web_view_load_string(webView, embeddedObjects, 0, 0, 0);
-
-    AtkObject* object = getWebAreaObject(webView);
-    g_assert(object);
+#else // !ATK_CHECK_VERSION(2, 10, 0)
 
-    AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0));
-    g_assert(ATK_IS_TEXT(paragraph1));
-    g_assert(ATK_IS_HYPERTEXT(paragraph1));
+typedef gchar* (*AtkGetStringFunction) (AtkText*, gint, AtkTextGranularity, gint*, gint*);
 
-    const gchar* expectedText = "Choose: \357\277\274foo \357\277\274bar (pick one)";
-    char* text = atk_text_get_text(paragraph1, 0, -1);
-    g_assert_cmpstr(text, ==, expectedText);
+static void testGetStringFunction(AtkText* textObject, AtkGetStringFunction fn, AtkTextGranularity granularity, gint offset, const char* textResult, gint startOffsetResult, gint endOffsetResult)
+{
+    gint startOffset;
+    gint endOffset;
+    char* text = fn(textObject, offset, granularity, &startOffset, &endOffset);
+    g_assert_cmpstr(text, ==, textResult);
+    g_assert_cmpint(startOffset, ==, startOffsetResult);
+    g_assert_cmpint(endOffset, ==, endOffsetResult);
     g_free(text);
+}
 
-    gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1));
-    g_assert_cmpint(nLinks, ==, 2);
+static void runGetStringTests(AtkText* textObject)
+{
+    char* text = atk_text_get_text(textObject, 0, -1);
+    g_assert_cmpstr(text, ==, "This is a test. This is the second sentence. And this the third.");
+    g_free(text);
 
-    AtkHyperlink* hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph1), 0);
-    g_assert(ATK_HYPERLINK(hLink));
-    AtkObject* hLinkObject = atk_hyperlink_get_object(hLink, 0);
-    g_assert(ATK_OBJECT(hLinkObject));
-    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_CHECK_BOX);
-    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
-    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
-    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
-    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+    /* ATK_TEXT_GRANULARITY_CHAR */
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR,
+                        0, "T", 0, 1);
 
-    AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1));
-    g_assert(ATK_IS_TEXT(paragraph2));
-    g_assert(ATK_IS_HYPERTEXT(paragraph2));
+    /* ATK_TEXT_GRANULARITY_WORD */
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD,
+                        0, "This ", 0, 5);
 
-    expectedText = "Choose: \357\277\274 (pick one)";
-    text = atk_text_get_text(paragraph2, 0, -1);
-    g_assert_cmpstr(text, ==, expectedText);
-    g_free(text);
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD,
+                        4, "This ", 0, 5);
 
-    nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2));
-    g_assert_cmpint(nLinks, ==, 1);
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD,
+                        10, "test. ", 10, 16);
 
-    hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0);
-    g_assert(ATK_HYPERLINK(hLink));
-    hLinkObject = atk_hyperlink_get_object(hLink, 0);
-    g_assert(ATK_OBJECT(hLinkObject));
-    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_COMBO_BOX);
-    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8);
-    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9);
-    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
-    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD,
+                        58, "third.", 58, 64);
 
-    AtkText* paragraph3 = ATK_TEXT(atk_object_ref_accessible_child(object, 2));
-    g_assert(ATK_IS_TEXT(paragraph3));
-    g_assert(ATK_IS_HYPERTEXT(paragraph3));
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD,
+                        64, "third.", 58, 64);
 
-    expectedText = "\357\277\274";
-    text = atk_text_get_text(paragraph3, 0, -1);
-    g_assert_cmpstr(text, ==, expectedText);
-    g_free(text);
+    /* ATK_TEXT_GRANULARITY_SENTENCE */
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_SENTENCE,
+                        0, "This is a test. ", 0, 16);
 
-    nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph3));
-    g_assert_cmpint(nLinks, ==, 1);
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_SENTENCE,
+                        15, "This is a test. ", 0, 16);
 
-    hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph3), 0);
-    g_assert(ATK_HYPERLINK(hLink));
-    hLinkObject = atk_hyperlink_get_object(hLink, 0);
-    g_assert(ATK_OBJECT(hLinkObject));
-    g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_PUSH_BUTTON);
-    g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 0);
-    g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 1);
-    g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1);
-    g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0);
+    /* ATK_TEXT_GRANULARITY_LINE */
+    /* It's tricky to test these properly right now, since our a11y
+       implementation splits different lines in different a11y items. */
+    testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE,
+                        0, "This is a test. This is the second sentence. And this the third.", 0, 64);
 
-    g_object_unref(paragraph1);
-    g_object_unref(paragraph2);
-    g_object_unref(paragraph3);
-    g_object_unref(webView);
+    /* For objects implementing AtkEditableText, try to change the
+       exposed text and retrieve it again as a full line.
+       (see https://bugs.webkit.org/show_bug.cgi?id=72830) */
+    if (ATK_IS_EDITABLE_TEXT(textObject)) {
+        atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(textObject), "foo bar baz");
+        testGetStringFunction(textObject, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 0, "foo bar baz", 0, 11);
+    }
 }
 
-static void testWebkitAtkGetTextAtOffset()
+static void testWebkitAtkGetStringAtOffset()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -810,13 +1205,13 @@ static void testWebkitAtkGetTextAtOffset()
     AtkText* textObject = ATK_TEXT(object);
     g_assert(ATK_IS_TEXT(textObject));
 
-    runGetTextTests(textObject);
+    runGetStringTests(textObject);
 
     g_object_unref(object);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetNewlines()
+static void testWebkitAtkGetStringAtOffsetNewlines()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -833,13 +1228,13 @@ static void testWebkitAtkGetTextAtOffsetNewlines()
     AtkText* textObject = ATK_TEXT(object);
     g_assert(ATK_IS_TEXT(textObject));
 
-    runGetTextTests(textObject);
+    runGetStringTests(textObject);
 
     g_object_unref(object);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetTextarea()
+static void testWebkitAtkGetStringAtOffsetTextarea()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -858,14 +1253,14 @@ static void testWebkitAtkGetTextAtOffsetTextarea()
     AtkText* textObject = ATK_TEXT(grandchild);
     g_assert(ATK_IS_TEXT(textObject));
 
-    runGetTextTests(textObject);
+    runGetStringTests(textObject);
 
     g_object_unref(child);
     g_object_unref(grandchild);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetTextInput()
+static void testWebkitAtkGetStringAtOffsetTextInput()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -884,14 +1279,14 @@ static void testWebkitAtkGetTextAtOffsetTextInput()
     AtkText* textObject = ATK_TEXT(grandchild);
     g_assert(ATK_IS_TEXT(textObject));
 
-    runGetTextTests(textObject);
+    runGetStringTests(textObject);
 
     g_object_unref(child);
     g_object_unref(grandchild);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetWithPreformattedText()
+static void testWebkitAtkGetStringAtOffsetWithPreformattedText()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -911,15 +1306,15 @@ static void testWebkitAtkGetTextAtOffsetWithPreformattedText()
     g_free(text);
 
     /* Try retrieving all the lines indicating the position of the offsets at the beginning of each of them. */
-    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, "\t\n", 0, 2);
-    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 2, "\tfirst line\n", 2, 14);
-    testGetTextFunction(ATK_TEXT(preformattedText), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 14, "\tsecond line\n", 14, 27);
+    testGetStringFunction(ATK_TEXT(preformattedText), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 0, "\t\n", 0, 2);
+    testGetStringFunction(ATK_TEXT(preformattedText), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 2, "\tfirst line\n", 2, 14);
+    testGetStringFunction(ATK_TEXT(preformattedText), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 14, "\tsecond line\n", 14, 27);
 
     g_object_unref(preformattedText);
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
+static void testWebkitAtkGetStringAtOffsetWithSpecialCharacters()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -939,11 +1334,9 @@ static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
     g_assert_cmpstr(text, ==, expectedText);
     g_free(text);
 
-    /* Check that getting the text with ATK_TEXT_BOUNDARY_LINE_START
-       and ATK_TEXT_BOUNDARY_LINE_END does not crash because of not
-       properly handling characters inside the UTF-8 string. */
-    testGetTextFunction(ATK_TEXT(paragraph), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, expectedText, 0, 57);
-    testGetTextFunction(ATK_TEXT(paragraph), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, expectedText, 0, 57);
+    /* Check that getting the text with ATK_TEXT_BOUNDARY_LINE_START does not crash
+       because of not properly handling characters inside the UTF-8 string. */
+    testGetStringFunction(ATK_TEXT(paragraph), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 0, expectedText, 0, 57);
     g_free(expectedText);
 
     AtkObject* list = atk_object_ref_accessible_child(object, 1);
@@ -960,10 +1353,8 @@ static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
        and ATK_TEXT_BOUNDARY_LINE_END for line items with bullets
        (special character) and wrapped text always return the right
        piece of text for each line. */
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 3, "\342\200\242 List item ", 0, 12);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 13, "with some ", 12, 22);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "\342\200\242 List item", 0, 11);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 12, " with some", 11, 21);
+    testGetStringFunction(ATK_TEXT(listItem), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 3, "\342\200\242 List item ", 0, 12);
+    testGetStringFunction(ATK_TEXT(listItem), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 13, "with some ", 12, 22);
 
     g_object_unref(listItem);
 
@@ -975,10 +1366,8 @@ static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
     g_assert_cmpstr(text, ==, "\342\200\242 List item with some text that wraps across different lines.");
     g_free(text);
 
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 3, "\342\200\242 List item ", 0, 12);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 13, "with some ", 12, 22);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, "\342\200\242 List item", 0, 11);
-    testGetTextFunction(ATK_TEXT(listItem), atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 12, " with some", 11, 21);
+    testGetStringFunction(ATK_TEXT(listItem), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 3, "\342\200\242 List item ", 0, 12);
+    testGetStringFunction(ATK_TEXT(listItem), atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 13, "with some ", 12, 22);
 
     g_object_unref(list);
     g_object_unref(listItem);
@@ -986,7 +1375,7 @@ static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters()
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetWithWrappedLines()
+static void testWebkitAtkGetStringAtOffsetWithWrappedLines()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -994,11 +1383,6 @@ static void testWebkitAtkGetTextAtOffsetWithWrappedLines()
     gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
     webkit_web_view_load_string(webView, contentsWithWrappedLines, 0, 0, 0);
 
-    /* Enable caret browsing. */
-    WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
-    g_object_set(settings, "enable-caret-browsing", TRUE, NULL);
-    webkit_web_view_set_settings(webView, settings);
-
     /* Get to the inner AtkText object. */
     AtkObject* object = getWebAreaObject(webView);
     g_assert(object);
@@ -1011,25 +1395,9 @@ static void testWebkitAtkGetTextAtOffsetWithWrappedLines()
     g_assert_cmpstr(text, ==, "This is one line wrapped because of the maximum width of its container.");
     g_free(text);
 
-    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 16, "e", 15, 16);
-    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 16, " ", 16, 17);
-    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 16, "w", 17, 18);
-
-    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "one ", 8, 12);
-    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "line ", 12, 17);
-    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 16, "wrapped ", 17, 25);
-
-    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " line", 11, 16);
-    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " wrapped", 16, 24);
-    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 16, " because", 24, 32);
-
-    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "This is one line ", 0, 17);
-    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "wrapped because ", 17, 33);
-    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_START, 17, "of the maximum ", 33, 48);
-
-    testGetTextFunction(paragraph1, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, "This is one line", 0, 16);
-    testGetTextFunction(paragraph1, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, " wrapped because", 16, 32);
-    testGetTextFunction(paragraph1, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_END, 17, " of the maximum", 32, 47);
+    testGetStringFunction(paragraph1, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 16, " ", 16, 17);
+    testGetStringFunction(paragraph1, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 16, "line ", 12, 17);
+    testGetStringFunction(paragraph1, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 17, "wrapped because ", 17, 33);
 
     g_object_unref(paragraph1);
 
@@ -1041,32 +1409,16 @@ static void testWebkitAtkGetTextAtOffsetWithWrappedLines()
     g_assert_cmpstr(text, ==, "This is another line wrapped\nbecause of one forced\nline break in the middle.");
     g_free(text);
 
-    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "d", 27, 28);
-    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "\n", 28, 29);
-    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 28, "b", 29, 30);
-
-    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "line ", 16, 21);
-    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "wrapped\n", 21, 29);
-    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 28, "because ", 29, 37);
-
-    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, " wrapped", 20, 28);
-    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, "\nbecause", 28, 36);
-    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 28, " of", 36, 39);
-
-    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "This is another line wrapped\n", 0, 29);
-    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "because of one forced\n", 29, 51);
-    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_START, 30, "line break in the middle.", 51, 76);
-
-    testGetTextFunction(paragraph2, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "This is another line wrapped", 0, 28);
-    testGetTextFunction(paragraph2, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "\nbecause of one forced", 28, 50);
-    testGetTextFunction(paragraph2, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_LINE_END, 30, "\nline break in the middle.", 50, 76);
+    testGetStringFunction(paragraph2, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 28, "\n", 28, 29);
+    testGetStringFunction(paragraph2, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 28, "wrapped\n", 21, 29);
+    testGetStringFunction(paragraph2, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_LINE, 30, "because of one forced\n", 29, 51);
 
     g_object_unref(paragraph2);
 
     g_object_unref(webView);
 }
 
-static void testWebkitAtkGetTextAtOffsetWithEmbeddedObjects()
+static void testWebkitAtkGetStringAtOffsetWithEmbeddedObjects()
 {
     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
     g_object_ref_sink(webView);
@@ -1074,11 +1426,6 @@ static void testWebkitAtkGetTextAtOffsetWithEmbeddedObjects()
     gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation);
     webkit_web_view_load_string(webView, contentsWithEmbeddedObjects, 0, 0, 0);
 
-    /* Enable caret browsing. */
-    WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
-    g_object_set(settings, "enable-caret-browsing", TRUE, NULL);
-    webkit_web_view_set_settings(webView, settings);
-
     /* Get to the inner AtkText object. */
     AtkObject* object = getWebAreaObject(webView);
     g_assert(object);
@@ -1092,48 +1439,41 @@ static void testWebkitAtkGetTextAtOffsetWithEmbeddedObjects()
     g_free(text);
 
     /* Check right before the first embedded object */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 32, "\357\277\274", 32, 33);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 32, "two \357\277\274 ", 28, 34);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 32, " \357\277\274 embedded", 31, 42);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 32, "\357\277\274", 32, 33);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 32, "two \357\277\274 ", 28, 34);
 
     /* Check right after the first embedded object (and before the first word after it) */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 33, " ", 33, 34);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 33, "two \357\277\274 ", 28, 34);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 33, " \357\277\274 embedded", 31, 42);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 33, " ", 33, 34);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 33, "two \357\277\274 ", 28, 34);
 
     /* Check at the beginning of the first word between the two embedded objects */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 34, "e", 34, 35);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 34, "embedded ", 34, 43);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 34, " \357\277\274 embedded", 31, 42);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 34, "e", 34, 35);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 34, "embedded ", 34, 43);
 
     /* Check at the end of the first word between the two embedded objects */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 42, " ", 42, 43);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 42, "embedded ", 34, 43);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 42, " objects", 42, 50);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 42, " ", 42, 43);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 42, "embedded ", 34, 43);
 
     /* Check right before the second embedded object */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 51, "\357\277\274", 51, 52);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 51, "objects \357\277\274 ", 43, 53);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 51, " \357\277\274 in", 50, 55);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 51, "\357\277\274", 51, 52);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 51, "objects \357\277\274 ", 43, 53);
 
     /* Check right after the second embedded object (and before the first word after it) */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 52, " ", 52, 53);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 52, "objects \357\277\274 ", 43, 53);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 52, " \357\277\274 in", 50, 55);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 52, " ", 52, 53);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 52, "objects \357\277\274 ", 43, 53);
 
     /* Check at the beginning of the first word after the two embedded objects */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 53, "i", 53, 54);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 53, "in ", 53, 56);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 53, " \357\277\274 in", 50, 55);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 53, "i", 53, 54);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 53, "in ", 53, 56);
 
     /* Check at the end of the first word after the two embedded objects */
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 55, " ", 55, 56);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 55, "in ", 53, 56);
-    testGetTextFunction(paragraph, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 55, " the", 55, 59);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_CHAR, 55, " ", 55, 56);
+    testGetStringFunction(paragraph, atk_text_get_string_at_offset, ATK_TEXT_GRANULARITY_WORD, 55, "in ", 53, 56);
 
     g_object_unref(paragraph);
     g_object_unref(webView);
 }
+#endif // !ATK_CHECK_VERSION(2, 10, 0)
 
 static void testWebkitAtkGetTextInParagraphAndBodySimple()
 {
@@ -1737,8 +2077,14 @@ static void testWebkitAtkGetExtents()
        a partial section of the same line */
     gint startOffset;
     gint endOffset;
+
+#if !ATK_CHECK_VERSION(2, 10, 0)
     gchar* text = atk_text_get_text_at_offset(multilineText, 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
     g_free(text);
+#else
+    gchar* text = atk_text_get_string_at_offset(multilineText, 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+    g_free(text);
+#endif
 
     AtkTextRectangle fline_window;
     AtkTextRectangle afline_window;
@@ -1806,36 +2152,68 @@ static void testWebkitAtkLinksWithInlineImages()
     g_assert(ATK_IS_TEXT(paragraph));
     gint startOffset;
     gint endOffset;
+
+#if !ATK_CHECK_VERSION(2, 10, 0)
     gchar* text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
     g_assert(text);
     g_assert_cmpstr(text, ==, "foo bar baz");
     g_assert_cmpint(startOffset, ==, 0);
     g_assert_cmpint(endOffset, ==, 11);
     g_free(text);
+#else
+    gchar* text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+    g_assert(text);
+    g_assert_cmpstr(text, ==, "foo bar baz");
+    g_assert_cmpint(startOffset, ==, 0);
+    g_assert_cmpint(endOffset, ==, 11);
+    g_free(text);
+#endif
+
     g_object_unref(paragraph);
 
     /* Second paragraph (link in the middle). */
     paragraph = atk_object_ref_accessible_child(object, 1);
     g_assert(ATK_IS_TEXT(paragraph));
+
+#if !ATK_CHECK_VERSION(2, 10, 0)
     text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
     g_assert(text);
     g_assert_cmpstr(text, ==, "foo bar baz");
     g_assert_cmpint(startOffset, ==, 0);
     g_assert_cmpint(endOffset, ==, 11);
     g_free(text);
+#else
+    text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+    g_assert(text);
+    g_assert_cmpstr(text, ==, "foo bar baz");
+    g_assert_cmpint(startOffset, ==, 0);
+    g_assert_cmpint(endOffset, ==, 11);
+    g_free(text);
+#endif
+
     g_object_unref(paragraph);
 
     /* Third paragraph (link at the end). */
     paragraph = atk_object_ref_accessible_child(object, 2);
     g_assert(ATK_IS_TEXT(paragraph));
+
+#if !ATK_CHECK_VERSION(2, 10, 0)
     text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset);
     g_assert(text);
     g_assert_cmpstr(text, ==, "foo bar baz");
     g_assert_cmpint(startOffset, ==, 0);
     g_assert_cmpint(endOffset, ==, 11);
     g_free(text);
-    g_object_unref(paragraph);
+#else
+    text = atk_text_get_string_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+    g_assert(text);
+    g_assert_cmpstr(text, ==, "foo bar baz");
+    g_assert_cmpint(startOffset, ==, 0);
+    g_assert_cmpint(endOffset, ==, 11);
+    g_free(text);
+#endif
 
+    g_object_unref(paragraph);
     g_object_unref(webView);
 }
 
@@ -2218,6 +2596,7 @@ int main(int argc, char** argv)
     g_test_add_func("/webkit/atk/comboBox", testWebkitAtkComboBox);
     g_test_add_func("/webkit/atk/documentLoadingEvents", testWebkitAtkDocumentLoadingEvents);
     g_test_add_func("/webkit/atk/embeddedObjects", testWebkitAtkEmbeddedObjects);
+#if !ATK_CHECK_VERSION(2, 10, 0)
     g_test_add_func("/webkit/atk/getTextAtOffset", testWebkitAtkGetTextAtOffset);
     g_test_add_func("/webkit/atk/getTextAtOffsetNewlines", testWebkitAtkGetTextAtOffsetNewlines);
     g_test_add_func("/webkit/atk/getTextAtOffsetTextarea", testWebkitAtkGetTextAtOffsetTextarea);
@@ -2226,6 +2605,16 @@ int main(int argc, char** argv)
     g_test_add_func("/webkit/atk/getTextAtOffsetWithSpecialCharacters", testWebkitAtkGetTextAtOffsetWithSpecialCharacters);
     g_test_add_func("/webkit/atk/getTextAtOffsetWithWrappedLines", testWebkitAtkGetTextAtOffsetWithWrappedLines);
     g_test_add_func("/webkit/atk/getTextAtOffsetWithEmbeddedObjects", testWebkitAtkGetTextAtOffsetWithEmbeddedObjects);
+#else
+    g_test_add_func("/webkit/atk/getStringAtOffset", testWebkitAtkGetStringAtOffset);
+    g_test_add_func("/webkit/atk/getStringAtOffsetNewlines", testWebkitAtkGetStringAtOffsetNewlines);
+    g_test_add_func("/webkit/atk/getStringAtOffsetTextarea", testWebkitAtkGetStringAtOffsetTextarea);
+    g_test_add_func("/webkit/atk/getStringAtOffsetTextInput", testWebkitAtkGetStringAtOffsetTextInput);
+    g_test_add_func("/webkit/atk/getStringAtOffsetWithPreformattedText", testWebkitAtkGetStringAtOffsetWithPreformattedText);
+    g_test_add_func("/webkit/atk/getStringAtOffsetWithSpecialCharacters", testWebkitAtkGetStringAtOffsetWithSpecialCharacters);
+    g_test_add_func("/webkit/atk/getStringAtOffsetWithWrappedLines", testWebkitAtkGetStringAtOffsetWithWrappedLines);
+    g_test_add_func("/webkit/atk/getStringAtOffsetWithEmbeddedObjects", testWebkitAtkGetStringAtOffsetWithEmbeddedObjects);
+#endif
     g_test_add_func("/webkit/atk/getTextInParagraphAndBodySimple", testWebkitAtkGetTextInParagraphAndBodySimple);
     g_test_add_func("/webkit/atk/getTextInParagraphAndBodyModerate", testWebkitAtkGetTextInParagraphAndBodyModerate);
     g_test_add_func("/webkit/atk/getTextInTable", testWebkitAtkGetTextInTable);
index 72befe2..4f5bcfb 100644 (file)
@@ -1,3 +1,13 @@
+2013-10-09  Mario Sanchez Prada  <mario.prada@samsung.com>
+
+        [ATK] Implement new API in AtkText: atk_text_get_string_at_offset()
+        https://bugs.webkit.org/show_bug.cgi?id=120638
+
+        Reviewed by Gustavo Noronha Silva.
+
+        * gtk/jhbuild.modules: Raised ATK and AT-SPI versions to 2.10.0, so we
+        can check both the old and new APIs to retrieve text at a given offset.
+
 2013-10-08  Alex Christensen  <achristensen@webkit.org>
 
         Improved WinLauncher.
index 17ab4a7..95f883d 100644 (file)
   <autotools id="atk"
              autogen-sh="configure"
              autogenargs="--disable-introspection">
-    <branch module="pub/GNOME/sources/atk/2.8/atk-2.8.0.tar.xz" version="2.8.0"
+    <branch module="pub/GNOME/sources/atk/2.10/atk-2.10.0.tar.xz" version="2.10.0"
             repo="ftp.gnome.org"
-            hash="sha256:b22519176226f3e07cf6d932b77852e6b6be4780977770704b32d0f4e0686df4"/>
+            hash="sha256:636917a5036bc851d8491194645d284798ec118919a828be5e713b6ecc5b50b0"/>
   </autotools>
 
   <autotools id="at-spi2-core" 
              autogenargs="--disable-introspection">
-    <branch module="pub/GNOME/sources/at-spi2-core/2.8/at-spi2-core-2.8.0.tar.xz" version="2.8.0"
+    <branch module="pub/GNOME/sources/at-spi2-core/2.10/at-spi2-core-2.10.0.tar.xz" version="2.10.0"
             repo="ftp.gnome.org"
-            hash="sha256:1861a30fc7f583d5a567a0ba547db67ce9bd294f0d1c9f7403c96a10a481c458">
+            hash="sha256:964155c7574220a00e11e1c0d91f2d3017ed603920eb1333ff9cbdb6a22744db">
     </branch>
     <dependencies>
       <dep package="glib"/>
   </autotools>
 
   <autotools id="at-spi2-atk">
-    <branch module="pub/GNOME/sources/at-spi2-atk/2.8/at-spi2-atk-2.8.0.tar.xz" version="2.8.0"
+    <branch module="pub/GNOME/sources/at-spi2-atk/2.10/at-spi2-atk-2.10.0.tar.xz" version="2.10.0"
             repo="ftp.gnome.org"
-            hash="sha256:4688acbc1474cda0aa49341f109ad0726603ce3e872cc6521c74931338c7ba20">
-      <patch file="at-spi2-atk-2.8.0-null-check-after-cleanup.patch" strip="1"/>
+            hash="sha256:dea7ff2f9bc9bbdb0351112616d738de718b55739cd2511afecac51604c31a94">
     </branch>
     <dependencies>
       <dep package="glib"/>
diff --git a/Tools/gtk/patches/at-spi2-atk-2.8.0-null-check-after-cleanup.patch b/Tools/gtk/patches/at-spi2-atk-2.8.0-null-check-after-cleanup.patch
deleted file mode 100644 (file)
index cd13ee4..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-From 5de2b2bc9c83045a6870e13cd20bc3c2c0a1121f Mon Sep 17 00:00:00 2001
-From: Mike Gorse <mgorse@suse.com>
-Date: Wed, 10 Apr 2013 17:40:47 +0000
-Subject: Add NULL check to fix crash when receiving a dbus reply after cleanup
-
----
-diff --git a/atk-adaptor/bridge.c b/atk-adaptor/bridge.c
-index 9683e18..b016da6 100644
---- a/atk-adaptor/bridge.c
-+++ b/atk-adaptor/bridge.c
-@@ -88,6 +88,9 @@ tally_event_reply ()
- {
-   static int replies_received = 0;
-+  if (!spi_global_app_data)
-+    return;
-+
-   replies_received++;
-   if (replies_received == 3)
-   {
---
-cgit v0.9.1