1 /* 2 * Copyright (C) 2009 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 #include <errno.h> 21 #include <glib.h> 22 #include <glib/gstdio.h> 23 #include <gtk/gtk.h> 24 #include <unistd.h> 25 #include <webkit/webkit.h> 26 27 #if GTK_CHECK_VERSION(2, 14, 0) 28 29 static const char* centeredContents = "<html><body><p style='text-align: center;'>Short line</p><p style='text-align: center;'>Long-size line with some foo bar baz content</p><p style='text-align: center;'>Short line</p><p style='text-align: center;'>This is a multi-line paragraph<br />where the first line<br />is the biggest one</p></body></html>"; 30 31 static const char* contents = "<html><body><p>This is a test. This is the second sentence. And this the third.</p></body></html>"; 32 33 static const char* contentsWithNewlines = "<html><body><p>This is a test. \n\nThis\n is the second sentence. And this the third.</p></body></html>"; 34 35 static const char* contentsWithSpecialChars = "<html><body><p>« This is a paragraph with “special” characters inside. »</p></body></html>"; 36 37 static const char* contentsInTextarea = "<html><body><textarea cols='80'>This is a test. This is the second sentence. And this the third.</textarea></body></html>"; 38 39 static const char* contentsInTextInput = "<html><body><input type='text' size='80' value='This is a test. This is the second sentence. And this the third.'/></body></html>"; 40 41 static const char* contentsInParagraphAndBodySimple = "<html><body><p>This is a test.</p>Hello world.</body></html>"; 42 43 static const char* contentsInParagraphAndBodyModerate = "<html><body><p>This is a test.</p>Hello world.<br /><font color='#00cc00'>This sentence is green.</font><br />This one is not.</body></html>"; 44 45 static const char* contentsInTable = "<html><body><table><tr><td>foo</td><td>bar</td></tr></table></body></html>"; 46 47 static 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>"; 48 49 static const char* contentsWithExtraneousWhiteSpaces = "<html><head><body><p>This\n paragraph\n is\n borked!</p></body></html>"; 50 51 static const char* comboBoxSelector = "<html><body><select><option selected value='foo'>foo</option><option value='bar'>bar</option></select></body></html>"; 52 53 static const char* embeddedObjects = "<html><body><p>Choose: <input value='foo' type='checkbox'/>foo <input value='bar' type='checkbox'/>bar (pick one)</p><p>Choose: <select name='foo'><option>bar</option><option>baz</option></select> (pick one)</p><p><input name='foobarbutton' value='foobar' type='button'/></p></body></html>"; 54 55 static const char* formWithTextInputs = "<html><body><form><input type='text' name='entry' /></form></body></html>"; 56 57 static const char* hypertextAndHyperlinks = "<html><body><p>A paragraph with no links at all</p><p><a href='http://foo.bar.baz/'>A line</a> with <a href='http://bar.baz.foo/'>a link in the middle</a> as well as at the beginning and <a href='http://baz.foo.bar/'>at the end</a></p><ol><li>List item with a <span><a href='http://foo.bar.baz/'>link inside a span node</a></span></li></ol></body></html>"; 58 59 static const char* layoutAndDataTables = "<html><body><table><tr><th>Odd</th><th>Even</th></tr><tr><td>1</td><td>2</td></tr></table><table><tr><td>foo</td><td>bar</td></tr></table></body></html>"; 60 61 static const char* linksWithInlineImages = "<html><head><style>a.http:before {content: url(no-image.png);}</style><body><p><a class='http' href='foo'>foo</a> bar baz</p><p>foo <a class='http' href='bar'>bar</a> baz</p><p>foo bar <a class='http' href='baz'>baz</a></p></body></html>"; 62 63 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>"; 64 65 static const char* textForCaretBrowsing = "<html><body><h1>A text header</h1><p>A paragraph <a href='http://foo.bar.baz/'>with a link</a> in the middle</p><ol><li>A list item</li></ol><select><option selected value='foo'>An option in a combo box</option></select></body></html>"; 66 67 static 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><ol><li>A list item</li></ol><select></body></html>"; 68 69 static 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>"; 70 71 static void waitForAccessibleObjects() 72 { 73 /* Manually spin the main context to make sure the accessible 74 objects are properly created before continuing. */ 75 while (g_main_context_pending(0)) 76 g_main_context_iteration(0, TRUE); 77 } 78 79 typedef gchar* (*AtkGetTextFunction) (AtkText*, gint, AtkTextBoundary, gint*, gint*); 80 81 static void testGetTextFunction(AtkText* textObject, AtkGetTextFunction fn, AtkTextBoundary boundary, gint offset, const char* textResult, gint startOffsetResult, gint endOffsetResult) 82 { 83 gint startOffset; 84 gint endOffset; 85 char* text = fn(textObject, offset, boundary, &startOffset, &endOffset); 86 g_assert_cmpstr(text, ==, textResult); 87 g_assert_cmpint(startOffset, ==, startOffsetResult); 88 g_assert_cmpint(endOffset, ==, endOffsetResult); 89 g_free(text); 90 } 91 92 static void runGetTextTests(AtkText* textObject) 93 { 94 char* text = atk_text_get_text(textObject, 0, -1); 95 g_assert_cmpstr(text, ==, "This is a test. This is the second sentence. And this the third."); 96 g_free(text); 97 98 /* ATK_TEXT_BOUNDARY_CHAR */ 99 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_CHAR, 100 0, "T", 0, 1); 101 102 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_CHAR, 103 0, "h", 1, 2); 104 105 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 106 0, "", 0, 0); 107 108 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_CHAR, 109 1, "T", 0, 1); 110 111 /* ATK_TEXT_BOUNDARY_WORD_START */ 112 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 113 0, "This ", 0, 5); 114 115 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 116 4, "This ", 0, 5); 117 118 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 119 10, "test. ", 10, 16); 120 121 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_START, 122 58, "third.", 58, 64); 123 124 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 125 5, "This ", 0, 5); 126 127 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_START, 128 7, "This ", 0, 5); 129 130 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 131 0, "is ", 5, 8); 132 133 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 134 4, "is ", 5, 8); 135 136 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_START, 137 3, "is ", 5, 8); 138 139 /* ATK_TEXT_BOUNDARY_WORD_END */ 140 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 141 0, "This", 0, 4); 142 143 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 144 4, " is", 4, 7); 145 146 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 147 5, " is", 4, 7); 148 149 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 150 9, " test", 9, 14); 151 152 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 153 5, "This", 0, 4); 154 155 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 156 4, "This", 0, 4); 157 158 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_WORD_END, 159 7, " is", 4, 7); 160 161 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 162 5, " a", 7, 9); 163 164 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_WORD_END, 165 4, " a", 7, 9); 166 167 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_WORD_END, 168 58, " third", 57, 63); 169 170 /* ATK_TEXT_BOUNDARY_SENTENCE_START */ 171 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 172 0, "This is a test. ", 0, 16); 173 174 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 175 15, "This is a test. ", 0, 16); 176 177 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 178 0, "This is the second sentence. ", 16, 45); 179 180 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 181 15, "This is the second sentence. ", 16, 45); 182 183 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 184 16, "This is a test. ", 0, 16); 185 186 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 187 44, "This is a test. ", 0, 16); 188 189 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_START, 190 15, "", 0, 0); 191 192 /* ATK_TEXT_BOUNDARY_SENTENCE_END */ 193 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 194 0, "This is a test.", 0, 15); 195 196 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 197 15, " This is the second sentence.", 15, 44); 198 199 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 200 16, " This is the second sentence.", 15, 44); 201 202 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 203 17, " This is the second sentence.", 15, 44); 204 205 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 206 0, " This is the second sentence.", 15, 44); 207 208 testGetTextFunction(textObject, atk_text_get_text_after_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 209 15, " And this the third.", 44, 64); 210 211 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 212 16, "This is a test.", 0, 15); 213 214 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 215 15, "This is a test.", 0, 15); 216 217 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 218 14, "", 0, 0); 219 220 testGetTextFunction(textObject, atk_text_get_text_before_offset, ATK_TEXT_BOUNDARY_SENTENCE_END, 221 44, " This is the second sentence.", 15, 44); 222 223 /* It's trick to test these properly right now, since our a11y 224 implementation splits different lines in different a11y items. */ 225 /* ATK_TEXT_BOUNDARY_LINE_START */ 226 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 227 0, "This is a test. This is the second sentence. And this the third.", 0, 64); 228 229 /* ATK_TEXT_BOUNDARY_LINE_END */ 230 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 231 0, "This is a test. This is the second sentence. And this the third.", 0, 64); 232 } 233 234 static void testWebkitAtkCaretOffsets() 235 { 236 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 237 g_object_ref_sink(webView); 238 GtkAllocation allocation = { 0, 0, 800, 600 }; 239 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 240 webkit_web_view_load_string(webView, textForCaretBrowsing, 0, 0, 0); 241 242 /* Wait for the accessible objects to be created. */ 243 waitForAccessibleObjects(); 244 245 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 246 g_assert(object); 247 248 AtkObject* header = atk_object_ref_accessible_child(object, 0); 249 g_assert(ATK_IS_TEXT(header)); 250 gchar* text = atk_text_get_text(ATK_TEXT(header), 0, -1); 251 g_assert_cmpstr(text, ==, "A text header"); 252 g_free (text); 253 254 /* It should be possible to place the caret inside a header. */ 255 gboolean result = atk_text_set_caret_offset(ATK_TEXT(header), 5); 256 g_assert_cmpint(result, ==, TRUE); 257 gint offset = atk_text_get_caret_offset(ATK_TEXT(header)); 258 g_assert_cmpint(offset, ==, 5); 259 260 AtkObject* paragraph = atk_object_ref_accessible_child(object, 1); 261 g_assert(ATK_IS_TEXT(paragraph)); 262 text = atk_text_get_text(ATK_TEXT(paragraph), 0, -1); 263 g_assert_cmpstr(text, ==, "A paragraph with a link in the middle"); 264 g_free (text); 265 266 /* It should be possible to place the caret inside a paragraph and a link. */ 267 result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 5); 268 g_assert_cmpint(result, ==, TRUE); 269 offset = atk_text_get_caret_offset(ATK_TEXT(paragraph)); 270 g_assert_cmpint(offset, ==, 5); 271 272 result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 20); 273 g_assert_cmpint(result, ==, TRUE); 274 offset = atk_text_get_caret_offset(ATK_TEXT(paragraph)); 275 g_assert_cmpint(offset, ==, 20); 276 277 result = atk_text_set_caret_offset(ATK_TEXT(paragraph), 30); 278 g_assert_cmpint(result, ==, TRUE); 279 offset = atk_text_get_caret_offset(ATK_TEXT(paragraph)); 280 g_assert_cmpint(offset, ==, 30); 281 282 AtkObject* list = atk_object_ref_accessible_child(object, 2); 283 g_assert(ATK_OBJECT(list)); 284 g_assert(atk_object_get_role(list) == ATK_ROLE_LIST); 285 g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 1); 286 287 AtkObject* listItem = atk_object_ref_accessible_child(list, 0); 288 g_assert(ATK_IS_TEXT(listItem)); 289 text = atk_text_get_text(ATK_TEXT(listItem), 0, -1); 290 g_assert_cmpstr(text, ==, "1. A list item"); 291 g_free (text); 292 293 /* It's not possible to place the caret inside an item's marker. */ 294 result = atk_text_set_caret_offset(ATK_TEXT(listItem), 1); 295 g_assert_cmpint(result, ==, FALSE); 296 297 /* It should be possible to place the caret inside an item's text. */ 298 result = atk_text_set_caret_offset(ATK_TEXT(listItem), 5); 299 g_assert_cmpint(result, ==, TRUE); 300 offset = atk_text_get_caret_offset(ATK_TEXT(listItem)); 301 g_assert_cmpint(offset, ==, 5); 302 303 AtkObject* panel = atk_object_ref_accessible_child(object, 3); 304 g_assert(ATK_IS_OBJECT(panel)); 305 g_assert(atk_object_get_role(panel) == ATK_ROLE_PANEL); 306 307 AtkObject* comboBox = atk_object_ref_accessible_child(panel, 0); 308 g_assert(ATK_IS_OBJECT(comboBox)); 309 g_assert(atk_object_get_role(comboBox) == ATK_ROLE_COMBO_BOX); 310 311 AtkObject* menuPopup = atk_object_ref_accessible_child(comboBox, 0); 312 g_assert(ATK_IS_OBJECT(menuPopup)); 313 g_assert(atk_object_get_role(menuPopup) == ATK_ROLE_MENU); 314 315 AtkObject* comboBoxOption = atk_object_ref_accessible_child(menuPopup, 0); 316 g_assert(ATK_IS_OBJECT(comboBoxOption)); 317 g_assert(atk_object_get_role(comboBoxOption) == ATK_ROLE_MENU_ITEM); 318 g_assert(ATK_IS_TEXT(comboBoxOption)); 319 text = atk_text_get_text(ATK_TEXT(comboBoxOption), 0, -1); 320 g_assert_cmpstr(text, ==, "An option in a combo box"); 321 322 /* It's not possible to place the caret inside an option for a combobox. */ 323 result = atk_text_set_caret_offset(ATK_TEXT(comboBoxOption), 1); 324 g_assert_cmpint(result, ==, FALSE); 325 326 g_object_unref(header); 327 g_object_unref(paragraph); 328 g_object_unref(list); 329 g_object_unref(listItem); 330 g_object_unref(panel); 331 g_object_unref(comboBox); 332 g_object_unref(menuPopup); 333 g_object_unref(comboBoxOption); 334 g_object_unref(webView); 335 } 336 337 static void testWebkitAtkCaretOffsetsAndExtranousWhiteSpaces() 338 { 339 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 340 g_object_ref_sink(webView); 341 GtkAllocation allocation = { 0, 0, 800, 600 }; 342 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 343 webkit_web_view_load_string(webView, contentsWithExtraneousWhiteSpaces, 0, 0, 0); 344 345 /* Wait for the accessible objects to be created. */ 346 waitForAccessibleObjects(); 347 348 /* Enable caret browsing. */ 349 WebKitWebSettings* settings = webkit_web_view_get_settings(webView); 350 g_object_set(G_OBJECT(settings), "enable-caret-browsing", TRUE, NULL); 351 webkit_web_view_set_settings(webView, settings); 352 353 /* Get to the inner AtkText object. */ 354 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 355 g_assert(object); 356 object = atk_object_ref_accessible_child(object, 0); 357 g_assert(object); 358 359 AtkText* textObject = ATK_TEXT(object); 360 g_assert(ATK_IS_TEXT(textObject)); 361 362 gchar* text = atk_text_get_text(textObject, 0, -1); 363 g_assert_cmpstr(text, ==, "This paragraph is borked!"); 364 g_free(text); 365 366 gint characterCount = atk_text_get_character_count(textObject); 367 g_assert_cmpint(characterCount, ==, 25); 368 369 gboolean result = atk_text_set_caret_offset(textObject, characterCount - 1); 370 g_assert_cmpint(result, ==, TRUE); 371 372 gint caretOffset = atk_text_get_caret_offset(textObject); 373 g_assert_cmpint(caretOffset, ==, characterCount - 1); 374 375 result = atk_text_set_caret_offset(textObject, characterCount); 376 g_assert_cmpint(result, ==, TRUE); 377 378 caretOffset = atk_text_get_caret_offset(textObject); 379 g_assert_cmpint(caretOffset, ==, characterCount); 380 381 g_object_unref(webView); 382 } 383 384 static void testWebkitAtkComboBox() 385 { 386 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 387 g_object_ref_sink(webView); 388 GtkAllocation allocation = { 0, 0, 800, 600 }; 389 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 390 webkit_web_view_load_string(webView, comboBoxSelector, 0, 0, 0); 391 392 /* Wait for the accessible objects to be created. */ 393 waitForAccessibleObjects(); 394 395 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 396 g_assert(object); 397 398 AtkObject* formObject = atk_object_ref_accessible_child(object, 0); 399 g_assert(formObject); 400 401 AtkObject* comboBox = atk_object_ref_accessible_child(formObject, 0); 402 g_assert(ATK_IS_OBJECT(comboBox)); 403 404 AtkObject* menuPopup = atk_object_ref_accessible_child(comboBox, 0); 405 g_assert(ATK_IS_OBJECT(menuPopup)); 406 407 AtkObject* item1 = atk_object_ref_accessible_child(menuPopup, 0); 408 g_assert(ATK_IS_OBJECT(item1)); 409 410 AtkObject* item2 = atk_object_ref_accessible_child(menuPopup, 1); 411 g_assert(ATK_IS_OBJECT(item2)); 412 413 /* Check roles. */ 414 g_assert(atk_object_get_role(comboBox) == ATK_ROLE_COMBO_BOX); 415 g_assert(atk_object_get_role(menuPopup) == ATK_ROLE_MENU); 416 g_assert(atk_object_get_role(item1) == ATK_ROLE_MENU_ITEM); 417 g_assert(atk_object_get_role(item2) == ATK_ROLE_MENU_ITEM); 418 419 /* Check the implementation of the AtkSelection interface. */ 420 g_assert(ATK_IS_SELECTION(comboBox)); 421 AtkSelection* atkSelection = ATK_SELECTION(comboBox); 422 g_assert_cmpint(atk_selection_get_selection_count(atkSelection), ==, 1); 423 g_assert(atk_selection_is_child_selected(atkSelection, 0)); 424 g_assert(!atk_selection_is_child_selected(atkSelection, 1)); 425 AtkObject* selectedItem = atk_selection_ref_selection(atkSelection, 0); 426 g_assert(selectedItem == item1); 427 g_object_unref(selectedItem); 428 429 /* Check the implementations of the AtkAction interface. */ 430 g_assert(ATK_IS_ACTION(comboBox)); 431 AtkAction* atkAction = ATK_ACTION(comboBox); 432 g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1); 433 g_assert(atk_action_do_action(atkAction, 0)); 434 435 g_assert(ATK_IS_ACTION(menuPopup)); 436 atkAction = ATK_ACTION(menuPopup); 437 g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1); 438 g_assert(atk_action_do_action(atkAction, 0)); 439 440 g_assert(ATK_IS_ACTION(item1)); 441 atkAction = ATK_ACTION(item1); 442 g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1); 443 g_assert(atk_action_do_action(atkAction, 0)); 444 445 g_assert(ATK_IS_ACTION(item2)); 446 atkAction = ATK_ACTION(item2); 447 g_assert_cmpint(atk_action_get_n_actions(atkAction), ==, 1); 448 g_assert(atk_action_do_action(atkAction, 0)); 449 450 /* After selecting the second item, selection should have changed. */ 451 g_assert_cmpint(atk_selection_get_selection_count(atkSelection), ==, 1); 452 g_assert(!atk_selection_is_child_selected(atkSelection, 0)); 453 g_assert(atk_selection_is_child_selected(atkSelection, 1)); 454 selectedItem = atk_selection_ref_selection(atkSelection, 0); 455 g_assert(selectedItem == item2); 456 g_object_unref(selectedItem); 457 458 /* Check the implementation of the AtkText interface. */ 459 g_assert(ATK_IS_TEXT(item1)); 460 AtkText* atkText = ATK_TEXT(item1); 461 char *text = atk_text_get_text(atkText, 0, -1); 462 g_assert_cmpstr(text, ==, "foo"); 463 g_free(text); 464 text = atk_text_get_text(atkText, 0, 2); 465 g_assert_cmpstr(text, ==, "fo"); 466 g_free(text); 467 468 g_assert(ATK_IS_TEXT(item2)); 469 atkText = ATK_TEXT(item2); 470 text = atk_text_get_text(atkText, 0, -1); 471 g_assert_cmpstr(text, ==, "bar"); 472 g_free(text); 473 text = atk_text_get_text(atkText, 1, 3); 474 g_assert_cmpstr(text, ==, "ar"); 475 g_free(text); 476 477 g_object_unref(formObject); 478 g_object_unref(comboBox); 479 g_object_unref(menuPopup); 480 g_object_unref(item1); 481 g_object_unref(item2); 482 g_object_unref(webView); 483 } 484 485 static void testWebkitAtkEmbeddedObjects() 486 { 487 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 488 g_object_ref_sink(webView); 489 GtkAllocation allocation = { 0, 0, 800, 600 }; 490 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 491 webkit_web_view_load_string(webView, embeddedObjects, 0, 0, 0); 492 493 /* Wait for the accessible objects to be created. */ 494 waitForAccessibleObjects(); 495 496 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 497 g_assert(object); 498 499 AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0)); 500 g_assert(ATK_IS_TEXT(paragraph1)); 501 g_assert(ATK_IS_HYPERTEXT(paragraph1)); 502 503 const gchar* expectedText = "Choose: \357\277\274foo \357\277\274bar (pick one)"; 504 char* text = atk_text_get_text(paragraph1, 0, -1); 505 g_assert_cmpstr(text, ==, expectedText); 506 g_free(text); 507 508 gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1)); 509 g_assert_cmpint(nLinks, ==, 2); 510 511 AtkHyperlink* hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph1), 0); 512 g_assert(ATK_HYPERLINK(hLink)); 513 AtkObject* hLinkObject = atk_hyperlink_get_object(hLink, 0); 514 g_assert(ATK_OBJECT(hLinkObject)); 515 g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_CHECK_BOX); 516 g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8); 517 g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9); 518 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1); 519 g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0); 520 521 AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1)); 522 g_assert(ATK_IS_TEXT(paragraph2)); 523 g_assert(ATK_IS_HYPERTEXT(paragraph2)); 524 525 expectedText = "Choose: \357\277\274 (pick one)"; 526 text = atk_text_get_text(paragraph2, 0, -1); 527 g_assert_cmpstr(text, ==, expectedText); 528 g_free(text); 529 530 nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2)); 531 g_assert_cmpint(nLinks, ==, 1); 532 533 hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0); 534 g_assert(ATK_HYPERLINK(hLink)); 535 hLinkObject = atk_hyperlink_get_object(hLink, 0); 536 g_assert(ATK_OBJECT(hLinkObject)); 537 g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_COMBO_BOX); 538 g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 8); 539 g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 9); 540 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1); 541 g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0); 542 543 AtkText* paragraph3 = ATK_TEXT(atk_object_ref_accessible_child(object, 2)); 544 g_assert(ATK_IS_TEXT(paragraph3)); 545 g_assert(ATK_IS_HYPERTEXT(paragraph3)); 546 547 expectedText = "\357\277\274"; 548 text = atk_text_get_text(paragraph3, 0, -1); 549 g_assert_cmpstr(text, ==, expectedText); 550 g_free(text); 551 552 nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph3)); 553 g_assert_cmpint(nLinks, ==, 1); 554 555 hLink = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph3), 0); 556 g_assert(ATK_HYPERLINK(hLink)); 557 hLinkObject = atk_hyperlink_get_object(hLink, 0); 558 g_assert(ATK_OBJECT(hLinkObject)); 559 g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_PUSH_BUTTON); 560 g_assert_cmpint(atk_hyperlink_get_start_index(hLink), ==, 0); 561 g_assert_cmpint(atk_hyperlink_get_end_index(hLink), ==, 1); 562 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink), ==, 1); 563 g_assert_cmpstr(atk_hyperlink_get_uri(hLink, 0), ==, 0); 564 565 g_object_unref(paragraph1); 566 g_object_unref(paragraph2); 567 g_object_unref(paragraph3); 568 g_object_unref(webView); 569 } 570 571 static void testWebkitAtkGetTextAtOffsetForms() 572 { 573 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 574 g_object_ref_sink(webView); 575 GtkAllocation allocation = { 0, 0, 800, 600 }; 576 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 577 webkit_web_view_load_string(webView, contents, 0, 0, 0); 578 579 /* Wait for the accessible objects to be created. */ 580 waitForAccessibleObjects(); 581 582 /* Get to the inner AtkText object. */ 583 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 584 g_assert(object); 585 object = atk_object_ref_accessible_child(object, 0); 586 g_assert(object); 587 588 AtkText* textObject = ATK_TEXT(object); 589 g_assert(ATK_IS_TEXT(textObject)); 590 591 runGetTextTests(textObject); 592 593 g_object_unref(webView); 594 } 595 596 static void testWebkitAtkGetTextAtOffset() 597 { 598 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 599 g_object_ref_sink(webView); 600 GtkAllocation allocation = { 0, 0, 800, 600 }; 601 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 602 webkit_web_view_load_string(webView, contents, 0, 0, 0); 603 604 /* Wait for the accessible objects to be created. */ 605 waitForAccessibleObjects(); 606 607 /* Get to the inner AtkText object. */ 608 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 609 g_assert(object); 610 object = atk_object_ref_accessible_child(object, 0); 611 g_assert(object); 612 613 AtkText* textObject = ATK_TEXT(object); 614 g_assert(ATK_IS_TEXT(textObject)); 615 616 runGetTextTests(textObject); 617 618 g_object_unref(webView); 619 } 620 621 static void testWebkitAtkGetTextAtOffsetNewlines() 622 { 623 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 624 g_object_ref_sink(webView); 625 GtkAllocation allocation = { 0, 0, 800, 600 }; 626 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 627 webkit_web_view_load_string(webView, contentsWithNewlines, 0, 0, 0); 628 629 /* Wait for the accessible objects to be created. */ 630 waitForAccessibleObjects(); 631 632 /* Get to the inner AtkText object. */ 633 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 634 g_assert(object); 635 object = atk_object_ref_accessible_child(object, 0); 636 g_assert(object); 637 638 AtkText* textObject = ATK_TEXT(object); 639 g_assert(ATK_IS_TEXT(textObject)); 640 641 runGetTextTests(textObject); 642 643 g_object_unref(webView); 644 } 645 646 static void testWebkitAtkGetTextAtOffsetTextarea() 647 { 648 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 649 g_object_ref_sink(webView); 650 GtkAllocation allocation = { 0, 0, 800, 600 }; 651 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 652 webkit_web_view_load_string(webView, contentsInTextarea, 0, 0, 0); 653 654 /* Wait for the accessible objects to be created. */ 655 waitForAccessibleObjects(); 656 657 /* Get to the inner AtkText object. */ 658 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 659 g_assert(object); 660 object = atk_object_ref_accessible_child(object, 0); 661 g_assert(object); 662 object = atk_object_ref_accessible_child(object, 0); 663 g_assert(object); 664 665 AtkText* textObject = ATK_TEXT(object); 666 g_assert(ATK_IS_TEXT(textObject)); 667 668 runGetTextTests(textObject); 669 670 g_object_unref(webView); 671 } 672 673 static void testWebkitAtkGetTextAtOffsetTextInput() 674 { 675 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 676 g_object_ref_sink(webView); 677 GtkAllocation allocation = { 0, 0, 800, 600 }; 678 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 679 webkit_web_view_load_string(webView, contentsInTextInput, 0, 0, 0); 680 681 /* Wait for the accessible objects to be created. */ 682 waitForAccessibleObjects(); 683 684 /* Get to the inner AtkText object. */ 685 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 686 g_assert(object); 687 object = atk_object_ref_accessible_child(object, 0); 688 g_assert(object); 689 object = atk_object_ref_accessible_child(object, 0); 690 g_assert(object); 691 692 AtkText* textObject = ATK_TEXT(object); 693 g_assert(ATK_IS_TEXT(textObject)); 694 695 runGetTextTests(textObject); 696 697 g_object_unref(webView); 698 } 699 700 static void testWebkitAtkGetTextAtOffsetWithSpecialCharacters() 701 { 702 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 703 g_object_ref_sink(webView); 704 GtkAllocation allocation = { 0, 0, 800, 600 }; 705 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 706 webkit_web_view_load_string(webView, contentsWithSpecialChars, 0, 0, 0); 707 708 /* Wait for the accessible objects to be created. */ 709 waitForAccessibleObjects(); 710 711 /* Get to the inner AtkText object. */ 712 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 713 g_assert(object); 714 object = atk_object_ref_accessible_child(object, 0); 715 g_assert(object); 716 717 AtkText* textObject = ATK_TEXT(object); 718 g_assert(ATK_IS_TEXT(textObject)); 719 720 const gchar* expectedText = "\302\253\302\240This is a paragraph with \342\200\234special\342\200\235 characters inside.\302\240\302\273"; 721 char* text = atk_text_get_text(textObject, 0, -1); 722 g_assert_cmpstr(text, ==, expectedText); 723 g_free(text); 724 725 /* Check that getting the text with ATK_TEXT_BOUNDARY_LINE_START 726 and ATK_TEXT_BOUNDARY_LINE_END does not crash because of not 727 properly handling characters inside the UTF-8 string. */ 728 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_START, 0, expectedText, 0, 57); 729 testGetTextFunction(textObject, atk_text_get_text_at_offset, ATK_TEXT_BOUNDARY_LINE_END, 0, expectedText, 0, 57); 730 731 g_object_unref(webView); 732 } 733 734 static void testWebkitAtkGetTextInParagraphAndBodySimple() 735 { 736 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 737 g_object_ref_sink(webView); 738 GtkAllocation allocation = { 0, 0, 800, 600 }; 739 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 740 webkit_web_view_load_string(webView, contentsInParagraphAndBodySimple, 0, 0, 0); 741 742 /* Wait for the accessible objects to be created. */ 743 waitForAccessibleObjects(); 744 745 /* Get to the inner AtkText object. */ 746 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 747 g_assert(object); 748 AtkObject* object1 = atk_object_ref_accessible_child(object, 0); 749 g_assert(object1); 750 AtkObject* object2 = atk_object_ref_accessible_child(object, 1); 751 g_assert(object2); 752 753 AtkText* textObject1 = ATK_TEXT(object1); 754 g_assert(ATK_IS_TEXT(textObject1)); 755 AtkText* textObject2 = ATK_TEXT(object2); 756 g_assert(ATK_IS_TEXT(textObject2)); 757 758 char *text = atk_text_get_text(textObject1, 0, -1); 759 g_assert_cmpstr(text, ==, "This is a test."); 760 761 text = atk_text_get_text(textObject2, 0, 12); 762 g_assert_cmpstr(text, ==, "Hello world."); 763 764 g_object_unref(object1); 765 g_object_unref(object2); 766 g_object_unref(webView); 767 } 768 769 static void testWebkitAtkGetTextInParagraphAndBodyModerate() 770 { 771 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 772 g_object_ref_sink(webView); 773 GtkAllocation allocation = { 0, 0, 800, 600 }; 774 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 775 webkit_web_view_load_string(webView, contentsInParagraphAndBodyModerate, 0, 0, 0); 776 777 /* Wait for the accessible objects to be created. */ 778 waitForAccessibleObjects(); 779 780 /* Get to the inner AtkText object. */ 781 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 782 g_assert(object); 783 AtkObject* object1 = atk_object_ref_accessible_child(object, 0); 784 g_assert(object1); 785 AtkObject* object2 = atk_object_ref_accessible_child(object, 1); 786 g_assert(object2); 787 788 AtkText* textObject1 = ATK_TEXT(object1); 789 g_assert(ATK_IS_TEXT(textObject1)); 790 AtkText* textObject2 = ATK_TEXT(object2); 791 g_assert(ATK_IS_TEXT(textObject2)); 792 793 char *text = atk_text_get_text(textObject1, 0, -1); 794 g_assert_cmpstr(text, ==, "This is a test."); 795 796 text = atk_text_get_text(textObject2, 0, 53); 797 g_assert_cmpstr(text, ==, "Hello world.\nThis sentence is green.\nThis one is not."); 798 799 g_object_unref(object1); 800 g_object_unref(object2); 801 g_object_unref(webView); 802 } 803 804 static void testWebkitAtkGetTextInTable() 805 { 806 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 807 g_object_ref_sink(webView); 808 GtkAllocation allocation = { 0, 0, 800, 600 }; 809 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 810 webkit_web_view_load_string(webView, contentsInTable, 0, 0, 0); 811 812 /* Wait for the accessible objects to be created. */ 813 waitForAccessibleObjects(); 814 815 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 816 g_assert(object); 817 object = atk_object_ref_accessible_child(object, 0); 818 g_assert(object); 819 820 /* Tables should not implement AtkText. */ 821 g_assert(!G_TYPE_INSTANCE_GET_INTERFACE(object, ATK_TYPE_TEXT, AtkTextIface)); 822 823 g_object_unref(object); 824 g_object_unref(webView); 825 } 826 827 static void testWebkitAtkGetHeadersInTable() 828 { 829 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 830 g_object_ref_sink(webView); 831 GtkAllocation allocation = { 0, 0, 800, 600 }; 832 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 833 webkit_web_view_load_string(webView, contentsInTableWithHeaders, 0, 0, 0); 834 835 /* Wait for the accessible objects to be created. */ 836 waitForAccessibleObjects(); 837 838 AtkObject* axWebView = gtk_widget_get_accessible(GTK_WIDGET(webView)); 839 g_assert(axWebView); 840 841 /* Check table with both column and row headers. */ 842 AtkObject* table = atk_object_ref_accessible_child(axWebView, 0); 843 g_assert(table); 844 g_assert(atk_object_get_role(table) == ATK_ROLE_TABLE); 845 846 AtkObject* colHeader = atk_table_get_column_header(ATK_TABLE(table), 0); 847 g_assert(colHeader); 848 g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL); 849 g_assert(atk_object_get_index_in_parent(colHeader) == 0); 850 851 colHeader = atk_table_get_column_header(ATK_TABLE(table), 1); 852 g_assert(colHeader); 853 g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL); 854 g_assert(atk_object_get_index_in_parent(colHeader) == 1); 855 856 colHeader = atk_table_get_column_header(ATK_TABLE(table), 2); 857 g_assert(colHeader); 858 g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL); 859 g_assert(atk_object_get_index_in_parent(colHeader) == 2); 860 861 colHeader = atk_table_get_column_header(ATK_TABLE(table), 3); 862 g_assert(colHeader); 863 g_assert(atk_object_get_role(colHeader) == ATK_ROLE_TABLE_CELL); 864 g_assert(atk_object_get_index_in_parent(colHeader) == 2); 865 866 AtkObject* rowHeader = atk_table_get_row_header(ATK_TABLE(table), 0); 867 g_assert(rowHeader); 868 g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL); 869 g_assert(atk_object_get_index_in_parent(rowHeader) == 0); 870 871 rowHeader = atk_table_get_row_header(ATK_TABLE(table), 1); 872 g_assert(rowHeader); 873 g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL); 874 g_assert(atk_object_get_index_in_parent(rowHeader) == 3); 875 876 rowHeader = atk_table_get_row_header(ATK_TABLE(table), 2); 877 g_assert(rowHeader); 878 g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL); 879 g_assert(atk_object_get_index_in_parent(rowHeader) == 7); 880 881 rowHeader = atk_table_get_row_header(ATK_TABLE(table), 3); 882 g_assert(rowHeader); 883 g_assert(atk_object_get_role(rowHeader) == ATK_ROLE_TABLE_CELL); 884 g_assert(atk_object_get_index_in_parent(rowHeader) == 7); 885 886 g_object_unref(table); 887 888 /* Check table with no headers at all. */ 889 table = atk_object_ref_accessible_child(axWebView, 1); 890 g_assert(table); 891 g_assert(atk_object_get_role(table) == ATK_ROLE_TABLE); 892 893 colHeader = atk_table_get_column_header(ATK_TABLE(table), 0); 894 g_assert(colHeader == 0); 895 896 colHeader = atk_table_get_column_header(ATK_TABLE(table), 1); 897 g_assert(colHeader == 0); 898 899 rowHeader = atk_table_get_row_header(ATK_TABLE(table), 0); 900 g_assert(rowHeader == 0); 901 902 rowHeader = atk_table_get_row_header(ATK_TABLE(table), 1); 903 g_assert(rowHeader == 0); 904 905 g_object_unref(table); 906 g_object_unref(webView); 907 } 908 909 static gint compAtkAttribute(AtkAttribute* a1, AtkAttribute* a2) 910 { 911 gint strcmpVal = g_strcmp0(a1->name, a2->name); 912 if (strcmpVal) 913 return strcmpVal; 914 return g_strcmp0(a1->value, a2->value); 915 } 916 917 static gint compAtkAttributeName(AtkAttribute* a1, AtkAttribute* a2) 918 { 919 return g_strcmp0(a1->name, a2->name); 920 } 921 922 static gboolean atkAttributeSetAttributeNameHasValue(AtkAttributeSet* set, const gchar* attributeName, const gchar* value) 923 { 924 AtkAttribute at; 925 at.name = (gchar*)attributeName; 926 GSList* element = g_slist_find_custom(set, &at, (GCompareFunc)compAtkAttributeName); 927 return element && !g_strcmp0(((AtkAttribute*)(element->data))->value, value); 928 } 929 930 static gboolean atkAttributeSetContainsAttributeName(AtkAttributeSet* set, const gchar* attributeName) 931 { 932 AtkAttribute at; 933 at.name = (gchar*)attributeName; 934 return g_slist_find_custom(set, &at, (GCompareFunc)compAtkAttributeName) ? true : false; 935 } 936 937 static gboolean atkAttributeSetAttributeHasValue(AtkAttributeSet* set, AtkTextAttribute attribute, const gchar* value) 938 { 939 return atkAttributeSetAttributeNameHasValue(set, atk_text_attribute_get_name(attribute), value); 940 } 941 942 static gboolean atkAttributeSetAreEqual(AtkAttributeSet* set1, AtkAttributeSet* set2) 943 { 944 if (!set1) 945 return !set2; 946 947 set1 = g_slist_sort(set1, (GCompareFunc)compAtkAttribute); 948 set2 = g_slist_sort(set2, (GCompareFunc)compAtkAttribute); 949 950 while (set1) { 951 if (!set2 || compAtkAttribute(set1->data, set2->data)) 952 return FALSE; 953 954 set1 = set1->next; 955 set2 = set2->next; 956 } 957 958 return (!set2); 959 } 960 961 static void testWebkitAtkTextAttributes() 962 { 963 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 964 g_object_ref_sink(webView); 965 GtkAllocation allocation = { 0, 0, 800, 600 }; 966 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 967 webkit_web_view_load_string(webView, textWithAttributes, 0, 0, 0); 968 969 /* Wait for the accessible objects to be created. */ 970 waitForAccessibleObjects(); 971 972 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 973 g_assert(object); 974 975 AtkObject* child = atk_object_ref_accessible_child(object, 0); 976 g_assert(child && ATK_IS_TEXT(child)); 977 AtkText* childText = ATK_TEXT(child); 978 979 gint startOffset; 980 gint endOffset; 981 AtkAttributeSet* set1 = atk_text_get_run_attributes(childText, 0, &startOffset, &endOffset); 982 g_assert_cmpint(startOffset, ==, 0); 983 g_assert_cmpint(endOffset, ==, 12); 984 g_assert(atkAttributeSetAreEqual(set1, 0)); 985 986 AtkAttributeSet* set2 = atk_text_get_run_attributes(childText, 15, &startOffset, &endOffset); 987 g_assert_cmpint(startOffset, ==, 12); 988 g_assert_cmpint(endOffset, ==, 17); 989 g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_STYLE, "italic")); 990 991 AtkAttributeSet* set3 = atk_text_get_run_attributes(childText, 17, &startOffset, &endOffset); 992 g_assert_cmpint(startOffset, ==, 17); 993 g_assert_cmpint(endOffset, ==, 40); 994 g_assert(atkAttributeSetAttributeHasValue(set3, ATK_TEXT_ATTR_WEIGHT, "700")); 995 996 AtkAttributeSet* set4 = atk_text_get_default_attributes(childText); 997 g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_STYLE, "normal")); 998 g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_JUSTIFICATION, "right")); 999 g_assert(atkAttributeSetAttributeHasValue(set4, ATK_TEXT_ATTR_SIZE, "14")); 1000 atk_attribute_set_free(set1); 1001 atk_attribute_set_free(set2); 1002 atk_attribute_set_free(set3); 1003 atk_attribute_set_free(set4); 1004 1005 child = atk_object_ref_accessible_child(object, 1); 1006 g_assert(child && ATK_IS_TEXT(child)); 1007 childText = ATK_TEXT(child); 1008 1009 set1 = atk_text_get_default_attributes(childText); 1010 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_FAMILY_NAME, "monospace")); 1011 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STYLE, "normal")); 1012 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STRIKETHROUGH, "false")); 1013 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_WEIGHT, "400")); 1014 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_FG_COLOR, "120,121,122")); 1015 1016 set2 = atk_text_get_run_attributes(childText, 43, &startOffset, &endOffset); 1017 g_assert_cmpint(startOffset, ==, 43); 1018 g_assert_cmpint(endOffset, ==, 80); 1019 /* Checks that default attributes of text are not returned when called to atk_text_get_run_attributes. */ 1020 g_assert(!atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_FG_COLOR, "120,121,122")); 1021 g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_UNDERLINE, "single")); 1022 g_assert(atkAttributeSetAttributeHasValue(set2, ATK_TEXT_ATTR_BG_COLOR, "80,81,82")); 1023 atk_attribute_set_free(set1); 1024 atk_attribute_set_free(set2); 1025 1026 child = atk_object_ref_accessible_child(object, 2); 1027 g_assert(child && ATK_IS_TEXT(child)); 1028 childText = ATK_TEXT(child); 1029 1030 set1 = atk_text_get_run_attributes(childText, 0, &startOffset, &endOffset); 1031 set2 = atk_text_get_run_attributes(childText, 3, &startOffset, &endOffset); 1032 g_assert(atkAttributeSetAreEqual(set1, set2)); 1033 atk_attribute_set_free(set2); 1034 1035 set2 = atk_text_get_run_attributes(childText, 1, &startOffset, &endOffset); 1036 set3 = atk_text_get_run_attributes(childText, 5, &startOffset, &endOffset); 1037 g_assert(atkAttributeSetAreEqual(set2, set3)); 1038 g_assert(!atkAttributeSetAreEqual(set1, set2)); 1039 atk_attribute_set_free(set3); 1040 1041 set3 = atk_text_get_run_attributes(childText, 2, &startOffset, &endOffset); 1042 set4 = atk_text_get_run_attributes(childText, 6, &startOffset, &endOffset); 1043 g_assert(atkAttributeSetAreEqual(set3, set4)); 1044 g_assert(!atkAttributeSetAreEqual(set1, set3)); 1045 g_assert(!atkAttributeSetAreEqual(set2, set3)); 1046 atk_attribute_set_free(set1); 1047 atk_attribute_set_free(set2); 1048 atk_attribute_set_free(set3); 1049 atk_attribute_set_free(set4); 1050 1051 child = atk_object_ref_accessible_child(object, 3); 1052 g_assert(child && ATK_IS_TEXT(child)); 1053 childText = ATK_TEXT(child); 1054 set1 = atk_text_get_run_attributes(childText, 24, &startOffset, &endOffset); 1055 g_assert_cmpint(startOffset, ==, 21); 1056 g_assert_cmpint(endOffset, ==, 25); 1057 g_assert(atkAttributeSetAttributeHasValue(set1, ATK_TEXT_ATTR_STRIKETHROUGH, "true")); 1058 1059 set2 = atk_text_get_run_attributes(childText, 25, &startOffset, &endOffset); 1060 g_assert_cmpint(startOffset, ==, 25); 1061 g_assert_cmpint(endOffset, ==, 30); 1062 g_assert(atkAttributeSetAreEqual(set2, 0)); 1063 1064 set3 = atk_text_get_default_attributes(childText); 1065 g_assert(atkAttributeSetAttributeHasValue(set3, ATK_TEXT_ATTR_JUSTIFICATION, "center")); 1066 atk_attribute_set_free(set1); 1067 atk_attribute_set_free(set2); 1068 atk_attribute_set_free(set3); 1069 } 1070 1071 static void testWebkitAtkTextSelections() 1072 { 1073 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1074 g_object_ref_sink(webView); 1075 GtkAllocation allocation = { 0, 0, 800, 600 }; 1076 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1077 webkit_web_view_load_string(webView, textForSelections, 0, 0, 0); 1078 1079 /* Wait for the accessible objects to be created. */ 1080 waitForAccessibleObjects(); 1081 1082 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1083 g_assert(object); 1084 1085 AtkText* paragraph1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0)); 1086 g_assert(ATK_IS_TEXT(paragraph1)); 1087 1088 AtkText* paragraph2 = ATK_TEXT(atk_object_ref_accessible_child(object, 1)); 1089 g_assert(ATK_IS_TEXT(paragraph2)); 1090 1091 AtkText* link = ATK_TEXT(atk_object_ref_accessible_child(ATK_OBJECT(paragraph2), 0)); 1092 g_assert(ATK_IS_TEXT(link)); 1093 1094 AtkObject* list = atk_object_ref_accessible_child(object, 2); 1095 g_assert(ATK_OBJECT(list)); 1096 1097 AtkText* listItem = ATK_TEXT(atk_object_ref_accessible_child(list, 0)); 1098 g_assert(ATK_IS_TEXT(listItem)); 1099 1100 /* First paragraph (simple text). */ 1101 1102 /* Basic initial checks. */ 1103 g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0); 1104 1105 gint startOffset; 1106 gint endOffset; 1107 gchar* selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset); 1108 g_assert_cmpint(startOffset, ==, 0); 1109 g_assert_cmpint(endOffset, ==, 0); 1110 g_assert_cmpstr(selectedText, ==, 0); 1111 g_free (selectedText); 1112 1113 /* Try removing a non existing (yet) selection. */ 1114 gboolean result = atk_text_remove_selection(paragraph1, 0); 1115 g_assert(!result); 1116 1117 /* Try setting a 0-char selection. */ 1118 result = atk_text_set_selection(paragraph1, 0, 5, 5); 1119 g_assert(result); 1120 1121 /* Make a selection and test it. */ 1122 result = atk_text_set_selection(paragraph1, 0, 5, 25); 1123 g_assert(result); 1124 g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 1); 1125 selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset); 1126 g_assert_cmpint(startOffset, ==, 5); 1127 g_assert_cmpint(endOffset, ==, 25); 1128 g_assert_cmpstr(selectedText, ==, "agraph with plain te"); 1129 g_free (selectedText); 1130 /* Try removing the selection from other AtkText object (should fail). */ 1131 result = atk_text_remove_selection(paragraph2, 0); 1132 g_assert(!result); 1133 1134 /* Remove the selection and test everything again. */ 1135 result = atk_text_remove_selection(paragraph1, 0); 1136 g_assert(result); 1137 g_assert_cmpint(atk_text_get_n_selections(paragraph1), ==, 0); 1138 selectedText = atk_text_get_selection(paragraph1, 0, &startOffset, &endOffset); 1139 /* Now offsets should be the same, set to the last position of the caret. */ 1140 g_assert_cmpint(startOffset, ==, endOffset); 1141 g_assert_cmpint(startOffset, ==, 25); 1142 g_assert_cmpint(endOffset, ==, 25); 1143 g_assert_cmpstr(selectedText, ==, 0); 1144 g_free (selectedText); 1145 1146 /* Second paragraph (text + link + text). */ 1147 1148 /* Set a selection partially covering the link and test it. */ 1149 result = atk_text_set_selection(paragraph2, 0, 7, 21); 1150 g_assert(result); 1151 1152 /* Test the paragraph first. */ 1153 g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 1); 1154 selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset); 1155 g_assert_cmpint(startOffset, ==, 7); 1156 g_assert_cmpint(endOffset, ==, 21); 1157 g_assert_cmpstr(selectedText, ==, "raph with a li"); 1158 g_free (selectedText); 1159 1160 /* Now test just the link. */ 1161 g_assert_cmpint(atk_text_get_n_selections(link), ==, 1); 1162 selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset); 1163 g_assert_cmpint(startOffset, ==, 0); 1164 g_assert_cmpint(endOffset, ==, 4); 1165 g_assert_cmpstr(selectedText, ==, "a li"); 1166 g_free (selectedText); 1167 1168 /* Make a selection after the link and check selection for the whole paragraph. */ 1169 result = atk_text_set_selection(paragraph2, 0, 27, 37); 1170 g_assert(result); 1171 g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 1); 1172 selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset); 1173 g_assert_cmpint(startOffset, ==, 27); 1174 g_assert_cmpint(endOffset, ==, 37); 1175 g_assert_cmpstr(selectedText, ==, "the middle"); 1176 g_free (selectedText); 1177 1178 /* Remove selections and text everything again. */ 1179 result = atk_text_remove_selection(paragraph2, 0); 1180 g_assert(result); 1181 g_assert_cmpint(atk_text_get_n_selections(paragraph2), ==, 0); 1182 selectedText = atk_text_get_selection(paragraph2, 0, &startOffset, &endOffset); 1183 /* Now offsets should be the same (no selection). */ 1184 g_assert_cmpint(startOffset, ==, endOffset); 1185 g_assert_cmpstr(selectedText, ==, 0); 1186 g_free (selectedText); 1187 1188 g_assert_cmpint(atk_text_get_n_selections(link), ==, 0); 1189 selectedText = atk_text_get_selection(link, 0, &startOffset, &endOffset); 1190 /* Now offsets should be the same (no selection). */ 1191 g_assert_cmpint(startOffset, ==, endOffset); 1192 g_assert_cmpstr(selectedText, ==, 0); 1193 g_free (selectedText); 1194 1195 /* List item */ 1196 1197 g_assert(atk_object_get_role(list) == ATK_ROLE_LIST); 1198 g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 1); 1199 1200 gchar* text = atk_text_get_text(listItem, 0, -1); 1201 g_assert_cmpstr(text, ==, "1. A list item"); 1202 g_free (text); 1203 1204 /* It's not possible to select text inside an item's marker. */ 1205 result = atk_text_set_selection (listItem, 0, 0, 9); 1206 g_assert(!result); 1207 result = atk_text_set_selection (listItem, 0, 9, 1); 1208 g_assert(!result); 1209 1210 /* It should be possible to select text inside an item's text. */ 1211 result = atk_text_set_selection (listItem, 0, 3, 9); 1212 g_assert(result); 1213 1214 g_assert_cmpint(atk_text_get_n_selections(listItem), ==, 1); 1215 selectedText = atk_text_get_selection(listItem, 0, &startOffset, &endOffset); 1216 g_assert_cmpint(startOffset, ==, 3); 1217 g_assert_cmpint(endOffset, ==, 9); 1218 g_assert_cmpstr(selectedText, ==, "A list"); 1219 g_free (selectedText); 1220 1221 g_object_unref(paragraph1); 1222 g_object_unref(paragraph2); 1223 g_object_unref(list); 1224 g_object_unref(listItem); 1225 g_object_unref(webView); 1226 } 1227 1228 static void testWebkitAtkGetExtents() 1229 { 1230 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1231 g_object_ref_sink(webView); 1232 GtkAllocation allocation = { 0, 0, 800, 600 }; 1233 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1234 webkit_web_view_load_string(webView, centeredContents, 0, 0, 0); 1235 1236 /* Wait for the accessible objects to be created. */ 1237 waitForAccessibleObjects(); 1238 1239 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1240 g_assert(object); 1241 1242 AtkText* shortText1 = ATK_TEXT(atk_object_ref_accessible_child(object, 0)); 1243 g_assert(ATK_IS_TEXT(shortText1)); 1244 AtkText* longText = ATK_TEXT(atk_object_ref_accessible_child(object, 1)); 1245 g_assert(ATK_IS_TEXT(longText)); 1246 AtkText* shortText2 = ATK_TEXT(atk_object_ref_accessible_child(object, 2)); 1247 g_assert(ATK_IS_TEXT(shortText2)); 1248 AtkText* multilineText = ATK_TEXT(atk_object_ref_accessible_child(object, 3)); 1249 g_assert(ATK_IS_TEXT(multilineText)); 1250 1251 /* Start with window extents. */ 1252 AtkTextRectangle sline_window1, sline_window2, lline_window, mline_window; 1253 atk_text_get_range_extents(shortText1, 0, 10, ATK_XY_WINDOW, &sline_window1); 1254 atk_text_get_range_extents(longText, 0, 44, ATK_XY_WINDOW, &lline_window); 1255 atk_text_get_range_extents(shortText2, 0, 10, ATK_XY_WINDOW, &sline_window2); 1256 atk_text_get_range_extents(multilineText, 0, 60, ATK_XY_WINDOW, &mline_window); 1257 1258 /* Check vertical line position. */ 1259 g_assert_cmpint(sline_window1.y + sline_window1.height, <=, lline_window.y); 1260 g_assert_cmpint(lline_window.y + lline_window.height + sline_window2.height, <=, mline_window.y); 1261 1262 /* Paragraphs 1 and 3 have identical text and alignment. */ 1263 g_assert_cmpint(sline_window1.x, ==, sline_window2.x); 1264 g_assert_cmpint(sline_window1.width, ==, sline_window2.width); 1265 g_assert_cmpint(sline_window1.height, ==, sline_window2.height); 1266 1267 /* All lines should be the same height; line 2 is the widest line. */ 1268 g_assert_cmpint(sline_window1.height, ==, lline_window.height); 1269 g_assert_cmpint(sline_window1.width, <, lline_window.width); 1270 1271 /* Make sure the character extents jive with the range extents. */ 1272 gint x; 1273 gint y; 1274 gint width; 1275 gint height; 1276 1277 /* First paragraph (short text). */ 1278 atk_text_get_character_extents(shortText1, 0, &x, &y, &width, &height, ATK_XY_WINDOW); 1279 g_assert_cmpint(x, ==, sline_window1.x); 1280 g_assert_cmpint(y, ==, sline_window1.y); 1281 g_assert_cmpint(height, ==, sline_window1.height); 1282 1283 atk_text_get_character_extents(shortText1, 9, &x, &y, &width, &height, ATK_XY_WINDOW); 1284 g_assert_cmpint(x, ==, sline_window1.x + sline_window1.width - width); 1285 g_assert_cmpint(y, ==, sline_window1.y); 1286 g_assert_cmpint(height, ==, sline_window1.height); 1287 1288 /* Second paragraph (long text). */ 1289 atk_text_get_character_extents(longText, 0, &x, &y, &width, &height, ATK_XY_WINDOW); 1290 g_assert_cmpint(x, ==, lline_window.x); 1291 g_assert_cmpint(y, ==, lline_window.y); 1292 g_assert_cmpint(height, ==, lline_window.height); 1293 1294 atk_text_get_character_extents(longText, 43, &x, &y, &width, &height, ATK_XY_WINDOW); 1295 g_assert_cmpint(x, ==, lline_window.x + lline_window.width - width); 1296 g_assert_cmpint(y, ==, lline_window.y); 1297 g_assert_cmpint(height, ==, lline_window.height); 1298 1299 /* Third paragraph (short text). */ 1300 atk_text_get_character_extents(shortText2, 0, &x, &y, &width, &height, ATK_XY_WINDOW); 1301 g_assert_cmpint(x, ==, sline_window2.x); 1302 g_assert_cmpint(y, ==, sline_window2.y); 1303 g_assert_cmpint(height, ==, sline_window2.height); 1304 1305 atk_text_get_character_extents(shortText2, 9, &x, &y, &width, &height, ATK_XY_WINDOW); 1306 g_assert_cmpint(x, ==, sline_window2.x + sline_window2.width - width); 1307 g_assert_cmpint(y, ==, sline_window2.y); 1308 g_assert_cmpint(height, ==, sline_window2.height); 1309 1310 /* Four paragraph (3 lines multi-line text). */ 1311 atk_text_get_character_extents(multilineText, 0, &x, &y, &width, &height, ATK_XY_WINDOW); 1312 g_assert_cmpint(x, ==, mline_window.x); 1313 g_assert_cmpint(y, ==, mline_window.y); 1314 g_assert_cmpint(3 * height, ==, mline_window.height); 1315 1316 atk_text_get_character_extents(multilineText, 59, &x, &y, &width, &height, ATK_XY_WINDOW); 1317 /* Last line won't fill the whole width of the rectangle. */ 1318 g_assert_cmpint(x, <=, mline_window.x + mline_window.width - width); 1319 g_assert_cmpint(y, ==, mline_window.y + mline_window.height - height); 1320 g_assert_cmpint(height, <=, mline_window.height); 1321 1322 /* Check that extent for a full line are the same height than for 1323 a partial section of the same line */ 1324 gint startOffset; 1325 gint endOffset; 1326 gchar* text = atk_text_get_text_at_offset(multilineText, 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset); 1327 g_free(text); 1328 1329 AtkTextRectangle fline_window; 1330 AtkTextRectangle afline_window; 1331 atk_text_get_range_extents(multilineText, startOffset, endOffset, ATK_XY_WINDOW, &fline_window); 1332 atk_text_get_range_extents(multilineText, startOffset, endOffset - 1, ATK_XY_WINDOW, &afline_window); 1333 g_assert_cmpint(fline_window.x, ==, afline_window.x); 1334 g_assert_cmpint(fline_window.y, ==, afline_window.y); 1335 g_assert_cmpint(fline_window.height, ==, afline_window.height); 1336 1337 g_object_unref(shortText1); 1338 g_object_unref(shortText2); 1339 g_object_unref(longText); 1340 g_object_unref(multilineText); 1341 g_object_unref(webView); 1342 } 1343 1344 static void testWebkitAtkLayoutAndDataTables() 1345 { 1346 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1347 g_object_ref_sink(webView); 1348 GtkAllocation allocation = { 0, 0, 800, 600 }; 1349 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1350 webkit_web_view_load_string(webView, layoutAndDataTables, 0, 0, 0); 1351 1352 /* Wait for the accessible objects to be created. */ 1353 waitForAccessibleObjects(); 1354 1355 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1356 g_assert(object); 1357 1358 /* Check the non-layout table (data table). */ 1359 1360 AtkObject* table1 = atk_object_ref_accessible_child(object, 0); 1361 g_assert(ATK_IS_TABLE(table1)); 1362 AtkAttributeSet* set1 = atk_object_get_attributes(table1); 1363 g_assert(set1); 1364 g_assert(!atkAttributeSetContainsAttributeName(set1, "layout-guess")); 1365 atk_attribute_set_free(set1); 1366 1367 /* Check the layout table. */ 1368 1369 AtkObject* table2 = atk_object_ref_accessible_child(object, 1); 1370 g_assert(ATK_IS_TABLE(table2)); 1371 AtkAttributeSet* set2 = atk_object_get_attributes(table2); 1372 g_assert(set2); 1373 g_assert(atkAttributeSetContainsAttributeName(set2, "layout-guess")); 1374 g_assert(atkAttributeSetAttributeNameHasValue(set2, "layout-guess", "true")); 1375 atk_attribute_set_free(set2); 1376 1377 g_object_unref(table1); 1378 g_object_unref(table2); 1379 g_object_unref(webView); 1380 } 1381 1382 static void testWebkitAtkLinksWithInlineImages() 1383 { 1384 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1385 g_object_ref_sink(webView); 1386 GtkAllocation allocation = { 0, 0, 800, 600 }; 1387 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1388 webkit_web_view_load_string(webView, linksWithInlineImages, 0, 0, 0); 1389 1390 /* Wait for the accessible objects to be created. */ 1391 waitForAccessibleObjects(); 1392 1393 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1394 g_assert(object); 1395 1396 /* First paragraph (link at the beginning). */ 1397 AtkObject* paragraph = atk_object_ref_accessible_child(object, 0); 1398 g_assert(ATK_IS_TEXT(paragraph)); 1399 gint startOffset; 1400 gint endOffset; 1401 gchar* text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset); 1402 g_assert(text); 1403 g_assert_cmpstr(text, ==, "foo bar baz"); 1404 g_assert_cmpint(startOffset, ==, 0); 1405 g_assert_cmpint(endOffset, ==, 11); 1406 g_free(text); 1407 g_object_unref(paragraph); 1408 1409 /* Second paragraph (link in the middle). */ 1410 paragraph = atk_object_ref_accessible_child(object, 1); 1411 g_assert(ATK_IS_TEXT(paragraph)); 1412 text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset); 1413 g_assert(text); 1414 g_assert_cmpstr(text, ==, "foo bar baz"); 1415 g_assert_cmpint(startOffset, ==, 0); 1416 g_assert_cmpint(endOffset, ==, 11); 1417 g_free(text); 1418 g_object_unref(paragraph); 1419 1420 /* Third paragraph (link at the end). */ 1421 paragraph = atk_object_ref_accessible_child(object, 2); 1422 g_assert(ATK_IS_TEXT(paragraph)); 1423 text = atk_text_get_text_at_offset(ATK_TEXT(paragraph), 0, ATK_TEXT_BOUNDARY_LINE_START, &startOffset, &endOffset); 1424 g_assert(text); 1425 g_assert_cmpstr(text, ==, "foo bar baz"); 1426 g_assert_cmpint(startOffset, ==, 0); 1427 g_assert_cmpint(endOffset, ==, 11); 1428 g_free(text); 1429 g_object_unref(paragraph); 1430 1431 g_object_unref(webView); 1432 } 1433 1434 static void testWebkitAtkHypertextAndHyperlinks() 1435 { 1436 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1437 g_object_ref_sink(webView); 1438 GtkAllocation allocation = { 0, 0, 800, 600 }; 1439 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1440 webkit_web_view_load_string(webView, hypertextAndHyperlinks, 0, 0, 0); 1441 1442 /* Wait for the accessible objects to be created. */ 1443 waitForAccessibleObjects(); 1444 1445 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1446 g_assert(object); 1447 1448 AtkObject* paragraph1 = atk_object_ref_accessible_child(object, 0); 1449 g_assert(ATK_OBJECT(paragraph1)); 1450 g_assert(atk_object_get_role(paragraph1) == ATK_ROLE_PARAGRAPH); 1451 g_assert(ATK_IS_HYPERTEXT(paragraph1)); 1452 1453 /* No links in the first paragraph. */ 1454 gint nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph1)); 1455 g_assert_cmpint(nLinks, ==, 0); 1456 1457 AtkObject* paragraph2 = atk_object_ref_accessible_child(object, 1); 1458 g_assert(ATK_OBJECT(paragraph2)); 1459 g_assert(atk_object_get_role(paragraph2) == ATK_ROLE_PARAGRAPH); 1460 g_assert(ATK_IS_HYPERTEXT(paragraph2)); 1461 1462 /* Check links in the second paragraph. 1463 nLinks = atk_hypertext_get_n_links(ATK_HYPERTEXT(paragraph2)); 1464 g_assert_cmpint(nLinks, ==, 3); */ 1465 1466 AtkHyperlink* hLink1 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 0); 1467 g_assert(ATK_HYPERLINK(hLink1)); 1468 AtkObject* hLinkObject1 = atk_hyperlink_get_object(hLink1, 0); 1469 g_assert(ATK_OBJECT(hLinkObject1)); 1470 g_assert(atk_object_get_role(hLinkObject1) == ATK_ROLE_LINK); 1471 g_assert_cmpint(atk_hyperlink_get_start_index(hLink1), ==, 0); 1472 g_assert_cmpint(atk_hyperlink_get_end_index(hLink1), ==, 6); 1473 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink1), ==, 1); 1474 g_assert_cmpstr(atk_hyperlink_get_uri(hLink1, 0), ==, "http://foo.bar.baz/"); 1475 1476 AtkHyperlink* hLink2 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 1); 1477 g_assert(ATK_HYPERLINK(hLink2)); 1478 AtkObject* hLinkObject2 = atk_hyperlink_get_object(hLink2, 0); 1479 g_assert(ATK_OBJECT(hLinkObject2)); 1480 g_assert(atk_object_get_role(hLinkObject2) == ATK_ROLE_LINK); 1481 g_assert_cmpint(atk_hyperlink_get_start_index(hLink2), ==, 12); 1482 g_assert_cmpint(atk_hyperlink_get_end_index(hLink2), ==, 32); 1483 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink2), ==, 1); 1484 g_assert_cmpstr(atk_hyperlink_get_uri(hLink2, 0), ==, "http://bar.baz.foo/"); 1485 1486 AtkHyperlink* hLink3 = atk_hypertext_get_link(ATK_HYPERTEXT(paragraph2), 2); 1487 g_assert(ATK_HYPERLINK(hLink3)); 1488 AtkObject* hLinkObject3 = atk_hyperlink_get_object(hLink3, 0); 1489 g_assert(ATK_OBJECT(hLinkObject3)); 1490 g_assert(atk_object_get_role(hLinkObject3) == ATK_ROLE_LINK); 1491 g_assert_cmpint(atk_hyperlink_get_start_index(hLink3), ==, 65); 1492 g_assert_cmpint(atk_hyperlink_get_end_index(hLink3), ==, 75); 1493 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLink3), ==, 1); 1494 g_assert_cmpstr(atk_hyperlink_get_uri(hLink3, 0), ==, "http://baz.foo.bar/"); 1495 1496 AtkObject* list = atk_object_ref_accessible_child(object, 2); 1497 g_assert(ATK_OBJECT(list)); 1498 g_assert(atk_object_get_role(list) == ATK_ROLE_LIST); 1499 g_assert_cmpint(atk_object_get_n_accessible_children(list), ==, 1); 1500 1501 AtkObject* listItem = atk_object_ref_accessible_child(list, 0); 1502 g_assert(ATK_IS_TEXT(listItem)); 1503 g_assert(ATK_IS_HYPERTEXT(listItem)); 1504 1505 AtkHyperlink* hLinkInListItem = atk_hypertext_get_link(ATK_HYPERTEXT(listItem), 0); 1506 g_assert(ATK_HYPERLINK(hLinkInListItem)); 1507 AtkObject* hLinkObject = atk_hyperlink_get_object(hLinkInListItem, 0); 1508 g_assert(ATK_OBJECT(hLinkObject)); 1509 g_assert(atk_object_get_role(hLinkObject) == ATK_ROLE_LINK); 1510 g_assert_cmpint(atk_hyperlink_get_start_index(hLinkInListItem), ==, 20); 1511 g_assert_cmpint(atk_hyperlink_get_end_index(hLinkInListItem), ==, 43); 1512 g_assert_cmpint(atk_hyperlink_get_n_anchors(hLinkInListItem), ==, 1); 1513 g_assert_cmpstr(atk_hyperlink_get_uri(hLinkInListItem, 0), ==, "http://foo.bar.baz/"); 1514 1515 /* Finally check the AtkAction interface for a given AtkHyperlink. */ 1516 g_assert(ATK_IS_ACTION(hLink1)); 1517 g_assert_cmpint(atk_action_get_n_actions(ATK_ACTION(hLink1)), ==, 1); 1518 g_assert_cmpstr(atk_action_get_keybinding(ATK_ACTION(hLink1), 0), ==, ""); 1519 g_assert_cmpstr(atk_action_get_name(ATK_ACTION(hLink1), 0), ==, "jump"); 1520 g_assert(atk_action_do_action(ATK_ACTION(hLink1), 0)); 1521 1522 g_object_unref(paragraph1); 1523 g_object_unref(paragraph2); 1524 g_object_unref(list); 1525 g_object_unref(listItem); 1526 g_object_unref(webView); 1527 } 1528 1529 static void testWebkitAtkListsOfItems() 1530 { 1531 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1532 g_object_ref_sink(webView); 1533 GtkAllocation allocation = { 0, 0, 800, 600 }; 1534 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1535 webkit_web_view_load_string(webView, listsOfItems, 0, 0, 0); 1536 1537 /* Wait for the accessible objects to be created. */ 1538 waitForAccessibleObjects(); 1539 1540 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1541 g_assert(object); 1542 1543 /* Unordered list. */ 1544 1545 AtkObject* uList = atk_object_ref_accessible_child(object, 0); 1546 g_assert(ATK_OBJECT(uList)); 1547 g_assert(atk_object_get_role(uList) == ATK_ROLE_LIST); 1548 g_assert_cmpint(atk_object_get_n_accessible_children(uList), ==, 3); 1549 1550 AtkObject* item1 = atk_object_ref_accessible_child(uList, 0); 1551 g_assert(ATK_IS_TEXT(item1)); 1552 AtkObject* item2 = atk_object_ref_accessible_child(uList, 1); 1553 g_assert(ATK_IS_TEXT(item2)); 1554 AtkObject* item3 = atk_object_ref_accessible_child(uList, 2); 1555 g_assert(ATK_IS_TEXT(item3)); 1556 1557 g_assert_cmpint(atk_object_get_n_accessible_children(item1), ==, 0); 1558 g_assert_cmpint(atk_object_get_n_accessible_children(item2), ==, 1); 1559 g_assert_cmpint(atk_object_get_n_accessible_children(item3), ==, 1); 1560 1561 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item1), 0, -1), ==, "\342\200\242 text only"); 1562 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item2), 0, -1), ==, "\342\200\242 link only"); 1563 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item3), 0, -1), ==, "\342\200\242 text and a link"); 1564 1565 g_object_unref(item1); 1566 g_object_unref(item2); 1567 g_object_unref(item3); 1568 1569 /* Ordered list. */ 1570 1571 AtkObject* oList = atk_object_ref_accessible_child(object, 1); 1572 g_assert(ATK_OBJECT(oList)); 1573 g_assert(atk_object_get_role(oList) == ATK_ROLE_LIST); 1574 g_assert_cmpint(atk_object_get_n_accessible_children(oList), ==, 3); 1575 1576 item1 = atk_object_ref_accessible_child(oList, 0); 1577 g_assert(ATK_IS_TEXT(item1)); 1578 item2 = atk_object_ref_accessible_child(oList, 1); 1579 g_assert(ATK_IS_TEXT(item2)); 1580 item3 = atk_object_ref_accessible_child(oList, 2); 1581 g_assert(ATK_IS_TEXT(item3)); 1582 1583 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item1), 0, -1), ==, "1. text only"); 1584 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item2), 0, -1), ==, "2. link only"); 1585 g_assert_cmpstr(atk_text_get_text(ATK_TEXT(item3), 0, -1), ==, "3. text and a link"); 1586 1587 g_assert_cmpint(atk_object_get_n_accessible_children(item1), ==, 0); 1588 g_assert_cmpint(atk_object_get_n_accessible_children(item2), ==, 1); 1589 g_assert_cmpint(atk_object_get_n_accessible_children(item3), ==, 1); 1590 1591 g_object_unref(item1); 1592 g_object_unref(item2); 1593 g_object_unref(item3); 1594 1595 g_object_unref(uList); 1596 g_object_unref(oList); 1597 g_object_unref(webView); 1598 } 1599 1600 static gboolean textInserted = FALSE; 1601 static gboolean textDeleted = FALSE; 1602 1603 static void textChangedCb(AtkText* text, gint pos, gint len, const gchar* detail) 1604 { 1605 g_assert(text && ATK_IS_OBJECT(text)); 1606 1607 if (!g_strcmp0(detail, "insert")) 1608 textInserted = TRUE; 1609 else if (!g_strcmp0(detail, "delete")) 1610 textDeleted = TRUE; 1611 } 1612 1613 static gboolean checkTextChanges(gpointer unused) 1614 { 1615 g_assert_cmpint(textInserted, ==, TRUE); 1616 g_assert_cmpint(textDeleted, ==, TRUE); 1617 return FALSE; 1618 } 1619 1620 static void testWebkitAtkTextChangedNotifications() 1621 { 1622 WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); 1623 g_object_ref_sink(webView); 1624 GtkAllocation allocation = { 0, 0, 800, 600 }; 1625 gtk_widget_size_allocate(GTK_WIDGET(webView), &allocation); 1626 webkit_web_view_load_string(webView, formWithTextInputs, 0, 0, 0); 1627 1628 /* Wait for the accessible objects to be created. */ 1629 waitForAccessibleObjects(); 1630 1631 AtkObject* object = gtk_widget_get_accessible(GTK_WIDGET(webView)); 1632 g_assert(object); 1633 1634 AtkObject* form = atk_object_ref_accessible_child(object, 0); 1635 g_assert(ATK_IS_OBJECT(form)); 1636 1637 AtkObject* textEntry = atk_object_ref_accessible_child(form, 0); 1638 g_assert(ATK_IS_EDITABLE_TEXT(textEntry)); 1639 g_assert(atk_object_get_role(ATK_OBJECT(textEntry)) == ATK_ROLE_ENTRY); 1640 1641 g_signal_connect(textEntry, "text-changed::insert", 1642 G_CALLBACK(textChangedCb), 1643 (gpointer)"insert"); 1644 g_signal_connect(textEntry, "text-changed::delete", 1645 G_CALLBACK(textChangedCb), 1646 (gpointer)"delete"); 1647 1648 gint pos = 0; 1649 atk_editable_text_insert_text(ATK_EDITABLE_TEXT(textEntry), "foo bar baz", 11, &pos); 1650 atk_editable_text_delete_text(ATK_EDITABLE_TEXT(textEntry), 4, 7); 1651 textInserted = FALSE; 1652 textDeleted = FALSE; 1653 1654 g_idle_add((GSourceFunc)checkTextChanges, 0); 1655 1656 g_object_unref(form); 1657 g_object_unref(textEntry); 1658 g_object_unref(webView); 1659 } 1660 1661 int main(int argc, char** argv) 1662 { 1663 g_thread_init(0); 1664 gtk_test_init(&argc, &argv, 0); 1665 1666 g_test_bug_base("https://bugs.webkit.org/"); 1667 g_test_add_func("/webkit/atk/caretOffsets", testWebkitAtkCaretOffsets); 1668 g_test_add_func("/webkit/atk/caretOffsetsAndExtranousWhiteSpaces", testWebkitAtkCaretOffsetsAndExtranousWhiteSpaces); 1669 g_test_add_func("/webkit/atk/comboBox", testWebkitAtkComboBox); 1670 g_test_add_func("/webkit/atk/embeddedObjects", testWebkitAtkEmbeddedObjects); 1671 g_test_add_func("/webkit/atk/getTextAtOffset", testWebkitAtkGetTextAtOffset); 1672 g_test_add_func("/webkit/atk/getTextAtOffsetForms", testWebkitAtkGetTextAtOffsetForms); 1673 g_test_add_func("/webkit/atk/getTextAtOffsetNewlines", testWebkitAtkGetTextAtOffsetNewlines); 1674 g_test_add_func("/webkit/atk/getTextAtOffsetTextarea", testWebkitAtkGetTextAtOffsetTextarea); 1675 g_test_add_func("/webkit/atk/getTextAtOffsetTextInput", testWebkitAtkGetTextAtOffsetTextInput); 1676 g_test_add_func("/webkit/atk/getTextAtOffsetWithSpecialCharacters", testWebkitAtkGetTextAtOffsetWithSpecialCharacters); 1677 g_test_add_func("/webkit/atk/getTextInParagraphAndBodySimple", testWebkitAtkGetTextInParagraphAndBodySimple); 1678 g_test_add_func("/webkit/atk/getTextInParagraphAndBodyModerate", testWebkitAtkGetTextInParagraphAndBodyModerate); 1679 g_test_add_func("/webkit/atk/getTextInTable", testWebkitAtkGetTextInTable); 1680 g_test_add_func("/webkit/atk/getHeadersInTable", testWebkitAtkGetHeadersInTable); 1681 g_test_add_func("/webkit/atk/textAttributes", testWebkitAtkTextAttributes); 1682 g_test_add_func("/webkit/atk/textSelections", testWebkitAtkTextSelections); 1683 g_test_add_func("/webkit/atk/getExtents", testWebkitAtkGetExtents); 1684 g_test_add_func("/webkit/atk/hypertextAndHyperlinks", testWebkitAtkHypertextAndHyperlinks); 1685 g_test_add_func("/webkit/atk/layoutAndDataTables", testWebkitAtkLayoutAndDataTables); 1686 g_test_add_func("/webkit/atk/linksWithInlineImages", testWebkitAtkLinksWithInlineImages); 1687 g_test_add_func("/webkit/atk/listsOfItems", testWebkitAtkListsOfItems); 1688 g_test_add_func("/webkit/atk/textChangedNotifications", testWebkitAtkTextChangedNotifications); 1689 return g_test_run (); 1690 } 1691 1692 #else 1693 int main(int argc, char** argv) 1694 { 1695 g_critical("You will need gtk-2.14.0 to run the unit tests. Doing nothing now."); 1696 return 0; 1697 } 1698 1699 #endif 1700