~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit2/WebProcess/WebPage/gtk/WebPrintOperationGtk.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 Igalia S.L.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
23
 * THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
#include "WebPrintOperationGtk.h"
 
28
 
 
29
#include "WebCoreArgumentCoders.h"
 
30
#include "WebPage.h"
 
31
#include "WebPageProxyMessages.h"
 
32
#include <WebCore/ErrorsGtk.h>
 
33
#include <WebCore/IntRect.h>
 
34
#include <WebCore/NotImplemented.h>
 
35
#include <WebCore/PlatformContextCairo.h>
 
36
#include <WebCore/PrintContext.h>
 
37
#include <WebCore/ResourceError.h>
 
38
#include <gtk/gtk.h>
 
39
#include <wtf/Vector.h>
 
40
#include <wtf/gobject/GOwnPtr.h>
 
41
 
 
42
#ifdef HAVE_GTK_UNIX_PRINTING
 
43
#include <cairo-pdf.h>
 
44
#include <cairo-ps.h>
 
45
#include <gtk/gtkunixprint.h>
 
46
#endif
 
47
 
 
48
namespace WebKit {
 
49
 
 
50
#ifdef HAVE_GTK_UNIX_PRINTING
 
51
class WebPrintOperationGtkUnix: public WebPrintOperationGtk {
 
52
public:
 
53
    WebPrintOperationGtkUnix(WebPage* page, const PrintInfo& printInfo)
 
54
        : WebPrintOperationGtk(page, printInfo)
 
55
        , m_printJob(0)
 
56
    {
 
57
    }
 
58
 
 
59
    static gboolean enumeratePrintersFunction(GtkPrinter* printer, WebPrintOperationGtkUnix* printOperation)
 
60
    {
 
61
        const char* printerName = gtk_print_settings_get_printer(printOperation->printSettings());
 
62
        if ((printerName && strcmp(printerName, gtk_printer_get_name(printer)))
 
63
            || (!printerName && !gtk_printer_is_default(printer)))
 
64
            return FALSE;
 
65
 
 
66
        static int jobNumber = 0;
 
67
        const char* applicationName = g_get_application_name();
 
68
        GOwnPtr<char>jobName(g_strdup_printf("%s job #%d", applicationName ? applicationName : "WebKit", ++jobNumber));
 
69
        printOperation->m_printJob = adoptGRef(gtk_print_job_new(jobName.get(), printer,
 
70
                                                                 printOperation->printSettings(),
 
71
                                                                 printOperation->pageSetup()));
 
72
        return TRUE;
 
73
    }
 
74
 
 
75
    static void enumeratePrintersFinished(WebPrintOperationGtkUnix* printOperation)
 
76
    {
 
77
        if (!printOperation->m_printJob) {
 
78
            printOperation->printDone(printerNotFoundError(printOperation->m_printContext));
 
79
            return;
 
80
        }
 
81
 
 
82
        GOwnPtr<GError> error;
 
83
        cairo_surface_t* surface = gtk_print_job_get_surface(printOperation->m_printJob.get(), &error.outPtr());
 
84
        if (!surface) {
 
85
            printOperation->printDone(printError(printOperation->m_printContext, error->message));
 
86
            return;
 
87
        }
 
88
 
 
89
        int rangesCount;
 
90
        printOperation->m_pageRanges = gtk_print_job_get_page_ranges(printOperation->m_printJob.get(), &rangesCount);
 
91
        printOperation->m_pageRangesCount = rangesCount;
 
92
        printOperation->m_pagesToPrint = gtk_print_job_get_pages(printOperation->m_printJob.get());
 
93
        printOperation->m_needsRotation = gtk_print_job_get_rotate(printOperation->m_printJob.get());
 
94
 
 
95
        // Manual capabilities.
 
96
        printOperation->m_numberUp = gtk_print_job_get_n_up(printOperation->m_printJob.get());
 
97
        printOperation->m_numberUpLayout = gtk_print_job_get_n_up_layout(printOperation->m_printJob.get());
 
98
        printOperation->m_pageSet = gtk_print_job_get_page_set(printOperation->m_printJob.get());
 
99
        printOperation->m_reverse = gtk_print_job_get_reverse(printOperation->m_printJob.get());
 
100
        printOperation->m_copies = gtk_print_job_get_num_copies(printOperation->m_printJob.get());
 
101
        printOperation->m_collateCopies = gtk_print_job_get_collate(printOperation->m_printJob.get());
 
102
        printOperation->m_scale = gtk_print_job_get_scale(printOperation->m_printJob.get());
 
103
 
 
104
        printOperation->print(surface, 72, 72);
 
105
    }
 
106
 
 
107
    void startPrint(WebCore::PrintContext* printContext, uint64_t callbackID)
 
108
    {
 
109
        m_printContext = printContext;
 
110
        m_callbackID = callbackID;
 
111
        gtk_enumerate_printers(reinterpret_cast<GtkPrinterFunc>(enumeratePrintersFunction), this,
 
112
                               reinterpret_cast<GDestroyNotify>(enumeratePrintersFinished), FALSE);
 
113
    }
 
114
 
 
115
    void startPage(cairo_t* cr)
 
116
    {
 
117
        if (!currentPageIsFirstPageOfSheet())
 
118
          return;
 
119
 
 
120
        GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(m_pageSetup.get());
 
121
        double width = gtk_paper_size_get_width(paperSize, GTK_UNIT_POINTS);
 
122
        double height = gtk_paper_size_get_height(paperSize, GTK_UNIT_POINTS);
 
123
 
 
124
        cairo_surface_t* surface = gtk_print_job_get_surface(m_printJob.get(), 0);
 
125
        cairo_surface_type_t surfaceType = cairo_surface_get_type(surface);
 
126
        if (surfaceType == CAIRO_SURFACE_TYPE_PS) {
 
127
            cairo_ps_surface_set_size(surface, width, height);
 
128
            cairo_ps_surface_dsc_begin_page_setup(surface);
 
129
 
 
130
            switch (gtk_page_setup_get_orientation(m_pageSetup.get())) {
 
131
            case GTK_PAGE_ORIENTATION_PORTRAIT:
 
132
            case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
 
133
                cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Portrait");
 
134
                break;
 
135
            case GTK_PAGE_ORIENTATION_LANDSCAPE:
 
136
            case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
 
137
                cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Landscape");
 
138
                break;
 
139
            }
 
140
        } else if (surfaceType == CAIRO_SURFACE_TYPE_PDF)
 
141
            cairo_pdf_surface_set_size(surface, width, height);
 
142
    }
 
143
 
 
144
    void endPage(cairo_t* cr)
 
145
    {
 
146
        if (currentPageIsLastPageOfSheet())
 
147
            cairo_show_page(cr);
 
148
    }
 
149
 
 
150
    static void printJobComplete(GtkPrintJob* printJob, WebPrintOperationGtkUnix* printOperation, const GError* error)
 
151
    {
 
152
        printOperation->printDone(error ? printError(printOperation->m_printContext, error->message) : WebCore::ResourceError());
 
153
        printOperation->m_printJob = 0;
 
154
    }
 
155
 
 
156
    static void printJobFinished(WebPrintOperationGtkUnix* printOperation)
 
157
    {
 
158
        printOperation->deref();
 
159
    }
 
160
 
 
161
    void endPrint()
 
162
    {
 
163
        cairo_surface_finish(gtk_print_job_get_surface(m_printJob.get(), 0));
 
164
        // Make sure the operation is alive until the job is sent.
 
165
        ref();
 
166
        gtk_print_job_send(m_printJob.get(), reinterpret_cast<GtkPrintJobCompleteFunc>(printJobComplete), this,
 
167
                           reinterpret_cast<GDestroyNotify>(printJobFinished));
 
168
    }
 
169
 
 
170
    GRefPtr<GtkPrintJob> m_printJob;
 
171
};
 
172
#endif
 
173
 
 
174
#ifdef G_OS_WIN32
 
175
class WebPrintOperationGtkWin32: public WebPrintOperationGtk {
 
176
public:
 
177
    WebPrintOperationGtkWin32(WebPage* page, const PrintInfo& printInfo)
 
178
        : WebPrintOperationGtk(page, printInfo)
 
179
    {
 
180
    }
 
181
 
 
182
    void startPrint(WebCore::PrintContext* printContext, uint64_t callbackID)
 
183
    {
 
184
        m_printContext = printContext;
 
185
        m_callbackID = callbackID;
 
186
        notImplemented();
 
187
    }
 
188
 
 
189
    void startPage(cairo_t* cr)
 
190
    {
 
191
        notImplemented();
 
192
    }
 
193
 
 
194
    void endPage(cairo_t* cr)
 
195
    {
 
196
        notImplemented();
 
197
    }
 
198
 
 
199
    void endPrint()
 
200
    {
 
201
        notImplemented();
 
202
    }
 
203
};
 
204
#endif
 
205
 
 
206
struct PrintPagesData {
 
207
    PrintPagesData(WebPrintOperationGtk* printOperation)
 
208
        : printOperation(printOperation)
 
209
        , totalPrinted(-1)
 
210
        , pageNumber(0)
 
211
        , sheetNumber(0)
 
212
        , firstSheetNumber(0)
 
213
        , numberOfSheets(0)
 
214
        , firstPagePosition(0)
 
215
        , collated(0)
 
216
        , uncollated(0)
 
217
        , isDone(false)
 
218
        , isValid(true)
 
219
    {
 
220
        if (printOperation->collateCopies()) {
 
221
            collatedCopies = printOperation->copies();
 
222
            uncollatedCopies = 1;
 
223
        } else {
 
224
            collatedCopies = 1;
 
225
            uncollatedCopies = printOperation->copies();
 
226
        }
 
227
 
 
228
        if (printOperation->pagesToPrint() == GTK_PRINT_PAGES_RANGES) {
 
229
            Vector<GtkPageRange> pageRanges;
 
230
            GtkPageRange* ranges = printOperation->pageRanges();
 
231
            size_t rangesCount = printOperation->pageRangesCount();
 
232
            int pageCount = printOperation->pageCount();
 
233
 
 
234
            pageRanges.reserveCapacity(rangesCount);
 
235
            for (size_t i = 0; i < rangesCount; ++i) {
 
236
                if (ranges[i].start >= 0 && ranges[i].start < pageCount && ranges[i].end >= 0 && ranges[i].end < pageCount)
 
237
                    pageRanges.append(ranges[i]);
 
238
                else if (ranges[i].start >= 0 && ranges[i].start < pageCount && ranges[i].end >= pageCount) {
 
239
                    pageRanges.append(ranges[i]);
 
240
                    pageRanges.last().end = pageCount - 1;
 
241
                } else if (ranges[i].end >= 0 && ranges[i].end < pageCount && ranges[i].start < 0) {
 
242
                    pageRanges.append(ranges[i]);
 
243
                    pageRanges.last().start = 0;
 
244
                }
 
245
            }
 
246
 
 
247
            for (size_t i = 0; i < pageRanges.size(); ++i) {
 
248
                for (int j = pageRanges[i].start; j <= pageRanges[i].end; ++j)
 
249
                    pages.append(j);
 
250
            }
 
251
 
 
252
        } else {
 
253
            for (int i = 0; i < printOperation->pageCount(); ++i)
 
254
                pages.append(i);
 
255
        }
 
256
 
 
257
        if (!pages.size()) {
 
258
            isValid = false;
 
259
            return;
 
260
        }
 
261
        printOperation->setNumberOfPagesToPrint(pages.size());
 
262
 
 
263
        size_t numberUp = printOperation->numberUp();
 
264
        if (numberUp > 1)
 
265
            numberOfSheets = (pages.size() % numberUp) ? pages.size() / numberUp + 1 : pages.size() / numberUp;
 
266
        else
 
267
            numberOfSheets = pages.size();
 
268
 
 
269
        bool reverse = printOperation->reverse();
 
270
        switch (printOperation->pageSet()) {
 
271
        case GTK_PAGE_SET_ODD:
 
272
            if (reverse) {
 
273
                lastPagePosition = std::min(numberUp - 1, pages.size() - 1);
 
274
                sheetNumber = (numberOfSheets - 1) - (numberOfSheets - 1) % 2;
 
275
            } else
 
276
                lastPagePosition = std::min(((numberOfSheets - 1) - ((numberOfSheets - 1) % 2)) * numberUp - 1, pages.size() - 1);
 
277
            break;
 
278
        case GTK_PAGE_SET_EVEN:
 
279
            if (reverse) {
 
280
                lastPagePosition = std::min(2 * numberUp - 1, pages.size() - 1);
 
281
                sheetNumber = (numberOfSheets - 1) - (1 - (numberOfSheets - 1) % 2);
 
282
            } else {
 
283
                lastPagePosition = std::min(((numberOfSheets - 1) - (1 - (numberOfSheets - 1) % 2)) * numberUp - 1, pages.size() - 1);
 
284
                sheetNumber = numberOfSheets > 1 ? 1 : -1;
 
285
            }
 
286
            break;
 
287
        case GTK_PAGE_SET_ALL:
 
288
            if (reverse) {
 
289
                lastPagePosition = std::min(numberUp - 1, pages.size() - 1);
 
290
                sheetNumber = pages.size() - 1;
 
291
            } else
 
292
                lastPagePosition = pages.size() - 1;
 
293
            break;
 
294
        }
 
295
 
 
296
        if (sheetNumber * numberUp >= pages.size()) {
 
297
            isValid = false;
 
298
            return;
 
299
        }
 
300
 
 
301
        printOperation->setPagePosition(sheetNumber * numberUp);
 
302
        pageNumber = pages[printOperation->pagePosition()];
 
303
        firstPagePosition = printOperation->pagePosition();
 
304
        firstSheetNumber = sheetNumber;
 
305
    }
 
306
 
 
307
    size_t collatedCopiesLeft()
 
308
    {
 
309
        return collatedCopies > 1 ? collatedCopies - collated - 1 : 0;
 
310
    }
 
311
 
 
312
    size_t uncollatedCopiesLeft()
 
313
    {
 
314
        return uncollatedCopies > 1 ? uncollatedCopies - uncollated - 1 : 0;
 
315
    }
 
316
 
 
317
    size_t copiesLeft()
 
318
    {
 
319
        return collatedCopiesLeft() + uncollatedCopiesLeft();
 
320
    }
 
321
 
 
322
    void incrementPageSequence()
 
323
    {
 
324
        if (totalPrinted == -1) {
 
325
            totalPrinted = 0;
 
326
            return;
 
327
        }
 
328
 
 
329
        size_t pagePosition = printOperation->pagePosition();
 
330
        if (pagePosition == lastPagePosition && !copiesLeft()) {
 
331
            isDone = true;
 
332
            return;
 
333
        }
 
334
 
 
335
        if (pagePosition == lastPagePosition && uncollatedCopiesLeft()) {
 
336
            pagePosition = firstPagePosition;
 
337
            sheetNumber = firstSheetNumber;
 
338
            uncollated++;
 
339
        } else if (printOperation->currentPageIsLastPageOfSheet()) {
 
340
            if (!collatedCopiesLeft()) {
 
341
                int step = printOperation->pageSet() == GTK_PAGE_SET_ALL ? 1 : 2;
 
342
                step *= printOperation->reverse() ? -1 : 1;
 
343
                sheetNumber += step;
 
344
                collated = 0;
 
345
            } else
 
346
                collated++;
 
347
            pagePosition = sheetNumber * printOperation->numberUp();
 
348
        } else
 
349
            pagePosition++;
 
350
        printOperation->setPagePosition(pagePosition);
 
351
 
 
352
        if (pagePosition >= pages.size() || sheetNumber >= numberOfSheets) {
 
353
            isDone = true;
 
354
            return;
 
355
        }
 
356
        pageNumber = pages[pagePosition];
 
357
        totalPrinted++;
 
358
    }
 
359
 
 
360
    RefPtr<WebPrintOperationGtk> printOperation;
 
361
 
 
362
    int totalPrinted;
 
363
    size_t totalToPrint;
 
364
    int pageNumber;
 
365
    Vector<size_t> pages;
 
366
    size_t sheetNumber;
 
367
    size_t firstSheetNumber;
 
368
    size_t numberOfSheets;
 
369
    size_t firstPagePosition;
 
370
    size_t lastPagePosition;
 
371
    size_t collated;
 
372
    size_t uncollated;
 
373
    size_t collatedCopies;
 
374
    size_t uncollatedCopies;
 
375
 
 
376
    bool isDone : 1;
 
377
    bool isValid : 1;
 
378
};
 
379
 
 
380
PassRefPtr<WebPrintOperationGtk> WebPrintOperationGtk::create(WebPage* page, const PrintInfo& printInfo)
 
381
{
 
382
#ifdef HAVE_GTK_UNIX_PRINTING
 
383
    return adoptRef(new WebPrintOperationGtkUnix(page, printInfo));
 
384
#elif defined(G_OS_WIN32)
 
385
    return adoptRef(new WebPrintOperationGtkWin32(page, printInfo));
 
386
#else
 
387
    return 0;
 
388
#endif
 
389
}
 
390
 
 
391
WebPrintOperationGtk::WebPrintOperationGtk(WebPage* page, const PrintInfo& printInfo)
 
392
    : m_webPage(page)
 
393
    , m_printSettings(printInfo.printSettings.get())
 
394
    , m_pageSetup(printInfo.pageSetup.get())
 
395
    , m_printContext(0)
 
396
    , m_callbackID(0)
 
397
    , m_xDPI(1)
 
398
    , m_yDPI(1)
 
399
    , m_printPagesIdleId(0)
 
400
    , m_numberOfPagesToPrint(0)
 
401
    , m_pagesToPrint(GTK_PRINT_PAGES_ALL)
 
402
    , m_pagePosition(0)
 
403
    , m_pageRanges(0)
 
404
    , m_pageRangesCount(0)
 
405
    , m_needsRotation(false)
 
406
    , m_numberUp(1)
 
407
    , m_numberUpLayout(0)
 
408
    , m_pageSet(GTK_PAGE_SET_ALL)
 
409
    , m_reverse(false)
 
410
    , m_copies(1)
 
411
    , m_collateCopies(false)
 
412
    , m_scale(1)
 
413
{
 
414
}
 
415
 
 
416
WebPrintOperationGtk::~WebPrintOperationGtk()
 
417
{
 
418
    if (m_printPagesIdleId)
 
419
        g_source_remove(m_printPagesIdleId);
 
420
}
 
421
 
 
422
int WebPrintOperationGtk::pageCount() const
 
423
{
 
424
    return m_printContext ? m_printContext->pageCount() : 0;
 
425
}
 
426
 
 
427
bool WebPrintOperationGtk::currentPageIsFirstPageOfSheet() const
 
428
{
 
429
    return (m_numberUp < 2 || !((m_pagePosition) % m_numberUp));
 
430
}
 
431
 
 
432
bool WebPrintOperationGtk::currentPageIsLastPageOfSheet() const
 
433
{
 
434
    return (m_numberUp < 2 || !((m_pagePosition + 1) % m_numberUp) || m_pagePosition == m_numberOfPagesToPrint - 1);
 
435
}
 
436
 
 
437
void WebPrintOperationGtk::rotatePageIfNeeded()
 
438
{
 
439
    if (!m_needsRotation)
 
440
        return;
 
441
 
 
442
    GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(m_pageSetup.get());
 
443
    double width = gtk_paper_size_get_width(paperSize, GTK_UNIT_INCH) * m_xDPI;
 
444
    double height = gtk_paper_size_get_height(paperSize, GTK_UNIT_INCH) * m_yDPI;
 
445
 
 
446
    cairo_matrix_t matrix;
 
447
    switch (gtk_page_setup_get_orientation(m_pageSetup.get())) {
 
448
    case GTK_PAGE_ORIENTATION_LANDSCAPE:
 
449
        cairo_translate(m_cairoContext.get(), 0, height);
 
450
        cairo_matrix_init(&matrix, 0, -1, 1, 0, 0, 0);
 
451
        cairo_transform(m_cairoContext.get(), &matrix);
 
452
        break;
 
453
    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
 
454
        cairo_translate(m_cairoContext.get(), width, height);
 
455
        cairo_matrix_init(&matrix, -1, 0, 0, -1, 0, 0);
 
456
        cairo_transform(m_cairoContext.get(), &matrix);
 
457
        break;
 
458
    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
 
459
        cairo_translate(m_cairoContext.get(), width, 0);
 
460
        cairo_matrix_init(&matrix, 0, 1, -1, 0, 0, 0);
 
461
        cairo_transform(m_cairoContext.get(), &matrix);
 
462
        break;
 
463
    case GTK_PAGE_ORIENTATION_PORTRAIT:
 
464
    default:
 
465
        break;
 
466
    }
 
467
}
 
468
 
 
469
void WebPrintOperationGtk::getRowsAndColumnsOfPagesPerSheet(size_t& rows, size_t& columns)
 
470
{
 
471
    switch (m_numberUp) {
 
472
    default:
 
473
        columns = 1;
 
474
        rows = 1;
 
475
        break;
 
476
    case 2:
 
477
        columns = 2;
 
478
        rows = 1;
 
479
        break;
 
480
    case 4:
 
481
        columns = 2;
 
482
        rows = 2;
 
483
        break;
 
484
    case 6:
 
485
        columns = 3;
 
486
        rows = 2;
 
487
        break;
 
488
    case 9:
 
489
        columns = 3;
 
490
        rows = 3;
 
491
        break;
 
492
    case 16:
 
493
        columns = 4;
 
494
        rows = 4;
 
495
        break;
 
496
    }
 
497
}
 
498
 
 
499
void WebPrintOperationGtk::getPositionOfPageInSheet(size_t rows, size_t columns, int& x, int&y)
 
500
{
 
501
    switch (m_numberUpLayout) {
 
502
    case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
 
503
        x = m_pagePosition % columns;
 
504
        y = (m_pagePosition / columns) % rows;
 
505
        break;
 
506
    case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
 
507
        x = m_pagePosition % columns;
 
508
        y = rows - 1 - (m_pagePosition / columns) % rows;
 
509
        break;
 
510
    case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
 
511
        x = columns - 1 - m_pagePosition % columns;
 
512
        y = (m_pagePosition / columns) % rows;
 
513
        break;
 
514
    case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
 
515
        x = columns - 1 - m_pagePosition % columns;
 
516
        y = rows - 1 - (m_pagePosition / columns) % rows;
 
517
        break;
 
518
    case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
 
519
        x = (m_pagePosition / rows) % columns;
 
520
        y = m_pagePosition % rows;
 
521
        break;
 
522
    case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
 
523
        x = columns - 1 - (m_pagePosition / rows) % columns;
 
524
        y = m_pagePosition % rows;
 
525
        break;
 
526
    case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
 
527
        x = (m_pagePosition / rows) % columns;
 
528
        y = rows - 1 - m_pagePosition % rows;
 
529
        break;
 
530
    case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
 
531
        x = columns - 1 - (m_pagePosition / rows) % columns;
 
532
        y = rows - 1 - m_pagePosition % rows;
 
533
        break;
 
534
    }
 
535
}
 
536
 
 
537
void WebPrintOperationGtk::prepareContextToDraw()
 
538
{
 
539
    if (m_numberUp < 2) {
 
540
        double left = gtk_page_setup_get_left_margin(m_pageSetup.get(), GTK_UNIT_INCH);
 
541
        double top = gtk_page_setup_get_top_margin(m_pageSetup.get(), GTK_UNIT_INCH);
 
542
        if (m_scale != 1.0)
 
543
            cairo_scale(m_cairoContext.get(), m_scale, m_scale);
 
544
        rotatePageIfNeeded();
 
545
        cairo_translate(m_cairoContext.get(), left * m_xDPI, top * m_yDPI);
 
546
 
 
547
        return;
 
548
    }
 
549
 
 
550
    rotatePageIfNeeded();
 
551
 
 
552
    // Multiple pages per sheet.
 
553
    double marginLeft = gtk_page_setup_get_left_margin(m_pageSetup.get(), GTK_UNIT_POINTS);
 
554
    double marginRight = gtk_page_setup_get_right_margin(m_pageSetup.get(), GTK_UNIT_POINTS);
 
555
    double marginTop = gtk_page_setup_get_top_margin(m_pageSetup.get(), GTK_UNIT_POINTS);
 
556
    double marginBottom = gtk_page_setup_get_bottom_margin(m_pageSetup.get(), GTK_UNIT_POINTS);
 
557
 
 
558
    double paperWidth = gtk_page_setup_get_paper_width(m_pageSetup.get(), GTK_UNIT_POINTS);
 
559
    double paperHeight = gtk_page_setup_get_paper_height(m_pageSetup.get(), GTK_UNIT_POINTS);
 
560
 
 
561
    size_t rows, columns;
 
562
    getRowsAndColumnsOfPagesPerSheet(rows, columns);
 
563
 
 
564
    GtkPageOrientation orientation = gtk_page_setup_get_orientation(m_pageSetup.get());
 
565
    double pageWidth = 0, pageHeight = 0;
 
566
    switch (orientation) {
 
567
    case GTK_PAGE_ORIENTATION_PORTRAIT:
 
568
    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
 
569
        pageWidth = paperWidth - (marginLeft + marginRight);
 
570
        pageHeight = paperHeight - (marginTop + marginBottom);
 
571
        cairo_translate(m_cairoContext.get(), marginLeft, marginTop);
 
572
        break;
 
573
    case GTK_PAGE_ORIENTATION_LANDSCAPE:
 
574
    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
 
575
        pageWidth = paperWidth - (marginTop + marginBottom);
 
576
        pageHeight = paperHeight - (marginLeft + marginRight);
 
577
        cairo_translate(m_cairoContext.get(), marginTop, marginLeft);
 
578
 
 
579
        size_t tmp = columns;
 
580
        columns = rows;
 
581
        rows = tmp;
 
582
        break;
 
583
    }
 
584
 
 
585
    int x, y;
 
586
    getPositionOfPageInSheet(rows, columns, x, y);
 
587
 
 
588
    switch (m_numberUp) {
 
589
    case 4:
 
590
    case 9:
 
591
    case 16: {
 
592
        double scaleX = pageWidth / (columns * paperWidth);
 
593
        double scaleY = pageHeight / (rows * paperHeight);
 
594
        double scale = std::min(scaleX, scaleY);
 
595
 
 
596
        double stepX = paperWidth * (scaleX / scale);
 
597
        double stepY = paperHeight * (scaleY / scale);
 
598
 
 
599
        double width = gtk_page_setup_get_page_width(m_pageSetup.get(), GTK_UNIT_INCH) * m_xDPI;
 
600
        double height = gtk_page_setup_get_page_height(m_pageSetup.get(), GTK_UNIT_INCH) * m_yDPI;
 
601
 
 
602
        double offsetX, offsetY;
 
603
        if (marginLeft + marginRight > 0) {
 
604
            offsetX = marginLeft * (stepX - width) / (marginLeft + marginRight);
 
605
            offsetY = marginTop * (stepY - height) / (marginTop + marginBottom);
 
606
        } else {
 
607
            offsetX = (stepX - width) / 2.0;
 
608
            offsetY = (stepY - height) / 2.0;
 
609
        }
 
610
 
 
611
        cairo_scale(m_cairoContext.get(), scale, scale);
 
612
        cairo_translate(m_cairoContext.get(), x * stepX + offsetX, y * stepY + offsetY);
 
613
        if (m_scale != 1.0)
 
614
            cairo_scale(m_cairoContext.get(), m_scale, m_scale);
 
615
        break;
 
616
    }
 
617
    case 2:
 
618
    case 6: {
 
619
        double scaleX = pageHeight / (columns * paperWidth);
 
620
        double scaleY = pageWidth / (rows * paperHeight);
 
621
        double scale = std::min(scaleX, scaleY);
 
622
 
 
623
        double stepX = paperWidth * (scaleX / scale);
 
624
        double stepY = paperHeight * (scaleY / scale);
 
625
 
 
626
        double offsetX = ((stepX - paperWidth) / 2.0 * columns) - marginRight;
 
627
        double offsetY = ((stepY - paperHeight) / 2.0 * rows) + marginTop;
 
628
 
 
629
        cairo_scale(m_cairoContext.get(), scale, scale);
 
630
        cairo_translate(m_cairoContext.get(), y * paperHeight + offsetY, (columns - x) * paperWidth + offsetX);
 
631
        if (m_scale != 1.0)
 
632
            cairo_scale(m_cairoContext.get(), m_scale, m_scale);
 
633
        cairo_rotate(m_cairoContext.get(), -G_PI / 2);
 
634
        break;
 
635
    }
 
636
    default:
 
637
        break;
 
638
    }
 
639
}
 
640
 
 
641
void WebPrintOperationGtk::renderPage(int pageNumber)
 
642
{
 
643
    startPage(m_cairoContext.get());
 
644
    cairo_save(m_cairoContext.get());
 
645
 
 
646
    prepareContextToDraw();
 
647
 
 
648
    double pageWidth = gtk_page_setup_get_page_width(m_pageSetup.get(), GTK_UNIT_INCH) * m_xDPI;
 
649
    WebCore::PlatformContextCairo platformContext(m_cairoContext.get());
 
650
    WebCore::GraphicsContext graphicsContext(&platformContext);
 
651
    m_printContext->spoolPage(graphicsContext, pageNumber, pageWidth / m_scale);
 
652
 
 
653
    cairo_restore(m_cairoContext.get());
 
654
    endPage(m_cairoContext.get());
 
655
}
 
656
 
 
657
gboolean WebPrintOperationGtk::printPagesIdle(gpointer userData)
 
658
{
 
659
    PrintPagesData* data = static_cast<PrintPagesData*>(userData);
 
660
 
 
661
    data->incrementPageSequence();
 
662
    if (data->isDone)
 
663
        return FALSE;
 
664
 
 
665
    data->printOperation->renderPage(data->pageNumber);
 
666
    return TRUE;
 
667
}
 
668
 
 
669
void WebPrintOperationGtk::printPagesIdleDone(gpointer userData)
 
670
{
 
671
    PrintPagesData* data = static_cast<PrintPagesData*>(userData);
 
672
 
 
673
    data->printOperation->printPagesDone();
 
674
    delete data;
 
675
}
 
676
 
 
677
void WebPrintOperationGtk::printPagesDone()
 
678
{
 
679
    m_printPagesIdleId = 0;
 
680
    endPrint();
 
681
    m_cairoContext = 0;
 
682
}
 
683
 
 
684
void WebPrintOperationGtk::printDone(const WebCore::ResourceError& error)
 
685
{
 
686
    if (m_printPagesIdleId)
 
687
        g_source_remove(m_printPagesIdleId);
 
688
    m_printPagesIdleId = 0;
 
689
 
 
690
    // Print finished or failed, notify the UI process that we are done.
 
691
    m_webPage->send(Messages::WebPageProxy::PrintFinishedCallback(error, m_callbackID));
 
692
}
 
693
 
 
694
void WebPrintOperationGtk::print(cairo_surface_t* surface, double xDPI, double yDPI)
 
695
{
 
696
    ASSERT(m_printContext);
 
697
 
 
698
    OwnPtr<PrintPagesData> data = adoptPtr(new PrintPagesData(this));
 
699
    if (!data->isValid) {
 
700
        cairo_surface_finish(surface);
 
701
        printDone(invalidPageRangeToPrint(m_printContext));
 
702
        return;
 
703
    }
 
704
 
 
705
    m_xDPI = xDPI;
 
706
    m_yDPI = yDPI;
 
707
    m_cairoContext = adoptRef(cairo_create(surface));
 
708
    m_printPagesIdleId = gdk_threads_add_idle_full(G_PRIORITY_DEFAULT_IDLE + 10, printPagesIdle,
 
709
                                                   data.leakPtr(), printPagesIdleDone);
 
710
}
 
711
 
 
712
}