summaryrefslogtreecommitdiff
path: root/Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp b/Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp
new file mode 100644
index 000000000..704adf3ea
--- /dev/null
+++ b/Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPrintOperationGtk.h"
+
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+#include <WebCore/IntRect.h>
+#include <WebCore/NotImplemented.h>
+#include <WebCore/PlatformContextCairo.h>
+#include <WebCore/PrintContext.h>
+#include <gtk/gtk.h>
+#include <wtf/Vector.h>
+#include <wtf/gobject/GOwnPtr.h>
+
+#ifdef HAVE_GTK_UNIX_PRINTING
+#include <cairo-pdf.h>
+#include <cairo-ps.h>
+#include <gtk/gtkunixprint.h>
+#endif
+
+namespace WebKit {
+
+#ifdef HAVE_GTK_UNIX_PRINTING
+class WebPrintOperationGtkUnix: public WebPrintOperationGtk {
+public:
+ WebPrintOperationGtkUnix(WebPage* page, const PrintInfo& printInfo)
+ : WebPrintOperationGtk(page, printInfo)
+ , m_printJob(0)
+ {
+ }
+
+ static gboolean enumeratePrintersFunction(GtkPrinter* printer, WebPrintOperationGtkUnix* printOperation)
+ {
+ GtkPrinter* selectedPrinter = 0;
+ const char* printerName = gtk_print_settings_get_printer(printOperation->printSettings());
+ if (printerName) {
+ if (!strcmp(printerName, gtk_printer_get_name(printer)))
+ selectedPrinter = printer;
+ } else if (gtk_printer_is_default(printer))
+ selectedPrinter = printer;
+
+ if (!selectedPrinter)
+ return FALSE;
+
+ static int jobNumber = 0;
+ const char* applicationName = g_get_application_name();
+ GOwnPtr<char>jobName(g_strdup_printf("%s job #%d", applicationName ? applicationName : "WebKit", ++jobNumber));
+ printOperation->m_printJob = adoptGRef(gtk_print_job_new(jobName.get(), selectedPrinter,
+ printOperation->printSettings(),
+ printOperation->pageSetup()));
+ return TRUE;
+ }
+
+ static void enumeratePrintersFinished(WebPrintOperationGtkUnix* printOperation)
+ {
+ if (!printOperation->m_printJob) {
+ // FIXME: Printing error.
+ return;
+ }
+
+ cairo_surface_t* surface = gtk_print_job_get_surface(printOperation->m_printJob.get(), 0);
+ if (!surface) {
+ // FIXME: Printing error.
+ return;
+ }
+
+ int rangesCount;
+ printOperation->m_pageRanges = gtk_print_job_get_page_ranges(printOperation->m_printJob.get(), &rangesCount);
+ printOperation->m_pageRangesCount = rangesCount;
+ printOperation->m_pagesToPrint = gtk_print_job_get_pages(printOperation->m_printJob.get());
+ printOperation->m_needsRotation = gtk_print_job_get_rotate(printOperation->m_printJob.get());
+
+ printOperation->print(surface, 72, 72);
+ }
+
+ void startPrint(WebCore::PrintContext* printContext, uint64_t callbackID)
+ {
+ m_printContext = printContext;
+ m_callbackID = callbackID;
+ gtk_enumerate_printers(reinterpret_cast<GtkPrinterFunc>(enumeratePrintersFunction), this,
+ reinterpret_cast<GDestroyNotify>(enumeratePrintersFinished), FALSE);
+ }
+
+ void startPage(cairo_t* cr)
+ {
+ GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(m_pageSetup.get());
+ double width = gtk_paper_size_get_width(paperSize, GTK_UNIT_POINTS);
+ double height = gtk_paper_size_get_height(paperSize, GTK_UNIT_POINTS);
+
+ cairo_surface_t* surface = gtk_print_job_get_surface(m_printJob.get(), 0);
+ cairo_surface_type_t surfaceType = cairo_surface_get_type(surface);
+ if (surfaceType == CAIRO_SURFACE_TYPE_PS) {
+ cairo_ps_surface_set_size(surface, width, height);
+ cairo_ps_surface_dsc_begin_page_setup(surface);
+
+ switch (gtk_page_setup_get_orientation(m_pageSetup.get())) {
+ case GTK_PAGE_ORIENTATION_PORTRAIT:
+ case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+ cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Portrait");
+ break;
+ case GTK_PAGE_ORIENTATION_LANDSCAPE:
+ case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+ cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Landscape");
+ break;
+ }
+ } else if (surfaceType == CAIRO_SURFACE_TYPE_PDF)
+ cairo_pdf_surface_set_size(surface, width, height);
+ }
+
+ void endPage(cairo_t* cr)
+ {
+ cairo_show_page(cr);
+ }
+
+ static void printJobComplete(GtkPrintJob* printJob, WebPrintOperationGtkUnix* printOperation, const GError*)
+ {
+ printOperation->m_printJob = 0;
+ }
+
+ static void printJobFinished(WebPrintOperationGtkUnix* printOperation)
+ {
+ printOperation->deref();
+ }
+
+ void endPrint()
+ {
+ cairo_surface_finish(gtk_print_job_get_surface(m_printJob.get(), 0));
+ // Make sure the operation is alive until the job is sent.
+ ref();
+ gtk_print_job_send(m_printJob.get(), reinterpret_cast<GtkPrintJobCompleteFunc>(printJobComplete), this,
+ reinterpret_cast<GDestroyNotify>(printJobFinished));
+ }
+
+ GRefPtr<GtkPrintJob> m_printJob;
+};
+#endif
+
+#ifdef G_OS_WIN32
+class WebPrintOperationGtkWin32: public WebPrintOperationGtk {
+public:
+ WebPrintOperationGtkWin32(WebPage* page, const PrintInfo& printInfo)
+ : WebPrintOperationGtk(page, printInfo)
+ {
+ }
+
+ void startPrint(WebCore::PrintContext* printContext, uint64_t callbackID)
+ {
+ m_printContext = printContext;
+ m_callbackID = callbackID;
+ notImplemented();
+ }
+
+ void startPage(cairo_t* cr)
+ {
+ notImplemented();
+ }
+
+ void endPage(cairo_t* cr)
+ {
+ notImplemented();
+ }
+
+ void endPrint()
+ {
+ notImplemented();
+ }
+};
+#endif
+
+struct PrintPagesData {
+ PrintPagesData(WebPrintOperationGtk* printOperation)
+ : printOperation(printOperation)
+ , totalPrinted(-1)
+ , pageNumber(0)
+ , pagePosition(0)
+ , isDone(false)
+ {
+ if (printOperation->pagesToPrint() == GTK_PRINT_PAGES_RANGES) {
+ Vector<GtkPageRange> pageRanges;
+ GtkPageRange* ranges = printOperation->pageRanges();
+ size_t rangesCount = printOperation->pageRangesCount();
+ int pageCount = printOperation->pageCount();
+
+ pageRanges.reserveCapacity(rangesCount);
+ for (size_t i = 0; i < rangesCount; ++i) {
+ if (ranges[i].start >= 0 && ranges[i].start < pageCount && ranges[i].end >= 0 && ranges[i].end < pageCount)
+ pageRanges.append(ranges[i]);
+ else if (ranges[i].start >= 0 && ranges[i].start < pageCount && ranges[i].end >= pageCount) {
+ pageRanges.append(ranges[i]);
+ pageRanges.last().end = pageCount - 1;
+ } else if (ranges[i].end >= 0 && ranges[i].end < pageCount && ranges[i].start < 0) {
+ pageRanges.append(ranges[i]);
+ pageRanges.last().start = 0;
+ }
+ }
+
+ for (size_t i = 0; i < pageRanges.size(); ++i) {
+ for (int j = pageRanges[i].start; j <= pageRanges[i].end; ++j)
+ pages.append(j);
+ }
+
+ } else {
+ for (int i = 0; i < printOperation->pageCount(); ++i)
+ pages.append(i);
+ }
+
+ pageNumber = pages[pagePosition];
+ }
+
+ void incrementPageSequence()
+ {
+ if (totalPrinted == -1) {
+ totalPrinted = 0;
+ return;
+ }
+
+ pagePosition++;
+ if (pagePosition >= pages.size()) {
+ isDone = true;
+ return;
+ }
+ pageNumber = pages[pagePosition];
+ totalPrinted++;
+ }
+
+ RefPtr<WebPrintOperationGtk> printOperation;
+
+ int totalPrinted;
+ size_t totalToPrint;
+ int pageNumber;
+ size_t pagePosition;
+ Vector<size_t> pages;
+
+ bool isDone : 1;
+};
+
+PassRefPtr<WebPrintOperationGtk> WebPrintOperationGtk::create(WebPage* page, const PrintInfo& printInfo)
+{
+#ifdef HAVE_GTK_UNIX_PRINTING
+ return adoptRef(new WebPrintOperationGtkUnix(page, printInfo));
+#endif
+#ifdef G_OS_WIN32
+ return adoptRef(new WebPrintOperationGtkWin32(page, printInfo));
+#endif
+}
+
+WebPrintOperationGtk::WebPrintOperationGtk(WebPage* page, const PrintInfo& printInfo)
+ : m_webPage(page)
+ , m_printSettings(printInfo.printSettings.get())
+ , m_pageSetup(printInfo.pageSetup.get())
+ , m_printContext(0)
+ , m_callbackID(0)
+ , m_xDPI(1)
+ , m_yDPI(1)
+ , m_printPagesIdleId(0)
+ , m_pagesToPrint(GTK_PRINT_PAGES_ALL)
+ , m_pageRanges(0)
+ , m_pageRangesCount(0)
+ , m_needsRotation(false)
+{
+}
+
+WebPrintOperationGtk::~WebPrintOperationGtk()
+{
+ if (m_printPagesIdleId)
+ g_source_remove(m_printPagesIdleId);
+}
+
+int WebPrintOperationGtk::pageCount() const
+{
+ return m_printContext ? m_printContext->pageCount() : 0;
+}
+
+void WebPrintOperationGtk::rotatePage()
+{
+ GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(m_pageSetup.get());
+ double width = gtk_paper_size_get_width(paperSize, GTK_UNIT_INCH) * m_xDPI;
+ double height = gtk_paper_size_get_height(paperSize, GTK_UNIT_INCH) * m_yDPI;
+
+ cairo_matrix_t matrix;
+ switch (gtk_page_setup_get_orientation(m_pageSetup.get())) {
+ case GTK_PAGE_ORIENTATION_LANDSCAPE:
+ cairo_translate(m_cairoContext.get(), 0, height);
+ cairo_matrix_init(&matrix, 0, -1, 1, 0, 0, 0);
+ cairo_transform(m_cairoContext.get(), &matrix);
+ break;
+ case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+ cairo_translate(m_cairoContext.get(), width, height);
+ cairo_matrix_init(&matrix, -1, 0, 0, -1, 0, 0);
+ cairo_transform(m_cairoContext.get(), &matrix);
+ break;
+ case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+ cairo_translate(m_cairoContext.get(), width, 0);
+ cairo_matrix_init(&matrix, 0, 1, -1, 0, 0, 0);
+ cairo_transform(m_cairoContext.get(), &matrix);
+ break;
+ case GTK_PAGE_ORIENTATION_PORTRAIT:
+ default:
+ break;
+ }
+}
+
+void WebPrintOperationGtk::renderPage(int pageNumber)
+{
+ startPage(m_cairoContext.get());
+
+ if (m_needsRotation)
+ rotatePage();
+
+ double left = gtk_page_setup_get_left_margin(m_pageSetup.get(), GTK_UNIT_INCH);
+ double top = gtk_page_setup_get_top_margin(m_pageSetup.get(), GTK_UNIT_INCH);
+ cairo_translate(m_cairoContext.get(), left * m_xDPI, top * m_yDPI);
+
+ double pageWidth = gtk_page_setup_get_page_width(m_pageSetup.get(), GTK_UNIT_INCH) * m_xDPI;
+ WebCore::PlatformContextCairo platformContext(m_cairoContext.get());
+ WebCore::GraphicsContext graphicsContext(&platformContext);
+ m_printContext->spoolPage(graphicsContext, pageNumber, pageWidth);
+
+ endPage(m_cairoContext.get());
+}
+
+gboolean WebPrintOperationGtk::printPagesIdle(gpointer userData)
+{
+ PrintPagesData* data = static_cast<PrintPagesData*>(userData);
+
+ data->incrementPageSequence();
+ if (data->isDone)
+ return FALSE;
+
+ data->printOperation->renderPage(data->pageNumber);
+ return TRUE;
+}
+
+void WebPrintOperationGtk::printPagesIdleDone(gpointer userData)
+{
+ PrintPagesData* data = static_cast<PrintPagesData*>(userData);
+
+ data->printOperation->printDone();
+ delete data;
+}
+
+void WebPrintOperationGtk::printDone()
+{
+ m_printPagesIdleId = 0;
+
+ endPrint();
+ // Job is now sent to the printer, we can notify the UI process that we are done.
+ m_webPage->send(Messages::WebPageProxy::VoidCallback(m_callbackID));
+ m_cairoContext = 0;
+}
+
+void WebPrintOperationGtk::print(cairo_surface_t* surface, double xDPI, double yDPI)
+{
+ ASSERT(m_printContext);
+
+ m_xDPI = xDPI;
+ m_yDPI = yDPI;
+ m_cairoContext = adoptRef(cairo_create(surface));
+
+ PrintPagesData* data = new PrintPagesData(this);
+ m_printPagesIdleId = gdk_threads_add_idle_full(G_PRIORITY_DEFAULT_IDLE + 10, printPagesIdle,
+ data, printPagesIdleDone);
+}
+
+}