1 | /* |
2 | * Copyright (C) 2011 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/HashSet.h> |
23 | #include <wtf/RunLoop.h> |
24 | #include <wtf/glib/GRefPtr.h> |
25 | #include <wtf/text/StringHash.h> |
26 | |
27 | static const char* kAlertDialogMessage = "WebKitGTK+ alert dialog message" ; |
28 | static const char* kConfirmDialogMessage = "WebKitGTK+ confirm dialog message" ; |
29 | static const char* kPromptDialogMessage = "WebKitGTK+ prompt dialog message" ; |
30 | static const char* kPromptDialogReturnedText = "WebKitGTK+ prompt dialog returned text" ; |
31 | static const char* kBeforeUnloadConfirmDialogMessage = "WebKitGTK+ beforeunload dialog message" ; |
32 | |
33 | class UIClientTest: public WebViewTest { |
34 | public: |
35 | MAKE_GLIB_TEST_FIXTURE(UIClientTest); |
36 | |
37 | enum WebViewEvents { |
38 | Create, |
39 | ReadyToShow, |
40 | RunAsModal, |
41 | Close |
42 | }; |
43 | |
44 | class WindowProperties { |
45 | public: |
46 | WindowProperties() |
47 | : m_isNull(true) |
48 | , m_toolbarVisible(true) |
49 | , m_statusbarVisible(true) |
50 | , m_scrollbarsVisible(true) |
51 | , m_menubarVisible(true) |
52 | , m_locationbarVisible(true) |
53 | , m_resizable(true) |
54 | , m_fullscreen(false) |
55 | { |
56 | #if PLATFORM(GTK) |
57 | memset(&m_geometry, 0, sizeof(GdkRectangle)); |
58 | #endif |
59 | } |
60 | |
61 | WindowProperties(WebKitWindowProperties* windowProperties) |
62 | : m_isNull(false) |
63 | , m_toolbarVisible(webkit_window_properties_get_toolbar_visible(windowProperties)) |
64 | , m_statusbarVisible(webkit_window_properties_get_statusbar_visible(windowProperties)) |
65 | , m_scrollbarsVisible(webkit_window_properties_get_scrollbars_visible(windowProperties)) |
66 | , m_menubarVisible(webkit_window_properties_get_menubar_visible(windowProperties)) |
67 | , m_locationbarVisible(webkit_window_properties_get_locationbar_visible(windowProperties)) |
68 | , m_resizable(webkit_window_properties_get_resizable(windowProperties)) |
69 | , m_fullscreen(webkit_window_properties_get_fullscreen(windowProperties)) |
70 | { |
71 | #if PLATFORM(GTK) |
72 | webkit_window_properties_get_geometry(windowProperties, &m_geometry); |
73 | #endif |
74 | } |
75 | |
76 | WindowProperties(cairo_rectangle_int_t* geometry, bool toolbarVisible, bool statusbarVisible, bool scrollbarsVisible, bool , bool locationbarVisible, bool resizable, bool fullscreen) |
77 | : m_isNull(false) |
78 | , m_geometry(*geometry) |
79 | , m_toolbarVisible(toolbarVisible) |
80 | , m_statusbarVisible(statusbarVisible) |
81 | , m_scrollbarsVisible(scrollbarsVisible) |
82 | , m_menubarVisible(menubarVisible) |
83 | , m_locationbarVisible(locationbarVisible) |
84 | , m_resizable(resizable) |
85 | , m_fullscreen(fullscreen) |
86 | { |
87 | } |
88 | |
89 | bool isNull() const { return m_isNull; } |
90 | |
91 | void assertEqual(const WindowProperties& other) const |
92 | { |
93 | #if PLATFORM(GTK) |
94 | g_assert_cmpint(m_geometry.x, ==, other.m_geometry.x); |
95 | g_assert_cmpint(m_geometry.y, ==, other.m_geometry.y); |
96 | g_assert_cmpint(m_geometry.width, ==, other.m_geometry.width); |
97 | g_assert_cmpint(m_geometry.height, ==, other.m_geometry.height); |
98 | #endif |
99 | g_assert_cmpint(static_cast<int>(m_toolbarVisible), ==, static_cast<int>(other.m_toolbarVisible)); |
100 | g_assert_cmpint(static_cast<int>(m_statusbarVisible), ==, static_cast<int>(other.m_statusbarVisible)); |
101 | g_assert_cmpint(static_cast<int>(m_scrollbarsVisible), ==, static_cast<int>(other.m_scrollbarsVisible)); |
102 | g_assert_cmpint(static_cast<int>(m_menubarVisible), ==, static_cast<int>(other.m_menubarVisible)); |
103 | g_assert_cmpint(static_cast<int>(m_locationbarVisible), ==, static_cast<int>(other.m_locationbarVisible)); |
104 | g_assert_cmpint(static_cast<int>(m_resizable), ==, static_cast<int>(other.m_resizable)); |
105 | g_assert_cmpint(static_cast<int>(m_fullscreen), ==, static_cast<int>(other.m_fullscreen)); |
106 | } |
107 | |
108 | private: |
109 | bool m_isNull; |
110 | |
111 | cairo_rectangle_int_t m_geometry; |
112 | |
113 | bool m_toolbarVisible; |
114 | bool m_statusbarVisible; |
115 | bool m_scrollbarsVisible; |
116 | bool ; |
117 | bool m_locationbarVisible; |
118 | |
119 | bool m_resizable; |
120 | bool m_fullscreen; |
121 | }; |
122 | |
123 | static void windowPropertiesNotifyCallback(GObject*, GParamSpec* paramSpec, UIClientTest* test) |
124 | { |
125 | test->m_windowPropertiesChanged.add(g_param_spec_get_name(paramSpec)); |
126 | } |
127 | |
128 | static WebKitWebView* viewCreateCallback(WebKitWebView* webView, WebKitNavigationAction* navigation, UIClientTest* test) |
129 | { |
130 | return test->viewCreate(webView, navigation); |
131 | } |
132 | |
133 | static void viewReadyToShowCallback(WebKitWebView* webView, UIClientTest* test) |
134 | { |
135 | test->viewReadyToShow(webView); |
136 | } |
137 | |
138 | static void viewCloseCallback(WebKitWebView* webView, UIClientTest* test) |
139 | { |
140 | test->viewClose(webView); |
141 | } |
142 | |
143 | void scriptAlert(WebKitScriptDialog* dialog) |
144 | { |
145 | switch (m_scriptDialogType) { |
146 | case WEBKIT_SCRIPT_DIALOG_ALERT: |
147 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kAlertDialogMessage); |
148 | break; |
149 | case WEBKIT_SCRIPT_DIALOG_CONFIRM: |
150 | g_assert_true(m_scriptDialogConfirmed); |
151 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, "confirmed" ); |
152 | |
153 | break; |
154 | case WEBKIT_SCRIPT_DIALOG_PROMPT: |
155 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogReturnedText); |
156 | break; |
157 | case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: |
158 | g_assert_not_reached(); |
159 | break; |
160 | } |
161 | |
162 | if (m_delayedScriptDialogs) { |
163 | webkit_script_dialog_ref(dialog); |
164 | RunLoop::main().dispatch([this, dialog] { |
165 | webkit_script_dialog_close(dialog); |
166 | webkit_script_dialog_unref(dialog); |
167 | g_main_loop_quit(m_mainLoop); |
168 | }); |
169 | } else |
170 | g_main_loop_quit(m_mainLoop); |
171 | } |
172 | |
173 | void scriptConfirm(WebKitScriptDialog* dialog) |
174 | { |
175 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kConfirmDialogMessage); |
176 | m_scriptDialogConfirmed = !m_scriptDialogConfirmed; |
177 | webkit_script_dialog_confirm_set_confirmed(dialog, m_scriptDialogConfirmed); |
178 | } |
179 | |
180 | void scriptPrompt(WebKitScriptDialog* dialog) |
181 | { |
182 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kPromptDialogMessage); |
183 | g_assert_cmpstr(webkit_script_dialog_prompt_get_default_text(dialog), ==, "default" ); |
184 | webkit_script_dialog_prompt_set_text(dialog, kPromptDialogReturnedText); |
185 | } |
186 | |
187 | void scriptBeforeUnloadConfirm(WebKitScriptDialog* dialog) |
188 | { |
189 | g_assert_cmpstr(webkit_script_dialog_get_message(dialog), ==, kBeforeUnloadConfirmDialogMessage); |
190 | m_scriptDialogConfirmed = true; |
191 | webkit_script_dialog_confirm_set_confirmed(dialog, m_scriptDialogConfirmed); |
192 | } |
193 | |
194 | static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, UIClientTest* test) |
195 | { |
196 | switch (webkit_script_dialog_get_dialog_type(dialog)) { |
197 | case WEBKIT_SCRIPT_DIALOG_ALERT: |
198 | test->scriptAlert(dialog); |
199 | break; |
200 | case WEBKIT_SCRIPT_DIALOG_CONFIRM: |
201 | test->scriptConfirm(dialog); |
202 | break; |
203 | case WEBKIT_SCRIPT_DIALOG_PROMPT: |
204 | test->scriptPrompt(dialog); |
205 | break; |
206 | case WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: |
207 | test->scriptBeforeUnloadConfirm(dialog); |
208 | break; |
209 | } |
210 | |
211 | return TRUE; |
212 | } |
213 | |
214 | static void mouseTargetChanged(WebKitWebView*, WebKitHitTestResult* hitTestResult, guint modifiers, UIClientTest* test) |
215 | { |
216 | g_assert_true(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult)); |
217 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(hitTestResult)); |
218 | |
219 | test->m_mouseTargetHitTestResult = hitTestResult; |
220 | test->m_mouseTargetModifiers = modifiers; |
221 | g_main_loop_quit(test->m_mainLoop); |
222 | } |
223 | |
224 | static gboolean permissionRequested(WebKitWebView*, WebKitPermissionRequest* request, UIClientTest* test) |
225 | { |
226 | g_assert_true(WEBKIT_IS_PERMISSION_REQUEST(request)); |
227 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request)); |
228 | |
229 | if (test->m_verifyMediaTypes && WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(request)) { |
230 | WebKitUserMediaPermissionRequest* userMediaRequest = WEBKIT_USER_MEDIA_PERMISSION_REQUEST(request); |
231 | g_assert_true(webkit_user_media_permission_is_for_audio_device(userMediaRequest) == test->m_expectedAudioMedia); |
232 | g_assert_true(webkit_user_media_permission_is_for_video_device(userMediaRequest) == test->m_expectedVideoMedia); |
233 | } |
234 | |
235 | if (test->m_allowPermissionRequests) |
236 | webkit_permission_request_allow(request); |
237 | else |
238 | webkit_permission_request_deny(request); |
239 | |
240 | return TRUE; |
241 | } |
242 | |
243 | static void permissionResultMessageReceivedCallback(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* javascriptResult, UIClientTest* test) |
244 | { |
245 | test->m_permissionResult.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
246 | g_main_loop_quit(test->m_mainLoop); |
247 | } |
248 | |
249 | UIClientTest() |
250 | : m_scriptDialogType(WEBKIT_SCRIPT_DIALOG_ALERT) |
251 | , m_scriptDialogConfirmed(true) |
252 | , m_allowPermissionRequests(false) |
253 | , m_verifyMediaTypes(false) |
254 | , m_expectedAudioMedia(false) |
255 | , m_expectedVideoMedia(false) |
256 | , m_mouseTargetModifiers(0) |
257 | { |
258 | webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE); |
259 | g_signal_connect(m_webView, "create" , G_CALLBACK(viewCreateCallback), this); |
260 | g_signal_connect(m_webView, "script-dialog" , G_CALLBACK(scriptDialog), this); |
261 | g_signal_connect(m_webView, "mouse-target-changed" , G_CALLBACK(mouseTargetChanged), this); |
262 | g_signal_connect(m_webView, "permission-request" , G_CALLBACK(permissionRequested), this); |
263 | webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "permission" ); |
264 | g_signal_connect(m_userContentManager.get(), "script-message-received::permission" , G_CALLBACK(permissionResultMessageReceivedCallback), this); |
265 | } |
266 | |
267 | ~UIClientTest() |
268 | { |
269 | g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
270 | g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
271 | webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "permission" ); |
272 | } |
273 | |
274 | static void tryWebViewCloseCallback(UIClientTest* test) |
275 | { |
276 | g_main_loop_quit(test->m_mainLoop); |
277 | } |
278 | |
279 | void tryCloseAndWaitUntilClosed() |
280 | { |
281 | gulong handler = g_signal_connect_swapped(m_webView, "close" , G_CALLBACK(tryWebViewCloseCallback), this); |
282 | // Use an idle because webkit_web_view_try_close can emit the close signal in the |
283 | // current run loop iteration. |
284 | g_idle_add([](gpointer data) -> gboolean { |
285 | webkit_web_view_try_close(WEBKIT_WEB_VIEW(data)); |
286 | return G_SOURCE_REMOVE; |
287 | }, m_webView); |
288 | g_main_loop_run(m_mainLoop); |
289 | g_signal_handler_disconnect(m_webView, handler); |
290 | } |
291 | |
292 | void waitUntilMainLoopFinishes() |
293 | { |
294 | g_main_loop_run(m_mainLoop); |
295 | } |
296 | |
297 | const char* waitUntilPermissionResultMessageReceived() |
298 | { |
299 | m_permissionResult = nullptr; |
300 | g_main_loop_run(m_mainLoop); |
301 | return m_permissionResult.get(); |
302 | } |
303 | |
304 | void setExpectedWindowProperties(const WindowProperties& windowProperties) |
305 | { |
306 | m_windowProperties = windowProperties; |
307 | } |
308 | |
309 | WebKitHitTestResult* moveMouseAndWaitUntilMouseTargetChanged(int x, int y, unsigned mouseModifiers = 0) |
310 | { |
311 | mouseMoveTo(x, y, mouseModifiers); |
312 | g_main_loop_run(m_mainLoop); |
313 | return m_mouseTargetHitTestResult.get(); |
314 | } |
315 | |
316 | void simulateUserInteraction() |
317 | { |
318 | runJavaScriptAndWaitUntilFinished("document.getElementById('testInput').focus()" , nullptr); |
319 | // FIXME: Implement keyStroke in WPE. |
320 | #if PLATFORM(GTK) |
321 | keyStroke(GDK_KEY_a); |
322 | keyStroke(GDK_KEY_b); |
323 | while (gtk_events_pending()) |
324 | gtk_main_iteration(); |
325 | #endif |
326 | } |
327 | |
328 | virtual WebKitWebView* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation) |
329 | { |
330 | g_assert_true(webView == m_webView); |
331 | g_assert_nonnull(navigation); |
332 | |
333 | auto* newWebView = Test::createWebView(webkit_web_view_get_context(webView)); |
334 | #if PLATFORM(GTK) |
335 | g_object_ref_sink(newWebView); |
336 | #endif |
337 | |
338 | m_webViewEvents.append(Create); |
339 | |
340 | WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(WEBKIT_WEB_VIEW(newWebView)); |
341 | g_assert_nonnull(windowProperties); |
342 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(windowProperties)); |
343 | m_windowPropertiesChanged.clear(); |
344 | |
345 | g_signal_connect(windowProperties, "notify" , G_CALLBACK(windowPropertiesNotifyCallback), this); |
346 | g_signal_connect(newWebView, "ready-to-show" , G_CALLBACK(viewReadyToShowCallback), this); |
347 | g_signal_connect(newWebView, "close" , G_CALLBACK(viewCloseCallback), this); |
348 | |
349 | return WEBKIT_WEB_VIEW(newWebView); |
350 | } |
351 | |
352 | virtual void viewReadyToShow(WebKitWebView* webView) |
353 | { |
354 | g_assert_true(webView != m_webView); |
355 | |
356 | WebKitWindowProperties* windowProperties = webkit_web_view_get_window_properties(webView); |
357 | g_assert_nonnull(windowProperties); |
358 | if (!m_windowProperties.isNull()) |
359 | WindowProperties(windowProperties).assertEqual(m_windowProperties); |
360 | |
361 | m_webViewEvents.append(ReadyToShow); |
362 | } |
363 | |
364 | virtual void viewClose(WebKitWebView* webView) |
365 | { |
366 | g_assert_true(webView != m_webView); |
367 | |
368 | m_webViewEvents.append(Close); |
369 | g_object_unref(webView); |
370 | |
371 | g_main_loop_quit(m_mainLoop); |
372 | } |
373 | |
374 | Vector<WebViewEvents> m_webViewEvents; |
375 | WebKitScriptDialogType m_scriptDialogType; |
376 | bool m_scriptDialogConfirmed; |
377 | bool m_delayedScriptDialogs { false }; |
378 | bool m_allowPermissionRequests; |
379 | gboolean m_verifyMediaTypes; |
380 | gboolean m_expectedAudioMedia; |
381 | gboolean m_expectedVideoMedia; |
382 | WindowProperties m_windowProperties; |
383 | HashSet<WTF::String> m_windowPropertiesChanged; |
384 | GRefPtr<WebKitHitTestResult> m_mouseTargetHitTestResult; |
385 | unsigned m_mouseTargetModifiers; |
386 | GUniquePtr<char> m_permissionResult; |
387 | }; |
388 | |
389 | static void testWebViewCreateReadyClose(UIClientTest* test, gconstpointer) |
390 | { |
391 | test->loadHtml("<html><body onLoad=\"window.open().close();\"></html>" , 0); |
392 | test->waitUntilMainLoopFinishes(); |
393 | |
394 | Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; |
395 | g_assert_cmpint(events.size(), ==, 3); |
396 | g_assert_cmpint(events[0], ==, UIClientTest::Create); |
397 | g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow); |
398 | g_assert_cmpint(events[2], ==, UIClientTest::Close); |
399 | } |
400 | |
401 | #if PLATFORM(GTK) |
402 | class CreateNavigationDataTest: public UIClientTest { |
403 | public: |
404 | MAKE_GLIB_TEST_FIXTURE(CreateNavigationDataTest); |
405 | |
406 | CreateNavigationDataTest() |
407 | : m_navigation(nullptr) |
408 | { |
409 | } |
410 | |
411 | ~CreateNavigationDataTest() |
412 | { |
413 | clearNavigation(); |
414 | } |
415 | |
416 | void clearNavigation() |
417 | { |
418 | if (m_navigation) |
419 | webkit_navigation_action_free(m_navigation); |
420 | m_navigation = nullptr; |
421 | } |
422 | |
423 | WebKitWebView* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation) |
424 | { |
425 | g_assert_nonnull(navigation); |
426 | g_assert_null(m_navigation); |
427 | m_navigation = webkit_navigation_action_copy(navigation); |
428 | g_main_loop_quit(m_mainLoop); |
429 | return nullptr; |
430 | } |
431 | |
432 | void loadHTML(const char* html) |
433 | { |
434 | clearNavigation(); |
435 | WebViewTest::loadHtml(html, nullptr); |
436 | } |
437 | |
438 | void clickAndWaitUntilMainLoopFinishes(int x, int y) |
439 | { |
440 | clearNavigation(); |
441 | clickMouseButton(x, y, 1); |
442 | g_main_loop_run(m_mainLoop); |
443 | } |
444 | |
445 | WebKitNavigationAction* m_navigation; |
446 | }; |
447 | |
448 | static void testWebViewCreateNavigationData(CreateNavigationDataTest* test, gconstpointer) |
449 | { |
450 | #if PLATFORM(GTK) |
451 | test->showInWindowAndWaitUntilMapped(); |
452 | #endif |
453 | |
454 | test->loadHTML( |
455 | "<html><body>" |
456 | "<input style=\"position:absolute; left:0; top:0; margin:0; padding:0\" type=\"button\" value=\"click to show a popup\" onclick=\"window.open('data:foo');\"/>" |
457 | "<a style=\"position:absolute; left:20; top:20;\" href=\"data:bar\" target=\"_blank\">popup link</a>" |
458 | "</body></html>" ); |
459 | test->waitUntilLoadFinished(); |
460 | |
461 | // Click on a button. |
462 | test->clickAndWaitUntilMainLoopFinishes(5, 5); |
463 | g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "data:foo" ); |
464 | g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_OTHER); |
465 | // FIXME: This should be button 1. |
466 | g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 0); |
467 | g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0); |
468 | g_assert_true(webkit_navigation_action_is_user_gesture(test->m_navigation)); |
469 | |
470 | // Click on a link. |
471 | test->clickAndWaitUntilMainLoopFinishes(21, 21); |
472 | g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "data:bar" ); |
473 | g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_LINK_CLICKED); |
474 | g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 1); |
475 | g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0); |
476 | g_assert_true(webkit_navigation_action_is_user_gesture(test->m_navigation)); |
477 | |
478 | // No user interaction. |
479 | test->loadHTML("<html><body onLoad=\"window.open();\"></html>" ); |
480 | test->waitUntilMainLoopFinishes(); |
481 | |
482 | g_assert_cmpstr(webkit_uri_request_get_uri(webkit_navigation_action_get_request(test->m_navigation)), ==, "about:blank" ); |
483 | g_assert_cmpuint(webkit_navigation_action_get_navigation_type(test->m_navigation), ==, WEBKIT_NAVIGATION_TYPE_OTHER); |
484 | g_assert_cmpuint(webkit_navigation_action_get_mouse_button(test->m_navigation), ==, 0); |
485 | g_assert_cmpuint(webkit_navigation_action_get_modifiers(test->m_navigation), ==, 0); |
486 | g_assert_false(webkit_navigation_action_is_user_gesture(test->m_navigation)); |
487 | } |
488 | #endif // PLATFORM(GTK) |
489 | |
490 | #if PLATFORM(GTK) |
491 | static gboolean checkMimeTypeForFilter(GtkFileFilter* filter, const gchar* mimeType) |
492 | { |
493 | GtkFileFilterInfo filterInfo; |
494 | filterInfo.contains = GTK_FILE_FILTER_MIME_TYPE; |
495 | filterInfo.mime_type = mimeType; |
496 | return gtk_file_filter_filter(filter, &filterInfo); |
497 | } |
498 | #endif |
499 | |
500 | class ModalDialogsTest: public UIClientTest { |
501 | public: |
502 | MAKE_GLIB_TEST_FIXTURE(ModalDialogsTest); |
503 | |
504 | static void dialogRunAsModalCallback(WebKitWebView* webView, ModalDialogsTest* test) |
505 | { |
506 | g_assert_true(webView != test->m_webView); |
507 | test->m_webViewEvents.append(RunAsModal); |
508 | } |
509 | |
510 | WebKitWebView* viewCreate(WebKitWebView* webView, WebKitNavigationAction* navigation) |
511 | { |
512 | g_assert_true(webView == m_webView); |
513 | |
514 | auto* newWebView = UIClientTest::viewCreate(webView, navigation); |
515 | g_signal_connect(newWebView, "run-as-modal" , G_CALLBACK(dialogRunAsModalCallback), this); |
516 | return newWebView; |
517 | } |
518 | |
519 | void viewReadyToShow(WebKitWebView* webView) |
520 | { |
521 | g_assert_true(webView != m_webView); |
522 | m_webViewEvents.append(ReadyToShow); |
523 | } |
524 | }; |
525 | |
526 | static void testWebViewAllowModalDialogs(ModalDialogsTest* test, gconstpointer) |
527 | { |
528 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
529 | webkit_settings_set_allow_modal_dialogs(settings, TRUE); |
530 | |
531 | test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>" , 0); |
532 | test->waitUntilMainLoopFinishes(); |
533 | |
534 | Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; |
535 | g_assert_cmpint(events.size(), ==, 4); |
536 | g_assert_cmpint(events[0], ==, UIClientTest::Create); |
537 | g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow); |
538 | g_assert_cmpint(events[2], ==, UIClientTest::RunAsModal); |
539 | g_assert_cmpint(events[3], ==, UIClientTest::Close); |
540 | } |
541 | |
542 | static void testWebViewDisallowModalDialogs(ModalDialogsTest* test, gconstpointer) |
543 | { |
544 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
545 | webkit_settings_set_allow_modal_dialogs(settings, FALSE); |
546 | |
547 | test->loadHtml("<html><body onload=\"window.showModalDialog('data:text/html,<html><body/><script>window.close();</script></html>')\"></body></html>" , 0); |
548 | // We need to use a timeout here because the viewClose() function |
549 | // won't ever be called as the dialog won't be created. |
550 | test->wait(1); |
551 | |
552 | Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; |
553 | g_assert_cmpint(events.size(), ==, 0); |
554 | } |
555 | |
556 | static void testWebViewJavaScriptDialogs(UIClientTest* test, gconstpointer) |
557 | { |
558 | #if PLATFORM(GTK) |
559 | test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL); |
560 | #endif |
561 | |
562 | static const char* htmlOnLoadFormat = "<html><body onLoad=\"%s\"></body></html>" ; |
563 | static const char* jsAlertFormat = "alert('%s')" ; |
564 | static const char* jsConfirmFormat = "do { confirmed = confirm('%s'); } while (!confirmed); alert('confirmed');" ; |
565 | static const char* jsPromptFormat = "alert(prompt('%s', 'default'));" ; |
566 | #if PLATFORM(GTK) |
567 | static const char* htmlOnBeforeUnloadFormat = |
568 | "<html><body onbeforeunload=\"return beforeUnloadHandler();\"><input id=\"testInput\" type=\"text\"></input><script>function beforeUnloadHandler() { return \"%s\"; }</script></body></html>" ; |
569 | #endif |
570 | |
571 | for (unsigned i = 0; i <= 1; ++i) { |
572 | test->m_delayedScriptDialogs = !!i; |
573 | |
574 | test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_ALERT; |
575 | GUniquePtr<char> alertDialogMessage(g_strdup_printf(jsAlertFormat, kAlertDialogMessage)); |
576 | GUniquePtr<char> alertHTML(g_strdup_printf(htmlOnLoadFormat, alertDialogMessage.get())); |
577 | test->loadHtml(alertHTML.get(), nullptr); |
578 | test->waitUntilMainLoopFinishes(); |
579 | webkit_web_view_stop_loading(test->m_webView); |
580 | test->waitUntilLoadFinished(); |
581 | |
582 | test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_CONFIRM; |
583 | GUniquePtr<char> confirmDialogMessage(g_strdup_printf(jsConfirmFormat, kConfirmDialogMessage)); |
584 | GUniquePtr<char> confirmHTML(g_strdup_printf(htmlOnLoadFormat, confirmDialogMessage.get())); |
585 | test->loadHtml(confirmHTML.get(), nullptr); |
586 | test->waitUntilMainLoopFinishes(); |
587 | webkit_web_view_stop_loading(test->m_webView); |
588 | test->waitUntilLoadFinished(); |
589 | |
590 | test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_PROMPT; |
591 | GUniquePtr<char> promptDialogMessage(g_strdup_printf(jsPromptFormat, kPromptDialogMessage)); |
592 | GUniquePtr<char> promptHTML(g_strdup_printf(htmlOnLoadFormat, promptDialogMessage.get())); |
593 | test->loadHtml(promptHTML.get(), nullptr); |
594 | test->waitUntilMainLoopFinishes(); |
595 | webkit_web_view_stop_loading(test->m_webView); |
596 | test->waitUntilLoadFinished(); |
597 | } |
598 | |
599 | test->m_delayedScriptDialogs = false; |
600 | |
601 | // FIXME: implement simulateUserInteraction in WPE. |
602 | #if PLATFORM(GTK) |
603 | test->m_scriptDialogType = WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM; |
604 | GUniquePtr<char> beforeUnloadDialogHTML(g_strdup_printf(htmlOnBeforeUnloadFormat, kBeforeUnloadConfirmDialogMessage)); |
605 | test->loadHtml(beforeUnloadDialogHTML.get(), nullptr); |
606 | test->waitUntilLoadFinished(); |
607 | |
608 | // Reload should trigger onbeforeunload. |
609 | #if 0 |
610 | test->simulateUserInteraction(); |
611 | // FIXME: reloading HTML data doesn't emit finished load event. |
612 | // See https://bugs.webkit.org/show_bug.cgi?id=139089. |
613 | test->m_scriptDialogConfirmed = false; |
614 | webkit_web_view_reload(test->m_webView); |
615 | test->waitUntilLoadFinished(); |
616 | g_assert_true(test->m_scriptDialogConfirmed); |
617 | #endif |
618 | |
619 | // Navigation should trigger onbeforeunload. |
620 | test->simulateUserInteraction(); |
621 | test->m_scriptDialogConfirmed = false; |
622 | test->loadHtml("<html></html>" , nullptr); |
623 | test->waitUntilLoadFinished(); |
624 | g_assert_true(test->m_scriptDialogConfirmed); |
625 | |
626 | // Try close should trigger onbeforeunload. |
627 | test->m_scriptDialogConfirmed = false; |
628 | test->loadHtml(beforeUnloadDialogHTML.get(), nullptr); |
629 | test->waitUntilLoadFinished(); |
630 | test->simulateUserInteraction(); |
631 | test->tryCloseAndWaitUntilClosed(); |
632 | g_assert_true(test->m_scriptDialogConfirmed); |
633 | |
634 | // Try close on a page with no unload handlers should not trigger onbeforeunload, |
635 | // but should actually close the page. |
636 | test->m_scriptDialogConfirmed = false; |
637 | test->loadHtml("<html><body></body></html>" , nullptr); |
638 | test->waitUntilLoadFinished(); |
639 | // We got a onbeforeunload of the previous page. |
640 | g_assert_true(test->m_scriptDialogConfirmed); |
641 | test->m_scriptDialogConfirmed = false; |
642 | test->tryCloseAndWaitUntilClosed(); |
643 | g_assert_false(test->m_scriptDialogConfirmed); |
644 | #endif // PLATFORM(GTK) |
645 | } |
646 | |
647 | static void testWebViewWindowProperties(UIClientTest* test, gconstpointer) |
648 | { |
649 | static const char* windowProrpertiesString = "left=100,top=150,width=400,height=400,location=no,menubar=no,status=no,toolbar=no,scrollbars=no" ; |
650 | cairo_rectangle_int_t geometry = { 100, 150, 400, 400 }; |
651 | test->setExpectedWindowProperties(UIClientTest::WindowProperties(&geometry, false, false, false, false, false, true, false)); |
652 | |
653 | GUniquePtr<char> htmlString(g_strdup_printf("<html><body onLoad=\"window.open('', '', '%s').close();\"></body></html>" , windowProrpertiesString)); |
654 | test->loadHtml(htmlString.get(), 0); |
655 | test->waitUntilMainLoopFinishes(); |
656 | |
657 | static const char* propertiesChanged[] = { |
658 | #if PLATFORM(GTK) |
659 | "geometry" , |
660 | #endif |
661 | "locationbar-visible" , "menubar-visible" , "statusbar-visible" , "toolbar-visible" , "scrollbars-visible" |
662 | }; |
663 | for (size_t i = 0; i < G_N_ELEMENTS(propertiesChanged); ++i) |
664 | g_assert_true(test->m_windowPropertiesChanged.contains(propertiesChanged[i])); |
665 | |
666 | Vector<UIClientTest::WebViewEvents>& events = test->m_webViewEvents; |
667 | g_assert_cmpint(events.size(), ==, 3); |
668 | g_assert_cmpint(events[0], ==, UIClientTest::Create); |
669 | g_assert_cmpint(events[1], ==, UIClientTest::ReadyToShow); |
670 | g_assert_cmpint(events[2], ==, UIClientTest::Close); |
671 | } |
672 | |
673 | #if PLATFORM(GTK) |
674 | static void testWebViewMouseTarget(UIClientTest* test, gconstpointer) |
675 | { |
676 | test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL); |
677 | |
678 | const char* linksHoveredHTML = |
679 | "<html><head>" |
680 | " <script>" |
681 | " window.onload = function () {" |
682 | " window.getSelection().removeAllRanges();" |
683 | " var select_range = document.createRange();" |
684 | " select_range.selectNodeContents(document.getElementById('text_to_select'));" |
685 | " window.getSelection().addRange(select_range);" |
686 | " }" |
687 | " </script>" |
688 | "</head><body>" |
689 | " <a style='position:absolute; left:1; top:1' href='http://www.webkitgtk.org' title='WebKitGTK+ Title'>WebKitGTK+ Website</a>" |
690 | " <img style='position:absolute; left:1; top:10' src='0xdeadbeef' width=5 height=5></img>" |
691 | " <a style='position:absolute; left:1; top:20' href='http://www.webkitgtk.org/logo' title='WebKitGTK+ Logo'><img src='0xdeadbeef' width=5 height=5></img></a>" |
692 | " <input style='position:absolute; left:1; top:30' size='10'></input>" |
693 | " <video style='position:absolute; left:1; top:100' width='300' height='300' controls='controls' preload='none'><source src='movie.ogg' type='video/ogg' /></video>" |
694 | " <p style='position:absolute; left:1; top:120' id='text_to_select'>Lorem ipsum.</p>" |
695 | "</body></html>" ; |
696 | |
697 | test->loadHtml(linksHoveredHTML, "file:///" ); |
698 | test->waitUntilLoadFinished(); |
699 | |
700 | // Move over link. |
701 | WebKitHitTestResult* hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 1); |
702 | g_assert_true(webkit_hit_test_result_context_is_link(hitTestResult)); |
703 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
704 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
705 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
706 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
707 | g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/" ); |
708 | g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Title" ); |
709 | g_assert_cmpstr(webkit_hit_test_result_get_link_label(hitTestResult), ==, "WebKitGTK+ Website" ); |
710 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
711 | |
712 | // Move out of the link. |
713 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(0, 0); |
714 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
715 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
716 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
717 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
718 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
719 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
720 | |
721 | // Move over image with GDK_CONTROL_MASK. |
722 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 10, GDK_CONTROL_MASK); |
723 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
724 | g_assert_true(webkit_hit_test_result_context_is_image(hitTestResult)); |
725 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
726 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
727 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
728 | g_assert_false(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
729 | g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef" ); |
730 | g_assert_true(test->m_mouseTargetModifiers & GDK_CONTROL_MASK); |
731 | |
732 | // Move over image link. |
733 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 20); |
734 | g_assert_true(webkit_hit_test_result_context_is_link(hitTestResult)); |
735 | g_assert_true(webkit_hit_test_result_context_is_image(hitTestResult)); |
736 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
737 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
738 | g_assert_false(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
739 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
740 | g_assert_cmpstr(webkit_hit_test_result_get_link_uri(hitTestResult), ==, "http://www.webkitgtk.org/logo" ); |
741 | g_assert_cmpstr(webkit_hit_test_result_get_image_uri(hitTestResult), ==, "file:///0xdeadbeef" ); |
742 | g_assert_cmpstr(webkit_hit_test_result_get_link_title(hitTestResult), ==, "WebKitGTK+ Logo" ); |
743 | g_assert_false(webkit_hit_test_result_get_link_label(hitTestResult)); |
744 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
745 | |
746 | // Move over media. |
747 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(1, 100); |
748 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
749 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
750 | g_assert_true(webkit_hit_test_result_context_is_media(hitTestResult)); |
751 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
752 | g_assert_false(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
753 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
754 | g_assert_cmpstr(webkit_hit_test_result_get_media_uri(hitTestResult), ==, "file:///movie.ogg" ); |
755 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
756 | |
757 | // Mover over input. |
758 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(5, 35); |
759 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
760 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
761 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
762 | g_assert_false(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
763 | g_assert_true(webkit_hit_test_result_context_is_editable(hitTestResult)); |
764 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
765 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
766 | |
767 | // Move over scrollbar. |
768 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(gtk_widget_get_allocated_width(GTK_WIDGET(test->m_webView)) - 4, 5); |
769 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
770 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
771 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
772 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
773 | g_assert_true(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
774 | g_assert_false(webkit_hit_test_result_context_is_selection(hitTestResult)); |
775 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
776 | |
777 | // Move over selection. |
778 | hitTestResult = test->moveMouseAndWaitUntilMouseTargetChanged(2, 145); |
779 | g_assert_false(webkit_hit_test_result_context_is_link(hitTestResult)); |
780 | g_assert_false(webkit_hit_test_result_context_is_image(hitTestResult)); |
781 | g_assert_false(webkit_hit_test_result_context_is_media(hitTestResult)); |
782 | g_assert_false(webkit_hit_test_result_context_is_editable(hitTestResult)); |
783 | g_assert_false(webkit_hit_test_result_context_is_scrollbar(hitTestResult)); |
784 | g_assert_true(webkit_hit_test_result_context_is_selection(hitTestResult)); |
785 | g_assert_cmpuint(test->m_mouseTargetModifiers, ==, 0); |
786 | } |
787 | #endif // PLATFORM(GTK) |
788 | |
789 | static void testWebViewGeolocationPermissionRequests(UIClientTest* test, gconstpointer) |
790 | { |
791 | // Some versions of geoclue give a runtime warning because it tries |
792 | // to register the error quark twice. See https://bugs.webkit.org/show_bug.cgi?id=89858. |
793 | // Make warnings non-fatal for this test to make it pass. |
794 | test->removeLogFatalFlag(G_LOG_LEVEL_WARNING); |
795 | #if PLATFORM(GTK) |
796 | test->showInWindowAndWaitUntilMapped(); |
797 | #endif |
798 | static const char* geolocationRequestHTML = |
799 | "<html>" |
800 | " <script>" |
801 | " function runTest()" |
802 | " {" |
803 | " navigator.geolocation.getCurrentPosition(function(p) { window.webkit.messageHandlers.permission.postMessage('OK'); }," |
804 | " function(e) { window.webkit.messageHandlers.permission.postMessage(e.code.toString()); });" |
805 | " }" |
806 | " </script>" |
807 | " <body onload='runTest();'></body>" |
808 | "</html>" ; |
809 | |
810 | // Geolocation is not allowed from insecure connections like HTTP, |
811 | // POSITION_UNAVAILABLE ('2') is returned in that case without even |
812 | // asking the API layer. |
813 | test->m_allowPermissionRequests = false; |
814 | test->loadHtml(geolocationRequestHTML, "http://foo.com/bar" ); |
815 | const gchar* result = test->waitUntilPermissionResultMessageReceived(); |
816 | g_assert_cmpstr(result, ==, "2" ); |
817 | |
818 | // Test denying a permission request. PERMISSION_DENIED ('1') is |
819 | // returned in this case. |
820 | test->m_allowPermissionRequests = false; |
821 | test->loadHtml(geolocationRequestHTML, "https://foo.com/bar" ); |
822 | result = test->waitUntilPermissionResultMessageReceived(); |
823 | g_assert_cmpstr(result, ==, "1" ); |
824 | |
825 | // Test allowing a permission request. Result should be different |
826 | // to PERMISSION_DENIED ('1'). |
827 | test->m_allowPermissionRequests = true; |
828 | test->loadHtml(geolocationRequestHTML, "https://foo.com/bar" ); |
829 | result = test->waitUntilPermissionResultMessageReceived(); |
830 | g_assert_cmpstr(result, !=, "1" ); |
831 | test->addLogFatalFlag(G_LOG_LEVEL_WARNING); |
832 | } |
833 | |
834 | #if ENABLE(MEDIA_STREAM) |
835 | static void testWebViewUserMediaEnumerateDevicesPermissionCheck(UIClientTest* test, gconstpointer) |
836 | { |
837 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
838 | gboolean enabled = webkit_settings_get_enable_media_stream(settings); |
839 | webkit_settings_set_enable_media_stream(settings, TRUE); |
840 | |
841 | #if PLATFORM(GTK) |
842 | test->showInWindowAndWaitUntilMapped(); |
843 | #endif |
844 | static const char* userMediaRequestHTML = |
845 | "<html>" |
846 | " <script>" |
847 | " function runTest()" |
848 | " {" |
849 | " navigator.mediaDevices.enumerateDevices().then(" |
850 | " function(devices) { " |
851 | " devices.forEach(function(device) {" |
852 | " if (device.label) document.title = \"OK\";" |
853 | " else document.title = \"Permission denied\";" |
854 | " })" |
855 | " })" |
856 | " }" |
857 | " </script>" |
858 | " <body onload='runTest();'></body>" |
859 | "</html>" ; |
860 | |
861 | test->m_verifyMediaTypes = TRUE; |
862 | |
863 | // Test denying a permission request. |
864 | test->m_allowPermissionRequests = false; |
865 | test->loadHtml(userMediaRequestHTML, nullptr); |
866 | test->waitUntilTitleChangedTo("Permission denied" ); |
867 | |
868 | // Test allowing a permission request. |
869 | test->m_allowPermissionRequests = true; |
870 | test->loadHtml(userMediaRequestHTML, nullptr); |
871 | test->waitUntilTitleChangedTo("OK" ); |
872 | |
873 | webkit_settings_set_enable_media_stream(settings, enabled); |
874 | } |
875 | |
876 | static void testWebViewUserMediaPermissionRequests(UIClientTest* test, gconstpointer) |
877 | { |
878 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
879 | gboolean enabled = webkit_settings_get_enable_media_stream(settings); |
880 | webkit_settings_set_enable_media_stream(settings, TRUE); |
881 | |
882 | #if PLATFORM(GTK) |
883 | test->showInWindowAndWaitUntilMapped(); |
884 | #endif |
885 | static const char* userMediaRequestHTML = |
886 | "<html>" |
887 | " <script>" |
888 | " function runTest()" |
889 | " {" |
890 | " navigator.webkitGetUserMedia({audio: true, video: true}," |
891 | " function(s) { document.title = \"OK\" }," |
892 | " function(e) { document.title = e.name });" |
893 | " }" |
894 | " </script>" |
895 | " <body onload='runTest();'></body>" |
896 | "</html>" ; |
897 | |
898 | test->m_verifyMediaTypes = TRUE; |
899 | test->m_expectedAudioMedia = TRUE; |
900 | test->m_expectedVideoMedia = TRUE; |
901 | |
902 | // Test denying a permission request. |
903 | test->m_allowPermissionRequests = false; |
904 | test->loadHtml(userMediaRequestHTML, nullptr); |
905 | test->waitUntilTitleChangedTo("PermissionDeniedError" ); |
906 | |
907 | // Test allowing a permission request. |
908 | test->m_allowPermissionRequests = true; |
909 | test->loadHtml(userMediaRequestHTML, nullptr); |
910 | test->waitUntilTitleChangedTo("OK" ); |
911 | |
912 | webkit_settings_set_enable_media_stream(settings, enabled); |
913 | } |
914 | |
915 | static void testWebViewAudioOnlyUserMediaPermissionRequests(UIClientTest* test, gconstpointer) |
916 | { |
917 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
918 | gboolean enabled = webkit_settings_get_enable_media_stream(settings); |
919 | webkit_settings_set_enable_media_stream(settings, TRUE); |
920 | |
921 | #if PLATFORM(GTK) |
922 | test->showInWindowAndWaitUntilMapped(); |
923 | #endif |
924 | static const char* userMediaRequestHTML = |
925 | "<html>" |
926 | " <script>" |
927 | " function runTest()" |
928 | " {" |
929 | " navigator.webkitGetUserMedia({audio: true, video: false}," |
930 | " function(s) { document.title = \"OK\" }," |
931 | " function(e) { document.title = e.name });" |
932 | " }" |
933 | " </script>" |
934 | " <body onload='runTest();'></body>" |
935 | "</html>" ; |
936 | |
937 | test->m_verifyMediaTypes = TRUE; |
938 | test->m_expectedAudioMedia = TRUE; |
939 | test->m_expectedVideoMedia = FALSE; |
940 | |
941 | // Test denying a permission request. |
942 | test->m_allowPermissionRequests = false; |
943 | test->loadHtml(userMediaRequestHTML, nullptr); |
944 | test->waitUntilTitleChangedTo("PermissionDeniedError" ); |
945 | |
946 | webkit_settings_set_enable_media_stream(settings, enabled); |
947 | } |
948 | #endif // ENABLE(MEDIA_STREAM) |
949 | |
950 | #if PLATFORM(GTK) |
951 | class FileChooserTest: public UIClientTest { |
952 | public: |
953 | MAKE_GLIB_TEST_FIXTURE(FileChooserTest); |
954 | |
955 | FileChooserTest() |
956 | { |
957 | g_signal_connect(m_webView, "run-file-chooser" , G_CALLBACK(runFileChooserCallback), this); |
958 | } |
959 | |
960 | static gboolean runFileChooserCallback(WebKitWebView*, WebKitFileChooserRequest* request, FileChooserTest* test) |
961 | { |
962 | test->runFileChooser(request); |
963 | return TRUE; |
964 | } |
965 | |
966 | void runFileChooser(WebKitFileChooserRequest* request) |
967 | { |
968 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request)); |
969 | m_fileChooserRequest = request; |
970 | g_main_loop_quit(m_mainLoop); |
971 | } |
972 | |
973 | WebKitFileChooserRequest* clickMouseButtonAndWaitForFileChooserRequest(int x, int y) |
974 | { |
975 | clickMouseButton(x, y); |
976 | g_main_loop_run(m_mainLoop); |
977 | return m_fileChooserRequest.get(); |
978 | } |
979 | |
980 | private: |
981 | GRefPtr<WebKitFileChooserRequest> m_fileChooserRequest; |
982 | }; |
983 | |
984 | static void testWebViewFileChooserRequest(FileChooserTest* test, gconstpointer) |
985 | { |
986 | #if PLATFORM(GTK) |
987 | test->showInWindowAndWaitUntilMapped(); |
988 | #endif |
989 | static const char* fileChooserHTMLFormat = "<html><body><input style='position:absolute;left:0;top:0;margin:0;padding:0' type='file' %s/></body></html>" ; |
990 | |
991 | // Multiple selections not allowed, no MIME filtering. |
992 | GUniquePtr<char> simpleFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, "" )); |
993 | test->loadHtml(simpleFileUploadHTML.get(), 0); |
994 | test->waitUntilLoadFinished(); |
995 | WebKitFileChooserRequest* fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5); |
996 | g_assert_false(webkit_file_chooser_request_get_select_multiple(fileChooserRequest)); |
997 | |
998 | const gchar* const* mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest); |
999 | g_assert_null(mimeTypes); |
1000 | #if PLATFORM(GTK) |
1001 | GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest); |
1002 | g_assert_null(filter); |
1003 | #endif |
1004 | const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest); |
1005 | g_assert_null(selectedFiles); |
1006 | webkit_file_chooser_request_cancel(fileChooserRequest); |
1007 | |
1008 | // Multiple selections allowed, no MIME filtering, some pre-selected files. |
1009 | GUniquePtr<char> multipleSelectionFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, "multiple" )); |
1010 | test->loadHtml(multipleSelectionFileUploadHTML.get(), 0); |
1011 | test->waitUntilLoadFinished(); |
1012 | fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5); |
1013 | g_assert_true(webkit_file_chooser_request_get_select_multiple(fileChooserRequest)); |
1014 | |
1015 | mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest); |
1016 | g_assert_null(mimeTypes); |
1017 | #if PLATFORM(GTK) |
1018 | filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest); |
1019 | g_assert_null(filter); |
1020 | #endif |
1021 | selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest); |
1022 | g_assert_null(selectedFiles); |
1023 | |
1024 | // Select some files. |
1025 | const gchar* filesToSelect[4] = { "/foo" , "/foo/bar" , "/foo/bar/baz" , 0 }; |
1026 | webkit_file_chooser_request_select_files(fileChooserRequest, filesToSelect); |
1027 | |
1028 | // Check the files that have been just selected. |
1029 | selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest); |
1030 | g_assert_nonnull(selectedFiles); |
1031 | g_assert_cmpstr(selectedFiles[0], ==, "/foo" ); |
1032 | g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar" ); |
1033 | g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz" ); |
1034 | g_assert_null(selectedFiles[3]); |
1035 | |
1036 | // Perform another request to check if the list of files selected |
1037 | // in the previous step appears now as part of the new request. |
1038 | fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5); |
1039 | selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest); |
1040 | g_assert_nonnull(selectedFiles); |
1041 | g_assert_cmpstr(selectedFiles[0], ==, "/foo" ); |
1042 | g_assert_cmpstr(selectedFiles[1], ==, "/foo/bar" ); |
1043 | g_assert_cmpstr(selectedFiles[2], ==, "/foo/bar/baz" ); |
1044 | g_assert_null(selectedFiles[3]); |
1045 | webkit_file_chooser_request_cancel(fileChooserRequest); |
1046 | |
1047 | // Multiple selections not allowed, only accept images, audio and video files.. |
1048 | GUniquePtr<char> mimeFilteredFileUploadHTML(g_strdup_printf(fileChooserHTMLFormat, "accept='audio/*,video/*,image/*'" )); |
1049 | test->loadHtml(mimeFilteredFileUploadHTML.get(), 0); |
1050 | test->waitUntilLoadFinished(); |
1051 | fileChooserRequest = test->clickMouseButtonAndWaitForFileChooserRequest(5, 5); |
1052 | g_assert_false(webkit_file_chooser_request_get_select_multiple(fileChooserRequest)); |
1053 | |
1054 | mimeTypes = webkit_file_chooser_request_get_mime_types(fileChooserRequest); |
1055 | g_assert_nonnull(mimeTypes); |
1056 | g_assert_cmpstr(mimeTypes[0], ==, "audio/*" ); |
1057 | g_assert_cmpstr(mimeTypes[1], ==, "video/*" ); |
1058 | g_assert_cmpstr(mimeTypes[2], ==, "image/*" ); |
1059 | g_assert_null(mimeTypes[3]); |
1060 | |
1061 | #if PLATFORM(GTK) |
1062 | filter = webkit_file_chooser_request_get_mime_types_filter(fileChooserRequest); |
1063 | g_assert_true(GTK_IS_FILE_FILTER(filter)); |
1064 | g_assert_true(checkMimeTypeForFilter(filter, "audio/*" )); |
1065 | g_assert_true(checkMimeTypeForFilter(filter, "video/*" )); |
1066 | g_assert_true(checkMimeTypeForFilter(filter, "image/*" )); |
1067 | #endif |
1068 | |
1069 | selectedFiles = webkit_file_chooser_request_get_selected_files(fileChooserRequest); |
1070 | g_assert_null(selectedFiles); |
1071 | webkit_file_chooser_request_cancel(fileChooserRequest); |
1072 | } |
1073 | #endif // PLATFORM(GTK) |
1074 | |
1075 | #if PLATFORM(GTK) |
1076 | class ColorChooserTest: public WebViewTest { |
1077 | public: |
1078 | MAKE_GLIB_TEST_FIXTURE(ColorChooserTest); |
1079 | |
1080 | static gboolean runColorChooserCallback(WebKitWebView*, WebKitColorChooserRequest* request, ColorChooserTest* test) |
1081 | { |
1082 | test->runColorChooser(request); |
1083 | return TRUE; |
1084 | } |
1085 | |
1086 | static void requestFinishedCallback(WebKitColorChooserRequest* request, ColorChooserTest* test) |
1087 | { |
1088 | g_assert_true(test->m_request.get() == request); |
1089 | test->m_request = nullptr; |
1090 | if (g_main_loop_is_running(test->m_mainLoop)) |
1091 | g_main_loop_quit(test->m_mainLoop); |
1092 | } |
1093 | |
1094 | ColorChooserTest() |
1095 | { |
1096 | g_signal_connect(m_webView, "run-color-chooser" , G_CALLBACK(runColorChooserCallback), this); |
1097 | } |
1098 | |
1099 | void runColorChooser(WebKitColorChooserRequest* request) |
1100 | { |
1101 | g_assert_true(WEBKIT_IS_COLOR_CHOOSER_REQUEST(request)); |
1102 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request)); |
1103 | m_request = request; |
1104 | g_signal_connect(request, "finished" , G_CALLBACK(requestFinishedCallback), this); |
1105 | g_main_loop_quit(m_mainLoop); |
1106 | } |
1107 | |
1108 | void finishRequest() |
1109 | { |
1110 | g_assert_nonnull(m_request.get()); |
1111 | webkit_color_chooser_request_finish(m_request.get()); |
1112 | g_assert_null(m_request); |
1113 | } |
1114 | |
1115 | void cancelRequest() |
1116 | { |
1117 | g_assert_nonnull(m_request.get()); |
1118 | webkit_color_chooser_request_cancel(m_request.get()); |
1119 | g_assert_null(m_request); |
1120 | } |
1121 | |
1122 | WebKitColorChooserRequest* clickMouseButtonAndWaitForColorChooserRequest(int x, int y) |
1123 | { |
1124 | clickMouseButton(x, y); |
1125 | g_main_loop_run(m_mainLoop); |
1126 | g_assert_nonnull(m_request.get()); |
1127 | return m_request.get(); |
1128 | } |
1129 | |
1130 | private: |
1131 | GRefPtr<WebKitColorChooserRequest> m_request; |
1132 | }; |
1133 | |
1134 | static void testWebViewColorChooserRequest(ColorChooserTest* test, gconstpointer) |
1135 | { |
1136 | static const char* colorChooserHTMLFormat = "<html><body><input style='position:absolute;left:1;top:1;margin:0;padding:0;width:45;height:25' type='color' %s/></body></html>" ; |
1137 | test->showInWindowAndWaitUntilMapped(); |
1138 | |
1139 | GUniquePtr<char> defaultColorHTML(g_strdup_printf(colorChooserHTMLFormat, "" )); |
1140 | test->loadHtml(defaultColorHTML.get(), nullptr); |
1141 | test->waitUntilLoadFinished(); |
1142 | WebKitColorChooserRequest* request = test->clickMouseButtonAndWaitForColorChooserRequest(5, 5); |
1143 | |
1144 | // Default color is black (#000000). |
1145 | GdkRGBA rgba1; |
1146 | GdkRGBA rgba2 = { 0., 0., 0., 1. }; |
1147 | webkit_color_chooser_request_get_rgba(request, &rgba1); |
1148 | g_assert_true(gdk_rgba_equal(&rgba1, &rgba2)); |
1149 | |
1150 | // Set a different color. |
1151 | rgba2.green = 1; |
1152 | webkit_color_chooser_request_set_rgba(request, &rgba2); |
1153 | webkit_color_chooser_request_get_rgba(request, &rgba1); |
1154 | g_assert_true(gdk_rgba_equal(&rgba1, &rgba2)); |
1155 | |
1156 | GdkRectangle rect; |
1157 | webkit_color_chooser_request_get_element_rectangle(request, &rect); |
1158 | g_assert_cmpint(rect.x, == , 1); |
1159 | g_assert_cmpint(rect.y, == , 1); |
1160 | g_assert_cmpint(rect.width, == , 45); |
1161 | g_assert_cmpint(rect.height, == , 25); |
1162 | |
1163 | test->finishRequest(); |
1164 | |
1165 | // Use an initial color. |
1166 | GUniquePtr<char> initialColorHTML(g_strdup_printf(colorChooserHTMLFormat, "value='#FF00FF'" )); |
1167 | test->loadHtml(initialColorHTML.get(), nullptr); |
1168 | test->waitUntilLoadFinished(); |
1169 | request = test->clickMouseButtonAndWaitForColorChooserRequest(5, 5); |
1170 | |
1171 | webkit_color_chooser_request_get_rgba(request, &rgba1); |
1172 | GdkRGBA rgba3 = { 1., 0., 1., 1. }; |
1173 | g_assert_true(gdk_rgba_equal(&rgba1, &rgba3)); |
1174 | |
1175 | test->cancelRequest(); |
1176 | } |
1177 | #endif // PLATFORM(GTK) |
1178 | |
1179 | void beforeAll() |
1180 | { |
1181 | UIClientTest::add("WebKitWebView" , "create-ready-close" , testWebViewCreateReadyClose); |
1182 | // FIXME: Implement mouse clicks in WPE. |
1183 | #if PLATFORM(GTK) |
1184 | CreateNavigationDataTest::add("WebKitWebView" , "create-navigation-data" , testWebViewCreateNavigationData); |
1185 | #endif |
1186 | ModalDialogsTest::add("WebKitWebView" , "allow-modal-dialogs" , testWebViewAllowModalDialogs); |
1187 | ModalDialogsTest::add("WebKitWebView" , "disallow-modal-dialogs" , testWebViewDisallowModalDialogs); |
1188 | UIClientTest::add("WebKitWebView" , "javascript-dialogs" , testWebViewJavaScriptDialogs); |
1189 | UIClientTest::add("WebKitWebView" , "window-properties" , testWebViewWindowProperties); |
1190 | // FIXME: Implement mouse move in WPE. |
1191 | #if PLATFORM(GTK) |
1192 | UIClientTest::add("WebKitWebView" , "mouse-target" , testWebViewMouseTarget); |
1193 | #endif |
1194 | UIClientTest::add("WebKitWebView" , "geolocation-permission-requests" , testWebViewGeolocationPermissionRequests); |
1195 | #if ENABLE(MEDIA_STREAM) |
1196 | UIClientTest::add("WebKitWebView" , "usermedia-enumeratedevices-permission-check" , testWebViewUserMediaEnumerateDevicesPermissionCheck); |
1197 | UIClientTest::add("WebKitWebView" , "usermedia-permission-requests" , testWebViewUserMediaPermissionRequests); |
1198 | UIClientTest::add("WebKitWebView" , "audio-usermedia-permission-request" , testWebViewAudioOnlyUserMediaPermissionRequests); |
1199 | #endif |
1200 | // FIXME: Implement mouse click in WPE. |
1201 | #if PLATFORM(GTK) |
1202 | FileChooserTest::add("WebKitWebView" , "file-chooser-request" , testWebViewFileChooserRequest); |
1203 | #endif |
1204 | #if PLATFORM(GTK) |
1205 | ColorChooserTest::add("WebKitWebView" , "color-chooser-request" , testWebViewColorChooserRequest); |
1206 | #endif |
1207 | } |
1208 | |
1209 | void afterAll() |
1210 | { |
1211 | } |
1212 | |