1 | /* |
2 | * Copyright (C) 2012 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 Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2,1 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 "config.h" |
21 | #include "WebViewTest.h" |
22 | #include <wtf/glib/GRefPtr.h> |
23 | |
24 | class EditorTest: public WebViewTest { |
25 | public: |
26 | MAKE_GLIB_TEST_FIXTURE(EditorTest); |
27 | |
28 | static const unsigned kClipboardWaitTimeout = 50; |
29 | static const unsigned kClipboardWaitMaxTries = 2; |
30 | |
31 | EditorTest() |
32 | : m_clipboard(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)) |
33 | , m_canExecuteEditingCommand(false) |
34 | , m_triesCount(0) |
35 | , m_editorState(nullptr) |
36 | { |
37 | showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL); |
38 | gtk_clipboard_clear(m_clipboard); |
39 | } |
40 | |
41 | static gboolean webViewDrawCallback(GMainLoop* mainLoop) |
42 | { |
43 | g_main_loop_quit(mainLoop); |
44 | return FALSE; |
45 | } |
46 | |
47 | void flushEditorState() |
48 | { |
49 | auto signalID = g_signal_connect_swapped(m_webView, "draw" , G_CALLBACK(webViewDrawCallback), m_mainLoop); |
50 | gtk_widget_queue_draw(GTK_WIDGET(m_webView)); |
51 | g_main_loop_run(m_mainLoop); |
52 | g_signal_handler_disconnect(m_webView, signalID); |
53 | } |
54 | |
55 | static void canExecuteEditingCommandReadyCallback(GObject*, GAsyncResult* result, EditorTest* test) |
56 | { |
57 | GUniqueOutPtr<GError> error; |
58 | test->m_canExecuteEditingCommand = webkit_web_view_can_execute_editing_command_finish(test->m_webView, result, &error.outPtr()); |
59 | g_assert_no_error(error.get()); |
60 | g_main_loop_quit(test->m_mainLoop); |
61 | } |
62 | |
63 | bool canExecuteEditingCommand(const char* command) |
64 | { |
65 | m_canExecuteEditingCommand = false; |
66 | webkit_web_view_can_execute_editing_command(m_webView, command, 0, reinterpret_cast<GAsyncReadyCallback>(canExecuteEditingCommandReadyCallback), this); |
67 | g_main_loop_run(m_mainLoop); |
68 | |
69 | if (!strcmp(command, WEBKIT_EDITING_COMMAND_CUT)) |
70 | g_assert_cmpint(m_canExecuteEditingCommand, ==, webkit_editor_state_is_cut_available(editorState())); |
71 | else if (!strcmp(command, WEBKIT_EDITING_COMMAND_COPY)) |
72 | g_assert_cmpint(m_canExecuteEditingCommand, ==, webkit_editor_state_is_copy_available(editorState())); |
73 | else if (!strcmp(command, WEBKIT_EDITING_COMMAND_PASTE)) |
74 | g_assert_cmpint(m_canExecuteEditingCommand, ==, webkit_editor_state_is_paste_available(editorState())); |
75 | // FIXME: Figure out how to add tests for undo and redo. It will probably require using user |
76 | // scripts to message the UI process when the content has been altered. |
77 | else if (!strcmp(command, WEBKIT_EDITING_COMMAND_UNDO)) |
78 | g_assert_cmpint(m_canExecuteEditingCommand, ==, webkit_editor_state_is_undo_available(editorState())); |
79 | else if (!strcmp(command, WEBKIT_EDITING_COMMAND_REDO)) |
80 | g_assert_cmpint(m_canExecuteEditingCommand, ==, webkit_editor_state_is_redo_available(editorState())); |
81 | |
82 | return m_canExecuteEditingCommand; |
83 | } |
84 | |
85 | static gboolean waitForClipboardText(EditorTest* test) |
86 | { |
87 | test->m_triesCount++; |
88 | if (gtk_clipboard_wait_is_text_available(test->m_clipboard) || test->m_triesCount > kClipboardWaitMaxTries) { |
89 | g_main_loop_quit(test->m_mainLoop); |
90 | return FALSE; |
91 | } |
92 | |
93 | return TRUE; |
94 | } |
95 | |
96 | void copyClipboard() |
97 | { |
98 | webkit_web_view_execute_editing_command(m_webView, WEBKIT_EDITING_COMMAND_COPY); |
99 | // There's no way to know when the selection has been copied to |
100 | // the clipboard, so use a timeout source to query the clipboard. |
101 | m_triesCount = 0; |
102 | g_timeout_add(kClipboardWaitTimeout, reinterpret_cast<GSourceFunc>(waitForClipboardText), this); |
103 | g_main_loop_run(m_mainLoop); |
104 | } |
105 | |
106 | gchar* cutSelection() |
107 | { |
108 | g_assert_true(canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
109 | g_assert_true(canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
110 | |
111 | webkit_web_view_execute_editing_command(m_webView, WEBKIT_EDITING_COMMAND_CUT); |
112 | // There's no way to know when the selection has been cut to |
113 | // the clipboard, so use a timeout source to query the clipboard. |
114 | m_triesCount = 0; |
115 | g_timeout_add(kClipboardWaitTimeout, reinterpret_cast<GSourceFunc>(waitForClipboardText), this); |
116 | g_main_loop_run(m_mainLoop); |
117 | |
118 | return gtk_clipboard_wait_for_text(m_clipboard); |
119 | } |
120 | |
121 | WebKitEditorState* editorState() |
122 | { |
123 | if (m_editorState) |
124 | return m_editorState; |
125 | |
126 | m_editorState = webkit_web_view_get_editor_state(m_webView); |
127 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_editorState)); |
128 | return m_editorState; |
129 | } |
130 | |
131 | static void quitMainLoopInCallback(EditorTest* test) |
132 | { |
133 | g_main_loop_quit(test->m_mainLoop); |
134 | } |
135 | |
136 | unsigned typingAttributes() |
137 | { |
138 | return webkit_editor_state_get_typing_attributes(editorState()); |
139 | } |
140 | |
141 | unsigned waitUntilTypingAttributesChanged() |
142 | { |
143 | unsigned long handlerID = g_signal_connect_swapped(editorState(), "notify::typing-attributes" , G_CALLBACK(quitMainLoopInCallback), this); |
144 | g_main_loop_run(m_mainLoop); |
145 | g_signal_handler_disconnect(m_editorState, handlerID); |
146 | return typingAttributes(); |
147 | } |
148 | |
149 | GtkClipboard* m_clipboard; |
150 | bool m_canExecuteEditingCommand; |
151 | size_t m_triesCount; |
152 | WebKitEditorState* m_editorState; |
153 | }; |
154 | |
155 | static const char* selectedSpanHTMLFormat = |
156 | "<html><body contentEditable=\"%s\">" |
157 | "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>" |
158 | "<script>document.getSelection().removeAllRanges();\n" |
159 | "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n" |
160 | "</script></body></html>" ; |
161 | |
162 | static void testWebViewEditorCutCopyPasteNonEditable(EditorTest* test, gconstpointer) |
163 | { |
164 | // Nothing loaded yet. |
165 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
166 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY)); |
167 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
168 | |
169 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false" )); |
170 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
171 | test->waitUntilLoadFinished(); |
172 | test->flushEditorState(); |
173 | |
174 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY)); |
175 | // It's not possible to cut and paste when content is not editable |
176 | // even if there's a selection. |
177 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
178 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
179 | |
180 | test->copyClipboard(); |
181 | GUniquePtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard)); |
182 | g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull" ); |
183 | } |
184 | |
185 | static void testWebViewEditorCutCopyPasteEditable(EditorTest* test, gconstpointer) |
186 | { |
187 | // Nothing loaded yet. |
188 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
189 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY)); |
190 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
191 | |
192 | g_assert_false(test->isEditable()); |
193 | test->setEditable(true); |
194 | g_assert_true(test->isEditable()); |
195 | |
196 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false" )); |
197 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
198 | test->waitUntilLoadFinished(); |
199 | test->flushEditorState(); |
200 | |
201 | // There's a selection. |
202 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
203 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY)); |
204 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
205 | |
206 | test->copyClipboard(); |
207 | GUniquePtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard)); |
208 | g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull" ); |
209 | } |
210 | |
211 | static void testWebViewEditorSelectAllNonEditable(EditorTest* test, gconstpointer) |
212 | { |
213 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL)); |
214 | |
215 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false" )); |
216 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
217 | test->waitUntilLoadFinished(); |
218 | test->flushEditorState(); |
219 | |
220 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL)); |
221 | |
222 | test->copyClipboard(); |
223 | GUniquePtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard)); |
224 | |
225 | // Initially only the subspan is selected. |
226 | g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull" ); |
227 | |
228 | webkit_web_view_execute_editing_command(test->m_webView, WEBKIT_EDITING_COMMAND_SELECT_ALL); |
229 | test->copyClipboard(); |
230 | clipboardText.reset(gtk_clipboard_wait_for_text(test->m_clipboard)); |
231 | |
232 | // The mainspan should be selected after calling SELECT_ALL. |
233 | g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy." ); |
234 | } |
235 | |
236 | static void testWebViewEditorSelectAllEditable(EditorTest* test, gconstpointer) |
237 | { |
238 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL)); |
239 | |
240 | g_assert_false(test->isEditable()); |
241 | test->setEditable(true); |
242 | g_assert_true(test->isEditable()); |
243 | |
244 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false" )); |
245 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
246 | test->waitUntilLoadFinished(); |
247 | test->flushEditorState(); |
248 | |
249 | g_assert_true(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL)); |
250 | |
251 | test->copyClipboard(); |
252 | GUniquePtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard)); |
253 | |
254 | // Initially only the subspan is selected. |
255 | g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull" ); |
256 | |
257 | webkit_web_view_execute_editing_command(test->m_webView, WEBKIT_EDITING_COMMAND_SELECT_ALL); |
258 | test->copyClipboard(); |
259 | clipboardText.reset(gtk_clipboard_wait_for_text(test->m_clipboard)); |
260 | |
261 | // The mainspan should be selected after calling SELECT_ALL. |
262 | g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy." ); |
263 | } |
264 | |
265 | static void loadContentsAndTryToCutSelection(EditorTest* test, bool contentEditable) |
266 | { |
267 | // View is not editable by default. |
268 | g_assert_false(test->isEditable()); |
269 | |
270 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, contentEditable ? "true" : "false" )); |
271 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
272 | test->waitUntilLoadFinished(); |
273 | test->flushEditorState(); |
274 | |
275 | g_assert_false(test->isEditable()); |
276 | test->setEditable(true); |
277 | g_assert_true(test->isEditable()); |
278 | |
279 | test->flushEditorState(); |
280 | |
281 | // Cut the selection to the clipboard to see if the view is indeed editable. |
282 | GUniquePtr<char> clipboardText(test->cutSelection()); |
283 | g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull" ); |
284 | |
285 | // Reset the editable for next test. |
286 | test->setEditable(false); |
287 | g_assert_false(test->isEditable()); |
288 | } |
289 | |
290 | static void testWebViewEditorNonEditable(EditorTest* test) |
291 | { |
292 | GUniquePtr<char> selectedSpanHTML(g_strdup_printf(selectedSpanHTMLFormat, "false" )); |
293 | test->loadHtml(selectedSpanHTML.get(), nullptr); |
294 | test->waitUntilLoadFinished(); |
295 | test->flushEditorState(); |
296 | |
297 | g_assert_false(test->isEditable()); |
298 | test->setEditable(true); |
299 | g_assert_true(test->isEditable()); |
300 | test->setEditable(false); |
301 | g_assert_false(test->isEditable()); |
302 | |
303 | // Check if view is indeed non-editable. |
304 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT)); |
305 | g_assert_false(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE)); |
306 | } |
307 | |
308 | static void testWebViewEditorEditable(EditorTest* test, gconstpointer) |
309 | { |
310 | testWebViewEditorNonEditable(test); |
311 | |
312 | // Reset the editable for next test. |
313 | test->setEditable(false); |
314 | g_assert_false(test->isEditable()); |
315 | |
316 | loadContentsAndTryToCutSelection(test, true); |
317 | |
318 | // Reset the editable for next test. |
319 | test->setEditable(false); |
320 | g_assert_false(test->isEditable()); |
321 | |
322 | loadContentsAndTryToCutSelection(test, false); |
323 | } |
324 | |
325 | static void testWebViewEditorEditorStateTypingAttributes(EditorTest* test, gconstpointer) |
326 | { |
327 | static const char* typingAttributesHTML = |
328 | "<html><body>" |
329 | "normal <b>bold </b><i>italic </i><u>underline </u><strike>strike </strike>" |
330 | "<b><i>boldanditalic </i></b>" |
331 | "</body></html>" ; |
332 | |
333 | test->loadHtml(typingAttributesHTML, nullptr); |
334 | test->waitUntilLoadFinished(); |
335 | test->flushEditorState(); |
336 | test->setEditable(true); |
337 | |
338 | unsigned typingAttributes = test->typingAttributes(); |
339 | g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE); |
340 | |
341 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward" ); |
342 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
343 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
344 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
345 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
346 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
347 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
348 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
349 | |
350 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward" ); |
351 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
352 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
353 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
354 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
355 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
356 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
357 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
358 | |
359 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward" ); |
360 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
361 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
362 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
363 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
364 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
365 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
366 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
367 | |
368 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward" ); |
369 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
370 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
371 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
372 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
373 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
374 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
375 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
376 | |
377 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForward" ); |
378 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
379 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
380 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
381 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
382 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
383 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
384 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
385 | |
386 | // Selections. |
387 | webkit_web_view_execute_editing_command(test->m_webView, "MoveToBeginningOfDocument" ); |
388 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
389 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
390 | g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE); |
391 | |
392 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
393 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
394 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
395 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
396 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
397 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
398 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
399 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
400 | |
401 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
402 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
403 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
404 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
405 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
406 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
407 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
408 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
409 | |
410 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
411 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
412 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
413 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
414 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
415 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
416 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
417 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
418 | |
419 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
420 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
421 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
422 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
423 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
424 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
425 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
426 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
427 | |
428 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
429 | webkit_web_view_execute_editing_command(test->m_webView, "MoveForward" ); |
430 | webkit_web_view_execute_editing_command(test->m_webView, "MoveWordForwardAndModifySelection" ); |
431 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
432 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD); |
433 | g_assert_true(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC); |
434 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE); |
435 | g_assert_false(typingAttributes & WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH); |
436 | |
437 | webkit_web_view_execute_editing_command(test->m_webView, "SelectAll" ); |
438 | typingAttributes = test->waitUntilTypingAttributesChanged(); |
439 | g_assert_cmpuint(typingAttributes, ==, WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE); |
440 | } |
441 | |
442 | static void testWebViewEditorInsertImage(EditorTest* test, gconstpointer) |
443 | { |
444 | test->loadHtml("<html><body></body></html>" , "file:///" ); |
445 | test->waitUntilLoadFinished(); |
446 | test->flushEditorState(); |
447 | test->setEditable(true); |
448 | |
449 | GUniquePtr<char> imagePath(g_build_filename(Test::getResourcesDir().data(), "blank.ico" , nullptr)); |
450 | GUniquePtr<char> imageURI(g_filename_to_uri(imagePath.get(), nullptr, nullptr)); |
451 | webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_INSERT_IMAGE, imageURI.get()); |
452 | GUniqueOutPtr<GError> error; |
453 | WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('IMG')[0].src" , &error.outPtr()); |
454 | g_assert_nonnull(javascriptResult); |
455 | g_assert_no_error(error.get()); |
456 | GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult)); |
457 | g_assert_cmpstr(resultString.get(), ==, imageURI.get()); |
458 | } |
459 | |
460 | static void testWebViewEditorCreateLink(EditorTest* test, gconstpointer) |
461 | { |
462 | test->loadHtml("<html><body onload=\"document.getSelection().selectAllChildren(document.body);\">webkitgtk.org</body></html>" , nullptr); |
463 | test->waitUntilLoadFinished(); |
464 | test->flushEditorState(); |
465 | test->setEditable(true); |
466 | |
467 | static const char* webkitGTKURL = "http://www.webkitgtk.org/" ; |
468 | webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, webkitGTKURL); |
469 | GUniqueOutPtr<GError> error; |
470 | WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[0].href;" , &error.outPtr()); |
471 | g_assert_nonnull(javascriptResult); |
472 | g_assert_no_error(error.get()); |
473 | GUniquePtr<char> resultString(WebViewTest::javascriptResultToCString(javascriptResult)); |
474 | g_assert_cmpstr(resultString.get(), ==, webkitGTKURL); |
475 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[0].innerText;" , &error.outPtr()); |
476 | g_assert_nonnull(javascriptResult); |
477 | g_assert_no_error(error.get()); |
478 | resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
479 | g_assert_cmpstr(resultString.get(), ==, "webkitgtk.org" ); |
480 | |
481 | // When there isn't text selected, the URL is used as link text. |
482 | webkit_web_view_execute_editing_command(test->m_webView, "MoveToEndOfLine" ); |
483 | webkit_web_view_execute_editing_command_with_argument(test->m_webView, WEBKIT_EDITING_COMMAND_CREATE_LINK, webkitGTKURL); |
484 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[1].href;" , &error.outPtr()); |
485 | g_assert_nonnull(javascriptResult); |
486 | g_assert_no_error(error.get()); |
487 | resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
488 | g_assert_cmpstr(resultString.get(), ==, webkitGTKURL); |
489 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('A')[1].innerText;" , &error.outPtr()); |
490 | g_assert_nonnull(javascriptResult); |
491 | g_assert_no_error(error.get()); |
492 | resultString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
493 | g_assert_cmpstr(resultString.get(), ==, webkitGTKURL); |
494 | } |
495 | |
496 | void beforeAll() |
497 | { |
498 | EditorTest::add("WebKitWebView" , "editable/editable" , testWebViewEditorEditable); |
499 | EditorTest::add("WebKitWebView" , "cut-copy-paste/non-editable" , testWebViewEditorCutCopyPasteNonEditable); |
500 | EditorTest::add("WebKitWebView" , "cut-copy-paste/editable" , testWebViewEditorCutCopyPasteEditable); |
501 | EditorTest::add("WebKitWebView" , "select-all/non-editable" , testWebViewEditorSelectAllNonEditable); |
502 | EditorTest::add("WebKitWebView" , "select-all/editable" , testWebViewEditorSelectAllEditable); |
503 | EditorTest::add("WebKitWebView" , "editor-state/typing-attributes" , testWebViewEditorEditorStateTypingAttributes); |
504 | EditorTest::add("WebKitWebView" , "insert/image" , testWebViewEditorInsertImage); |
505 | EditorTest::add("WebKitWebView" , "insert/link" , testWebViewEditorCreateLink); |
506 | } |
507 | |
508 | void afterAll() |
509 | { |
510 | } |
511 | |