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
29static 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
50static 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
65static 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
73static 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
83static GtkPrinter* findPrintToFilePrinter()
84{
85 GtkPrinter* printer = 0;
86 gtk_enumerate_printers(testPrintOperationPrintPrinter, &printer, 0, TRUE);
87 return printer;
88}
89
90class PrintTest: public WebViewTest {
91public:
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
124static 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
157static 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
191class CloseAfterPrintTest: public WebViewTest {
192public:
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
284static 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
290class PrintCustomWidgetTest: public WebViewTest {
291public:
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
422static 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
455void 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
467void afterAll()
468{
469}
470