Changeset 28648 in webkit


Ignore:
Timestamp:
Dec 12, 2007 8:14:48 AM (16 years ago)
Author:
alp@webkit.org
Message:

2007-12-12 Alp Toker <alp@atoker.com>

Reviewed by Holger Freyther.

http://bugs.webkit.org/show_bug.cgi?id=15576
[GTK] Printing support

Add printing support.

The API will be kept internal for the time being, but printing can now
be triggered by Web pages or the JSC API using JavaScript.

The print spooler and pagination code is fairly abstract and could be
shared by other ports including Win and Qt once complete. It doesn't
have header/footer support yet.

  • WebCoreSupport/ChromeClientGtk.cpp: (WebKit::ChromeClient::print):
  • WebView/webkitprivate.h:
  • WebView/webkitwebframe.cpp: (PrintContext::begin_print): (PrintContext::draw_page): (PrintContext::end_print): (PrintContext::webkit_web_frame_print):
Location:
trunk/WebKit/gtk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKit/gtk/ChangeLog

    r28645 r28648  
     12007-12-12  Alp Toker  <alp@atoker.com>
     2
     3        Reviewed by Holger Freyther.
     4
     5        http://bugs.webkit.org/show_bug.cgi?id=15576
     6        [GTK] Printing support
     7
     8        Add printing support.
     9
     10        The API will be kept internal for the time being, but printing can now
     11        be triggered by Web pages or the JSC API using JavaScript.
     12
     13        The print spooler and pagination code is fairly abstract and could be
     14        shared by other ports including Win and Qt once complete. It doesn't
     15        have header/footer support yet.
     16
     17        * WebCoreSupport/ChromeClientGtk.cpp:
     18        (WebKit::ChromeClient::print):
     19        * WebView/webkitprivate.h:
     20        * WebView/webkitwebframe.cpp:
     21        (PrintContext::begin_print):
     22        (PrintContext::draw_page):
     23        (PrintContext::end_print):
     24        (PrintContext::webkit_web_frame_print):
     25
    1262007-12-12  Sam Weinig  <sam@webkit.org>
    227
  • trunk/WebKit/gtk/WebCoreSupport/ChromeClientGtk.cpp

    r28490 r28648  
    298298}
    299299
    300 void ChromeClient::print(Frame*)
    301 {
    302     notImplemented();
     300void ChromeClient::print(Frame* frame)
     301{
     302    webkit_web_frame_print(kit(frame));
    303303}
    304304
  • trunk/WebKit/gtk/WebView/webkitprivate.h

    r28634 r28648  
    9494    WEBKIT_API gchar*
    9595    webkit_web_frame_get_inner_text (WebKitWebFrame* frame);
     96
     97    WEBKIT_API void
     98    webkit_web_frame_print (WebKitWebFrame* frame);
    9699}
    97100
  • trunk/WebKit/gtk/WebView/webkitwebframe.cpp

    r28484 r28648  
    22 * Copyright (C) 2007 Holger Hans Peter Freyther
    33 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
     4 * Copyright (C) 2007 Apple Inc.
    45 *
    56 * This library is free software; you can redistribute it and/or
     
    3132#include "FrameTree.h"
    3233#include "FrameView.h"
     34#include "GraphicsContext.h"
    3335#include "HTMLFrameOwnerElement.h"
     36#include "RenderView.h"
    3437#include "kjs_binding.h"
    3538#include "kjs_proxy.h"
     
    416419}
    417420
    418 }
     421
     422#if GTK_CHECK_VERSION(2,10,0)
     423
     424// This could be shared between ports once it's complete
     425class PrintContext
     426{
     427public:
     428    PrintContext(Frame* frame)
     429        : m_frame(frame)
     430    {
     431    }
     432
     433    ~PrintContext()
     434    {
     435        m_pageRects.clear();
     436    }
     437
     438    int pageCount()
     439    {
     440        return m_pageRects.size();
     441    }
     442
     443    void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight)
     444    {
     445        m_pageRects.clear();
     446        outPageHeight = 0;
     447
     448        if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer())
     449            return;
     450
     451        RenderView* root = static_cast<RenderView*>(m_frame->document()->renderer());
     452
     453        if (!root) {
     454            LOG_ERROR("document to be printed has no renderer");
     455            return;
     456        }
     457
     458        if (userScaleFactor <= 0) {
     459            LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor);
     460            return;
     461        }
     462
     463        float ratio = printRect.height() / printRect.width();
     464
     465        float pageWidth  = (float)root->docWidth();
     466        float pageHeight = pageWidth * ratio;
     467        outPageHeight = pageHeight;   // this is the height of the page adjusted by margins
     468        pageHeight -= headerHeight + footerHeight;
     469
     470        if (pageHeight <= 0) {
     471            LOG_ERROR("pageHeight has bad value %.2f", pageHeight);
     472            return;
     473        }
     474
     475        float currPageHeight = pageHeight / userScaleFactor;
     476        float docHeight = root->layer()->height();
     477        float currPageWidth = pageWidth / userScaleFactor;
     478
     479        // always return at least one page, since empty files should print a blank page
     480        float printedPagesHeight = 0.0;
     481        do {
     482            float proposedBottom = min(docHeight, printedPagesHeight + pageHeight);
     483            m_frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight);
     484            currPageHeight = max(1.0f, proposedBottom - printedPagesHeight);
     485
     486            m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight));
     487            printedPagesHeight += currPageHeight;
     488        } while (printedPagesHeight < docHeight);
     489    }
     490
     491    // TODO: eliminate width param
     492    void begin(float width)
     493    {
     494        // By imaging to a width a little wider than the available pixels,
     495        // thin pages will be scaled down a little, matching the way they
     496        // print in IE and Camino. This lets them use fewer sheets than they
     497        // would otherwise, which is presumably why other browsers do this.
     498        // Wide pages will be scaled down more than this.
     499        const float PrintingMinimumShrinkFactor = 1.25f;
     500
     501        // This number determines how small we are willing to reduce the page content
     502        // in order to accommodate the widest line. If the page would have to be
     503        // reduced smaller to make the widest line fit, we just clip instead (this
     504        // behavior matches MacIE and Mozilla, at least)
     505        const float PrintingMaximumShrinkFactor = 2.0f;
     506
     507        float minLayoutWidth = width * PrintingMinimumShrinkFactor;
     508        float maxLayoutWidth = width * PrintingMaximumShrinkFactor;
     509
     510        // FIXME: This will modify the rendering of the on-screen frame.
     511        // Could lead to flicker during printing.
     512        m_frame->setPrinting(true, minLayoutWidth, maxLayoutWidth, true);
     513    }
     514
     515    // TODO: eliminate width param
     516    void spoolPage(GraphicsContext& ctx, int pageNumber, float width)
     517    {
     518        IntRect pageRect = m_pageRects[pageNumber];
     519        float scale = width / pageRect.width();
     520
     521        ctx.save();
     522        ctx.scale(FloatSize(scale, scale));
     523        ctx.translate(-pageRect.x(), -pageRect.y());
     524        ctx.clip(pageRect);
     525        m_frame->paint(&ctx, pageRect);
     526        ctx.restore();
     527    }
     528
     529    void end()
     530    {
     531        m_frame->setPrinting(false, 0, 0, true);
     532    }
     533
     534protected:
     535    Frame* m_frame;
     536    Vector<IntRect> m_pageRects;
     537};
     538
     539static void begin_print(GtkPrintOperation* op, GtkPrintContext* context, gpointer user_data)
     540{
     541    PrintContext* printContext = reinterpret_cast<PrintContext*>(user_data);
     542
     543    float width = gtk_print_context_get_width(context);
     544    float height = gtk_print_context_get_height(context);
     545    FloatRect printRect = FloatRect(0, 0, width, height);
     546
     547    printContext->begin(width);
     548
     549    // TODO: Margin adjustments and header/footer support
     550    float headerHeight = 0;
     551    float footerHeight = 0;
     552    float pageHeight; // height of the page adjusted by margins
     553    printContext->computePageRects(printRect, headerHeight, footerHeight, 1.0, pageHeight);
     554    gtk_print_operation_set_n_pages(op, printContext->pageCount());
     555}
     556
     557static void draw_page(GtkPrintOperation* op, GtkPrintContext* context, gint page_nr, gpointer user_data)
     558{
     559    PrintContext* printContext = reinterpret_cast<PrintContext*>(user_data);
     560
     561    cairo_t* cr = gtk_print_context_get_cairo_context(context);
     562    GraphicsContext ctx(cr);
     563    float width = gtk_print_context_get_width(context);
     564    printContext->spoolPage(ctx, page_nr, width);
     565}
     566
     567static void end_print(GtkPrintOperation* op, GtkPrintContext* context, gpointer user_data)
     568{
     569    PrintContext* printContext = reinterpret_cast<PrintContext*>(user_data);
     570    printContext->end();
     571}
     572
     573void webkit_web_frame_print(WebKitWebFrame* frame)
     574{
     575    GtkWidget* topLevel = gtk_widget_get_toplevel(GTK_WIDGET(webkit_web_frame_get_web_view(frame)));
     576    if (!GTK_WIDGET_TOPLEVEL(topLevel))
     577        topLevel = NULL;
     578
     579    Frame* coreFrame = core(frame);
     580    PrintContext printContext(coreFrame);
     581
     582    GtkPrintOperation* op = gtk_print_operation_new();
     583    g_signal_connect(G_OBJECT(op), "begin-print", G_CALLBACK(begin_print), &printContext);
     584    g_signal_connect(G_OBJECT(op), "draw-page", G_CALLBACK(draw_page), &printContext);
     585    g_signal_connect(G_OBJECT(op), "end-print", G_CALLBACK(end_print), &printContext);
     586    GError *error = NULL;
     587    gtk_print_operation_run(op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW(topLevel), &error);
     588    g_object_unref(op);
     589
     590    if (error) {
     591        GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(topLevel),
     592                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
     593                                                   GTK_MESSAGE_ERROR,
     594                                                   GTK_BUTTONS_CLOSE,
     595                                                   "%s", error->message);
     596        g_error_free(error);
     597
     598        g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
     599        gtk_widget_show(dialog);
     600    }
     601}
     602
     603#else
     604
     605void webkit_web_frame_print(WebKitWebFrame*)
     606{
     607    g_warning("Printing support is not available in older versions of GTK+");
     608}
     609
     610#endif
     611
     612}
Note: See TracChangeset for help on using the changeset viewer.