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 <glib/gstdio.h> |
23 | #include <wtf/glib/GRefPtr.h> |
24 | |
25 | #ifdef HAVE_GTK_UNIX_PRINTING |
26 | #include <gtk/gtkunixprint.h> |
27 | #endif |
28 | |
29 | static void testPrintOperationPrintSettings(WebViewTest* test, gconstpointer) |
30 | { |
31 | GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(test->m_webView)); |
32 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printOperation.get())); |
33 | |
34 | g_assert_null(webkit_print_operation_get_print_settings(printOperation.get())); |
35 | g_assert_null(webkit_print_operation_get_page_setup(printOperation.get())); |
36 | |
37 | GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new()); |
38 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printSettings.get())); |
39 | |
40 | GRefPtr<GtkPageSetup> pageSetup = adoptGRef(gtk_page_setup_new()); |
41 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(pageSetup.get())); |
42 | |
43 | webkit_print_operation_set_print_settings(printOperation.get(), printSettings.get()); |
44 | webkit_print_operation_set_page_setup(printOperation.get(), pageSetup.get()); |
45 | |
46 | g_assert_true(webkit_print_operation_get_print_settings(printOperation.get()) == printSettings.get()); |
47 | g_assert_true(webkit_print_operation_get_page_setup(printOperation.get()) == pageSetup.get()); |
48 | } |
49 | |
50 | static gboolean webViewPrintCallback(WebKitWebView* webView, WebKitPrintOperation* printOperation, WebViewTest* test) |
51 | { |
52 | g_assert_true(webView == test->m_webView); |
53 | |
54 | g_assert_true(WEBKIT_IS_PRINT_OPERATION(printOperation)); |
55 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printOperation)); |
56 | |
57 | g_assert_null(webkit_print_operation_get_print_settings(printOperation)); |
58 | g_assert_null(webkit_print_operation_get_page_setup(printOperation)); |
59 | |
60 | g_main_loop_quit(test->m_mainLoop); |
61 | |
62 | return TRUE; |
63 | } |
64 | |
65 | static void testWebViewPrint(WebViewTest* test, gconstpointer) |
66 | { |
67 | g_signal_connect(test->m_webView, "print" , G_CALLBACK(webViewPrintCallback), test); |
68 | test->loadHtml("<html><body onLoad=\"print();\">WebKitGTK+ printing test</body></html>" , 0); |
69 | g_main_loop_run(test->m_mainLoop); |
70 | } |
71 | |
72 | #ifdef HAVE_GTK_UNIX_PRINTING |
73 | static gboolean testPrintOperationPrintPrinter(GtkPrinter* printer, gpointer userData) |
74 | { |
75 | if (strcmp(gtk_printer_get_name(printer), "Print to File" )) |
76 | return FALSE; |
77 | |
78 | GtkPrinter** foundPrinter = static_cast<GtkPrinter**>(userData); |
79 | *foundPrinter = static_cast<GtkPrinter*>(g_object_ref(printer)); |
80 | return TRUE; |
81 | } |
82 | |
83 | static GtkPrinter* findPrintToFilePrinter() |
84 | { |
85 | GtkPrinter* printer = 0; |
86 | gtk_enumerate_printers(testPrintOperationPrintPrinter, &printer, 0, TRUE); |
87 | return printer; |
88 | } |
89 | |
90 | class PrintTest: public WebViewTest { |
91 | public: |
92 | MAKE_GLIB_TEST_FIXTURE(PrintTest); |
93 | |
94 | static void printFinishedCallback(WebKitPrintOperation*, PrintTest* test) |
95 | { |
96 | g_main_loop_quit(test->m_mainLoop); |
97 | } |
98 | |
99 | static void printFailedCallback(WebKitPrintOperation*, GError* error, PrintTest* test) |
100 | { |
101 | g_assert_cmpuint(test->m_expectedError, !=, 0); |
102 | g_assert_nonnull(error); |
103 | g_assert_error(error, WEBKIT_PRINT_ERROR, test->m_expectedError); |
104 | } |
105 | |
106 | PrintTest() |
107 | : m_expectedError(0) |
108 | { |
109 | m_printOperation = adoptGRef(webkit_print_operation_new(m_webView)); |
110 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_printOperation.get())); |
111 | g_signal_connect(m_printOperation.get(), "finished" , G_CALLBACK(printFinishedCallback), this); |
112 | g_signal_connect(m_printOperation.get(), "failed" , G_CALLBACK(printFailedCallback), this); |
113 | } |
114 | |
115 | void waitUntilPrintFinished() |
116 | { |
117 | g_main_loop_run(m_mainLoop); |
118 | } |
119 | |
120 | GRefPtr<WebKitPrintOperation> m_printOperation; |
121 | unsigned m_expectedError; |
122 | }; |
123 | |
124 | static void testPrintOperationPrint(PrintTest* test, gconstpointer) |
125 | { |
126 | test->loadHtml("<html><body>WebKitGTK+ printing test</body></html>" , 0); |
127 | test->waitUntilLoadFinished(); |
128 | |
129 | GRefPtr<GtkPrinter> printer = adoptGRef(findPrintToFilePrinter()); |
130 | if (!printer) { |
131 | g_message("%s" , "Cannot test WebKitPrintOperation/print: no suitable printer found" ); |
132 | return; |
133 | } |
134 | |
135 | GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-print.pdf" , nullptr)); |
136 | GRefPtr<GFile> outputFile = adoptGRef(g_file_new_for_path(outputFilename.get())); |
137 | GUniquePtr<char> outputURI(g_file_get_uri(outputFile.get())); |
138 | |
139 | GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new()); |
140 | gtk_print_settings_set_printer(printSettings.get(), gtk_printer_get_name(printer.get())); |
141 | gtk_print_settings_set(printSettings.get(), GTK_PRINT_SETTINGS_OUTPUT_URI, outputURI.get()); |
142 | |
143 | webkit_print_operation_set_print_settings(test->m_printOperation.get(), printSettings.get()); |
144 | webkit_print_operation_print(test->m_printOperation.get()); |
145 | test->waitUntilPrintFinished(); |
146 | |
147 | GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(outputFile.get(), |
148 | G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, |
149 | static_cast<GFileQueryInfoFlags>(0), 0, 0)); |
150 | g_assert_nonnull(fileInfo.get()); |
151 | g_assert_cmpint(g_file_info_get_size(fileInfo.get()), >, 0); |
152 | g_assert_cmpstr(g_file_info_get_content_type(fileInfo.get()), ==, "application/pdf" ); |
153 | |
154 | g_file_delete(outputFile.get(), 0, 0); |
155 | } |
156 | |
157 | static void testPrintOperationErrors(PrintTest* test, gconstpointer) |
158 | { |
159 | test->loadHtml("<html><body>WebKitGTK+ printing errors test</body></html>" , 0); |
160 | test->waitUntilLoadFinished(); |
161 | |
162 | GRefPtr<GtkPrinter> printer = adoptGRef(findPrintToFilePrinter()); |
163 | if (!printer) { |
164 | g_message("%s" , "Cannot test WebKitPrintOperation/print: no suitable printer found" ); |
165 | return; |
166 | } |
167 | |
168 | // General Error: invalid filename. |
169 | test->m_expectedError = WEBKIT_PRINT_ERROR_GENERAL; |
170 | GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new()); |
171 | gtk_print_settings_set_printer(printSettings.get(), gtk_printer_get_name(printer.get())); |
172 | gtk_print_settings_set(printSettings.get(), GTK_PRINT_SETTINGS_OUTPUT_URI, "file:///foo/bar" ); |
173 | webkit_print_operation_set_print_settings(test->m_printOperation.get(), printSettings.get()); |
174 | webkit_print_operation_print(test->m_printOperation.get()); |
175 | test->waitUntilPrintFinished(); |
176 | |
177 | // Printer not found error. |
178 | test->m_expectedError = WEBKIT_PRINT_ERROR_PRINTER_NOT_FOUND; |
179 | gtk_print_settings_set_printer(printSettings.get(), "The fake WebKit printer" ); |
180 | webkit_print_operation_print(test->m_printOperation.get()); |
181 | test->waitUntilPrintFinished(); |
182 | |
183 | // No pages to print: print even pages for a single page document. |
184 | test->m_expectedError = WEBKIT_PRINT_ERROR_INVALID_PAGE_RANGE; |
185 | gtk_print_settings_set_printer(printSettings.get(), gtk_printer_get_name(printer.get())); |
186 | gtk_print_settings_set_page_set(printSettings.get(), GTK_PAGE_SET_EVEN); |
187 | webkit_print_operation_print(test->m_printOperation.get()); |
188 | test->waitUntilPrintFinished(); |
189 | } |
190 | |
191 | class CloseAfterPrintTest: public WebViewTest { |
192 | public: |
193 | MAKE_GLIB_TEST_FIXTURE(CloseAfterPrintTest); |
194 | |
195 | static GtkWidget* webViewCreate(WebKitWebView* webView, WebKitNavigationAction*, CloseAfterPrintTest* test) |
196 | { |
197 | return test->createWebView(); |
198 | } |
199 | |
200 | static gboolean webViewPrint(WebKitWebView* webView, WebKitPrintOperation* printOperation, CloseAfterPrintTest* test) |
201 | { |
202 | test->print(printOperation); |
203 | return TRUE; |
204 | } |
205 | |
206 | static void printOperationFinished(WebKitPrintOperation* printOperation, CloseAfterPrintTest* test) |
207 | { |
208 | test->printFinished(); |
209 | } |
210 | |
211 | static void webViewClosed(WebKitWebView* webView, CloseAfterPrintTest* test) |
212 | { |
213 | gtk_widget_destroy(GTK_WIDGET(webView)); |
214 | test->m_webViewClosed = true; |
215 | if (test->m_printFinished) |
216 | g_main_loop_quit(test->m_mainLoop); |
217 | } |
218 | |
219 | CloseAfterPrintTest() |
220 | : m_webViewClosed(false) |
221 | , m_printFinished(false) |
222 | { |
223 | webkit_settings_set_javascript_can_open_windows_automatically(webkit_web_view_get_settings(m_webView), TRUE); |
224 | g_signal_connect(m_webView, "create" , G_CALLBACK(webViewCreate), this); |
225 | } |
226 | |
227 | GtkWidget* createWebView() |
228 | { |
229 | GtkWidget* newWebView = webkit_web_view_new_with_context(m_webContext.get()); |
230 | g_object_ref_sink(newWebView); |
231 | |
232 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newWebView)); |
233 | g_signal_connect(newWebView, "print" , G_CALLBACK(webViewPrint), this); |
234 | g_signal_connect(newWebView, "close" , G_CALLBACK(webViewClosed), this); |
235 | return newWebView; |
236 | } |
237 | |
238 | void print(WebKitPrintOperation* printOperation) |
239 | { |
240 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printOperation)); |
241 | |
242 | GRefPtr<GtkPrinter> printer = adoptGRef(findPrintToFilePrinter()); |
243 | if (!printer) { |
244 | g_message("%s" , "Cannot test WebKitPrintOperation/print: no suitable printer found" ); |
245 | return; |
246 | } |
247 | |
248 | GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-close-after-print.pdf" , nullptr)); |
249 | m_outputFile = adoptGRef(g_file_new_for_path(outputFilename.get())); |
250 | GUniquePtr<char> outputURI(g_file_get_uri(m_outputFile.get())); |
251 | |
252 | GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new()); |
253 | gtk_print_settings_set_printer(printSettings.get(), gtk_printer_get_name(printer.get())); |
254 | gtk_print_settings_set(printSettings.get(), GTK_PRINT_SETTINGS_OUTPUT_URI, outputURI.get()); |
255 | webkit_print_operation_set_print_settings(printOperation, printSettings.get()); |
256 | |
257 | m_printOperation = printOperation; |
258 | g_signal_connect(m_printOperation.get(), "finished" , G_CALLBACK(printOperationFinished), this); |
259 | webkit_print_operation_print(m_printOperation.get()); |
260 | } |
261 | |
262 | void printFinished() |
263 | { |
264 | m_printFinished = true; |
265 | m_printOperation = nullptr; |
266 | g_assert_nonnull(m_outputFile); |
267 | g_file_delete(m_outputFile.get(), 0, 0); |
268 | m_outputFile = nullptr; |
269 | if (m_webViewClosed) |
270 | g_main_loop_quit(m_mainLoop); |
271 | } |
272 | |
273 | void waitUntilPrintFinishedAndViewClosed() |
274 | { |
275 | g_main_loop_run(m_mainLoop); |
276 | } |
277 | |
278 | GRefPtr<WebKitPrintOperation> m_printOperation; |
279 | GRefPtr<GFile> m_outputFile; |
280 | bool m_webViewClosed; |
281 | bool m_printFinished; |
282 | }; |
283 | |
284 | static void testPrintOperationCloseAfterPrint(CloseAfterPrintTest* test, gconstpointer) |
285 | { |
286 | test->loadHtml("<html><body onLoad=\"w = window.open();w.print();w.close();\"></body></html>" , 0); |
287 | test->waitUntilPrintFinishedAndViewClosed(); |
288 | } |
289 | |
290 | class PrintCustomWidgetTest: public WebViewTest { |
291 | public: |
292 | MAKE_GLIB_TEST_FIXTURE(PrintCustomWidgetTest); |
293 | |
294 | static void applyCallback(WebKitPrintCustomWidget*, PrintCustomWidgetTest* test) |
295 | { |
296 | test->m_applyEmitted = true; |
297 | } |
298 | |
299 | static gboolean scheduleJumpToCustomWidget(PrintCustomWidgetTest* test) |
300 | { |
301 | test->jumpToCustomWidget(); |
302 | |
303 | return FALSE; |
304 | } |
305 | |
306 | static void updateCallback(WebKitPrintCustomWidget* customWidget, GtkPageSetup*, GtkPrintSettings*, PrintCustomWidgetTest* test) |
307 | { |
308 | g_assert_true(test->m_widget == webkit_print_custom_widget_get_widget(customWidget)); |
309 | |
310 | test->m_updateEmitted = true; |
311 | // Would be nice to avoid the 1 second timeout here - but I didn't found |
312 | // a way to do so without making the test flaky. |
313 | g_timeout_add_seconds(1, reinterpret_cast<GSourceFunc>(scheduleJumpToCustomWidget), test); |
314 | } |
315 | |
316 | static void widgetRealizeCallback(GtkWidget* widget, PrintCustomWidgetTest* test) |
317 | { |
318 | g_assert_true(GTK_IS_LABEL(widget)); |
319 | g_assert_cmpstr(gtk_label_get_text(GTK_LABEL(widget)), ==, "Label" ); |
320 | |
321 | test->m_widgetRealized = true; |
322 | test->startPrinting(); |
323 | } |
324 | |
325 | static WebKitPrintCustomWidget* createCustomWidgetCallback(WebKitPrintOperation* printOperation, PrintCustomWidgetTest* test) |
326 | { |
327 | test->m_createEmitted = true; |
328 | WebKitPrintCustomWidget* printCustomWidget = test->createPrintCustomWidget(); |
329 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(printCustomWidget)); |
330 | g_signal_connect(printCustomWidget, "apply" , G_CALLBACK(applyCallback), test); |
331 | g_signal_connect(printCustomWidget, "update" , G_CALLBACK(updateCallback), test); |
332 | |
333 | GtkWidget* widget = webkit_print_custom_widget_get_widget(printCustomWidget); |
334 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(widget)); |
335 | g_signal_connect(widget, "realize" , G_CALLBACK(widgetRealizeCallback), test); |
336 | |
337 | return printCustomWidget; |
338 | } |
339 | |
340 | static gboolean scheduleMovementThroughDialog(PrintCustomWidgetTest* test) |
341 | { |
342 | test->jumpToFirstPrinter(); |
343 | |
344 | return FALSE; |
345 | } |
346 | |
347 | static gboolean openPrintDialog(PrintCustomWidgetTest* test) |
348 | { |
349 | g_idle_add(reinterpret_cast<GSourceFunc>(scheduleMovementThroughDialog), test); |
350 | test->m_response = webkit_print_operation_run_dialog(test->m_printOperation.get(), GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(test->m_webView)))); |
351 | |
352 | return FALSE; |
353 | } |
354 | |
355 | static void printOperationFinished(WebKitPrintOperation* printOperation, PrintCustomWidgetTest* test) |
356 | { |
357 | test->printFinished(); |
358 | } |
359 | |
360 | void printFinished() |
361 | { |
362 | g_assert_nonnull(m_outputFile); |
363 | g_file_delete(m_outputFile.get(), nullptr, nullptr); |
364 | m_outputFile = nullptr; |
365 | g_main_loop_quit(m_mainLoop); |
366 | } |
367 | |
368 | void createWebKitPrintOperation() |
369 | { |
370 | m_printOperation = adoptGRef(webkit_print_operation_new(m_webView)); |
371 | g_assert_nonnull(m_printOperation); |
372 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_printOperation.get())); |
373 | |
374 | g_signal_connect(m_printOperation.get(), "create-custom-widget" , G_CALLBACK(createCustomWidgetCallback), this); |
375 | g_signal_connect(m_printOperation.get(), "finished" , G_CALLBACK(printOperationFinished), this); |
376 | } |
377 | |
378 | WebKitPrintCustomWidget* createPrintCustomWidget() |
379 | { |
380 | m_widget = gtk_label_new("Label" ); |
381 | return webkit_print_custom_widget_new(m_widget, "Custom Widget" ); |
382 | } |
383 | |
384 | void startPrinting() |
385 | { |
386 | // To start printing it is enough to press the Return key |
387 | keyStroke(GDK_KEY_Return); |
388 | } |
389 | |
390 | void jumpToFirstPrinter() |
391 | { |
392 | // Initially the GtkNotebook has focus, so we just need to press the Tab |
393 | // key to jump to the first printer |
394 | keyStroke(GDK_KEY_Tab); |
395 | } |
396 | |
397 | void jumpToCustomWidget() |
398 | { |
399 | // Jump back to the GtkNotebook |
400 | keyStroke(GDK_KEY_Tab, GDK_SHIFT_MASK); |
401 | // Custom widget is on the third tab |
402 | keyStroke(GDK_KEY_Right); |
403 | keyStroke(GDK_KEY_Right); |
404 | } |
405 | |
406 | void openDialogMoveThroughItAndWaitUntilClosed() |
407 | { |
408 | g_idle_add(reinterpret_cast<GSourceFunc>(openPrintDialog), this); |
409 | g_main_loop_run(m_mainLoop); |
410 | } |
411 | |
412 | GRefPtr<WebKitPrintOperation> m_printOperation; |
413 | GRefPtr<GFile> m_outputFile; |
414 | GtkWidget* m_widget; |
415 | bool m_widgetRealized {false}; |
416 | bool m_applyEmitted {false}; |
417 | bool m_updateEmitted {false}; |
418 | bool m_createEmitted {false}; |
419 | WebKitPrintOperationResponse m_response {WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL}; |
420 | }; |
421 | |
422 | static void testPrintCustomWidget(PrintCustomWidgetTest* test, gconstpointer) |
423 | { |
424 | test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL, 0, 0); |
425 | |
426 | test->loadHtml("<html><body>Text</body></html>" , 0); |
427 | test->waitUntilLoadFinished(); |
428 | |
429 | test->createWebKitPrintOperation(); |
430 | |
431 | GRefPtr<GtkPrinter> printer = adoptGRef(findPrintToFilePrinter()); |
432 | if (!printer) { |
433 | g_message("%s" , "Cannot test WebKitPrintOperation/print: no suitable printer found" ); |
434 | return; |
435 | } |
436 | |
437 | GUniquePtr<char> outputFilename(g_build_filename(Test::dataDirectory(), "webkit-close-after-print.pdf" , nullptr)); |
438 | test->m_outputFile = adoptGRef(g_file_new_for_path(outputFilename.get())); |
439 | GUniquePtr<char> outputURI(g_file_get_uri(test->m_outputFile.get())); |
440 | |
441 | GRefPtr<GtkPrintSettings> printSettings = adoptGRef(gtk_print_settings_new()); |
442 | gtk_print_settings_set(printSettings.get(), GTK_PRINT_SETTINGS_OUTPUT_URI, outputURI.get()); |
443 | webkit_print_operation_set_print_settings(test->m_printOperation.get(), printSettings.get()); |
444 | |
445 | test->openDialogMoveThroughItAndWaitUntilClosed(); |
446 | |
447 | g_assert_cmpuint(test->m_response, ==, WEBKIT_PRINT_OPERATION_RESPONSE_PRINT); |
448 | g_assert_true(test->m_createEmitted); |
449 | g_assert_true(test->m_widgetRealized); |
450 | g_assert_true(test->m_updateEmitted); |
451 | g_assert_true(test->m_applyEmitted); |
452 | } |
453 | #endif // HAVE_GTK_UNIX_PRINTING |
454 | |
455 | void beforeAll() |
456 | { |
457 | WebViewTest::add("WebKitPrintOperation" , "printing-settings" , testPrintOperationPrintSettings); |
458 | WebViewTest::add("WebKitWebView" , "print" , testWebViewPrint); |
459 | #ifdef HAVE_GTK_UNIX_PRINTING |
460 | PrintTest::add("WebKitPrintOperation" , "print" , testPrintOperationPrint); |
461 | PrintTest::add("WebKitPrintOperation" , "print-errors" , testPrintOperationErrors); |
462 | CloseAfterPrintTest::add("WebKitPrintOperation" , "close-after-print" , testPrintOperationCloseAfterPrint); |
463 | PrintCustomWidgetTest::add("WebKitPrintOperation" , "custom-widget" , testPrintCustomWidget); |
464 | #endif |
465 | } |
466 | |
467 | void afterAll() |
468 | { |
469 | } |
470 | |