Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1132)

Side by Side Diff: chrome/renderer/print_web_view_helper.cc

Issue 11359020: Print headers and footers with WebKit. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: linux Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/print_web_view_helper.h" 5 #include "chrome/renderer/print_web_view_helper.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/json/json_writer.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/process_util.h"
15 #include "base/stringprintf.h"
13 #include "base/string_number_conversions.h" 16 #include "base/string_number_conversions.h"
14 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
15 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/print_messages.h" 19 #include "chrome/common/print_messages.h"
17 #include "chrome/common/render_messages.h" 20 #include "chrome/common/render_messages.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/renderer/prerender/prerender_helper.h" 21 #include "chrome/renderer/prerender/prerender_helper.h"
20 #include "content/public/renderer/render_thread.h" 22 #include "content/public/renderer/render_thread.h"
21 #include "content/public/renderer/render_view.h" 23 #include "content/public/renderer/render_view.h"
24 #include "grit/browser_resources.h"
22 #include "grit/generated_resources.h" 25 #include "grit/generated_resources.h"
26 #include "printing/metafile.h"
23 #include "printing/metafile_impl.h" 27 #include "printing/metafile_impl.h"
24 #include "printing/page_size_margins.h"
25 #include "printing/print_job_constants.h"
26 #include "printing/units.h" 28 #include "printing/units.h"
27 #include "skia/ext/vector_canvas.h"
28 #include "skia/ext/vector_platform_device_skia.h" 29 #include "skia/ext/vector_platform_device_skia.h"
29 #include "third_party/skia/include/core/SkRect.h"
30 #include "third_party/skia/include/core/SkTypeface.h"
31 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCanvas.h"
32 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" 30 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLReques t.h" 31 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLReques t.h"
34 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRespon se.h"
35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" 32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h"
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" 33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" 34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" 35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h" 36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h"
41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginDocument.h" 37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginDocument.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPrintParams.h"
42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPrintScalingOption .h" 39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPrintScalingOption .h"
40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSettings.h"
43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" 42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
44 #include "ui/base/l10n/l10n_util.h" 43 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/layout.h" 44 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/gfx/rect.h"
47 #include "ui/gfx/skia_util.h"
48 #include "webkit/glue/webpreferences.h" 45 #include "webkit/glue/webpreferences.h"
49 46
50 #if defined(OS_POSIX)
51 #include "base/process_util.h"
52 #endif
53
54 #if defined(OS_WIN) || defined(OS_MACOSX)
55 #define USE_RENDER_TEXT
56 #endif
57
58 #if defined(USE_RENDER_TEXT)
59 #include "ui/gfx/canvas.h"
60 #include "ui/gfx/render_text.h"
61 #endif
62
63 namespace { 47 namespace {
64 48
65 #if defined(USE_RENDER_TEXT) 49 const double kMinDpi = 1.0;
66 typedef gfx::RenderText* HeaderFooterPaint;
67 #else
68 typedef SkPaint HeaderFooterPaint;
69 #endif
70 50
71 const double kMinDpi = 1.0; 51 const char kPageLoadScriptFormat[] =
52 "document.open(); document.write(%s); document.close();";
53
54 const char kPageSetupScriptFormat[] = "setup(%s);";
55
56 void ExecuteScript(WebKit::WebFrame* frame,
57 const char* script_format,
58 const base::Value& parameters) {
59 std::string json;
60 base::JSONWriter::Write(&parameters, &json);
61 std::string script = StringPrintf(script_format, json.c_str());
62 frame->executeScript(WebKit::WebString(UTF8ToUTF16(script)));
63 }
72 64
73 int GetDPI(const PrintMsg_Print_Params* print_params) { 65 int GetDPI(const PrintMsg_Print_Params* print_params) {
74 #if defined(OS_MACOSX) 66 #if defined(OS_MACOSX)
75 // On the Mac, the printable area is in points, don't do any scaling based 67 // On the Mac, the printable area is in points, don't do any scaling based
76 // on dpi. 68 // on dpi.
77 return printing::kPointsPerInch; 69 return printing::kPointsPerInch;
78 #else 70 #else
79 return static_cast<int>(print_params->dpi); 71 return static_cast<int>(print_params->dpi);
80 #endif // defined(OS_MACOSX) 72 #endif // defined(OS_MACOSX)
81 } 73 }
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 336
345 bool FitToPageEnabled(const DictionaryValue& job_settings) { 337 bool FitToPageEnabled(const DictionaryValue& job_settings) {
346 bool fit_to_paper_size = false; 338 bool fit_to_paper_size = false;
347 if (!job_settings.GetBoolean(printing::kSettingFitToPageEnabled, 339 if (!job_settings.GetBoolean(printing::kSettingFitToPageEnabled,
348 &fit_to_paper_size)) { 340 &fit_to_paper_size)) {
349 NOTREACHED(); 341 NOTREACHED();
350 } 342 }
351 return fit_to_paper_size; 343 return fit_to_paper_size;
352 } 344 }
353 345
354 // Get the (x, y) coordinate from where printing of the current text should
355 // start depending on the horizontal alignment (LEFT, RIGHT, CENTER) and
356 // vertical alignment (TOP, BOTTOM).
357 SkPoint GetHeaderFooterPosition(
358 float webkit_scale_factor,
359 const printing::PageSizeMargins& page_layout,
360 printing::HorizontalHeaderFooterPosition horizontal_position,
361 printing::VerticalHeaderFooterPosition vertical_position,
362 double offset_to_baseline,
363 double text_width_in_points) {
364 SkScalar x = 0;
365 switch (horizontal_position) {
366 case printing::LEFT: {
367 x = printing::kSettingHeaderFooterInterstice - page_layout.margin_left;
368 break;
369 }
370 case printing::RIGHT: {
371 x = page_layout.content_width + page_layout.margin_right -
372 printing::kSettingHeaderFooterInterstice - text_width_in_points;
373 break;
374 }
375 case printing::CENTER: {
376 SkScalar available_width = printing::GetHeaderFooterSegmentWidth(
377 page_layout.margin_left + page_layout.margin_right +
378 page_layout.content_width);
379 x = available_width - page_layout.margin_left +
380 (available_width - text_width_in_points) / 2;
381 break;
382 }
383 default: {
384 NOTREACHED();
385 }
386 }
387
388 SkScalar y = 0;
389 switch (vertical_position) {
390 case printing::TOP:
391 y = printing::kSettingHeaderFooterInterstice -
392 page_layout.margin_top - offset_to_baseline;
393 break;
394 case printing::BOTTOM:
395 y = page_layout.margin_bottom + page_layout.content_height -
396 printing::kSettingHeaderFooterInterstice - offset_to_baseline;
397 break;
398 default:
399 NOTREACHED();
400 }
401
402 SkPoint point = SkPoint::Make(x / webkit_scale_factor,
403 y / webkit_scale_factor);
404 return point;
405 }
406
407 // Given a text, the positions, and the paint object, this method gets the
408 // coordinates and prints the text at those coordinates on the canvas.
409 void PrintHeaderFooterText(
410 const string16& text,
411 WebKit::WebCanvas* canvas,
412 HeaderFooterPaint paint,
413 float webkit_scale_factor,
414 const printing::PageSizeMargins& page_layout,
415 printing::HorizontalHeaderFooterPosition horizontal_position,
416 printing::VerticalHeaderFooterPosition vertical_position,
417 double offset_to_baseline) {
418 #if defined(USE_RENDER_TEXT)
419 paint->SetText(text);
420 paint->SetFontSize(printing::kSettingHeaderFooterFontSize);
421 double text_width_in_points = paint->GetStringSize().width();
422 SkPoint point = GetHeaderFooterPosition(webkit_scale_factor, page_layout,
423 horizontal_position,
424 vertical_position, offset_to_baseline,
425 text_width_in_points);
426 // Set the scaled font size before drawing the text.
427 // This creates a new font instead of calling |paint->SetFontSize()| to work
428 // around a Windows 8 bug. See: http://crbug.com/139206
429 gfx::FontList font_list(
430 gfx::Font(printing::kSettingHeaderFooterFontFamilyName,
431 printing::kSettingHeaderFooterFontSize / webkit_scale_factor));
432 paint->SetFontList(font_list);
433 gfx::Size size(paint->GetStringSize());
434 gfx::Rect rect(point.x(), point.y() - paint->GetBaseline(),
435 size.width(), size.height());
436 paint->SetDisplayRect(rect);
437 {
438 SkMatrix m = canvas->getTotalMatrix();
439 ui::ScaleFactor device_scale_factor = ui::GetScaleFactorFromScale(
440 SkScalarAbs(m.getScaleX()));
441 scoped_ptr<gfx::Canvas> gfx_canvas(gfx::Canvas::CreateCanvasWithoutScaling(
442 canvas, device_scale_factor));
443 paint->Draw(gfx_canvas.get());
444 }
445 #else
446 // TODO(arthurhsu): following code has issues with i18n BiDi, see
447 // crbug.com/108599.
448 size_t text_byte_length = text.length() * sizeof(char16);
449 double text_width_in_points = SkScalarToDouble(paint.measureText(
450 text.c_str(), text_byte_length));
451 SkPoint point = GetHeaderFooterPosition(webkit_scale_factor, page_layout,
452 horizontal_position,
453 vertical_position, offset_to_baseline,
454 text_width_in_points);
455 paint.setTextSize(SkDoubleToScalar(
456 paint.getTextSize() / webkit_scale_factor));
457 canvas->drawText(text.c_str(), text_byte_length, point.x(), point.y(),
458 paint);
459 #endif
460 }
461
462 PrintMsg_Print_Params CalculatePrintParamsForCss( 346 PrintMsg_Print_Params CalculatePrintParamsForCss(
463 WebKit::WebFrame* frame, 347 WebKit::WebFrame* frame,
464 int page_index, 348 int page_index,
465 const PrintMsg_Print_Params& page_params, 349 const PrintMsg_Print_Params& page_params,
466 bool ignore_css_margins, 350 bool ignore_css_margins,
467 bool fit_to_page, 351 bool fit_to_page,
468 double* scale_factor) { 352 double* scale_factor) {
469 PrintMsg_Print_Params css_params = GetCssPrintParams(frame, page_index, 353 PrintMsg_Print_Params css_params = GetCssPrintParams(frame, page_index,
470 page_params); 354 page_params);
471 355
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 int page_number, 404 int page_number,
521 int total_pages, 405 int total_pages,
522 float webkit_scale_factor, 406 float webkit_scale_factor,
523 const printing::PageSizeMargins& page_layout, 407 const printing::PageSizeMargins& page_layout,
524 const DictionaryValue& header_footer_info, 408 const DictionaryValue& header_footer_info,
525 const PrintMsg_Print_Params& params) { 409 const PrintMsg_Print_Params& params) {
526 skia::VectorPlatformDeviceSkia* device = 410 skia::VectorPlatformDeviceSkia* device =
527 static_cast<skia::VectorPlatformDeviceSkia*>(canvas->getTopDevice()); 411 static_cast<skia::VectorPlatformDeviceSkia*>(canvas->getTopDevice());
528 device->setDrawingArea(SkPDFDevice::kMargin_DrawingArea); 412 device->setDrawingArea(SkPDFDevice::kMargin_DrawingArea);
529 413
530 #if defined(USE_RENDER_TEXT) 414 SkAutoCanvasRestore auto_restore(canvas, true);
531 scoped_ptr<gfx::RenderText> render_text(gfx::RenderText::CreateInstance()); 415 canvas->scale(1/webkit_scale_factor, 1/webkit_scale_factor);
Alexei Svitkine (slow) 2012/11/10 16:52:13 Nit: spaces around the /'s.
Vitaly Buka (NO REVIEWS) 2012/11/12 08:20:52 Done.
532 // TODO(asvitkine): The below line is to workaround http://crbug.com/133548.
533 // Remove it when the underlying Skia bug has been fixed.
534 render_text->set_clip_to_display_rect(false);
535 gfx::FontList font_list(
536 gfx::Font(printing::kSettingHeaderFooterFontFamilyName,
537 printing::kSettingHeaderFooterFontSize));
538 gfx::RenderText* paint = render_text.get();
539 #else
540 SkPaint paint;
541 paint.setColor(SK_ColorBLACK);
542 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
543 paint.setTextSize(SkDoubleToScalar(printing::kSettingHeaderFooterFontSize));
544 paint.setTypeface(SkTypeface::CreateFromName(
545 printing::kSettingHeaderFooterFontFamilyName, SkTypeface::kNormal));
546 #endif
547 416
548 // Print the headers onto the |canvas| if there is enough space to print 417 WebKit::WebSize page_size(page_layout.margin_left + page_layout.margin_right +
549 // them. 418 page_layout.content_width,
550 string16 date; 419 page_layout.margin_top + page_layout.margin_bottom +
551 string16 title; 420 page_layout.content_height);
552 if (!header_footer_info.GetString(printing::kSettingHeaderFooterTitle,
553 &title) ||
554 !header_footer_info.GetString(printing::kSettingHeaderFooterDate,
555 &date)) {
556 NOTREACHED();
557 }
558 string16 header_text = date + title;
559 421
560 // Used for height calculations. Note that the width may be undefined. 422 WebKit::WebView* web_view = WebKit::WebView::create(NULL);
561 SkRect header_vertical_bounds; 423 web_view->settings()->setJavaScriptEnabled(true);
562 #if defined(USE_RENDER_TEXT) 424 web_view->initializeMainFrame(NULL);
563 paint->SetFontList(font_list);
564 paint->SetText(header_text);
565 {
566 gfx::Rect rect(gfx::Point(), paint->GetStringSize());
567 header_vertical_bounds = gfx::RectToSkRect(rect);
568 header_vertical_bounds.offset(0, -render_text->GetBaseline());
569 }
570 #else
571 paint.measureText(header_text.c_str(), header_text.length() * sizeof(char16),
572 &header_vertical_bounds, 0);
573 #endif
574 425
575 double text_height = printing::kSettingHeaderFooterInterstice + 426 WebKit::WebFrame* frame = web_view->mainFrame();
576 header_vertical_bounds.height();
577 if (text_height <= page_layout.margin_top) {
578 PrintHeaderFooterText(date, canvas, paint, webkit_scale_factor, page_layout,
579 printing::LEFT, printing::TOP,
580 header_vertical_bounds.top());
581 PrintHeaderFooterText(title, canvas, paint, webkit_scale_factor,
582 page_layout, printing::CENTER, printing::TOP,
583 header_vertical_bounds.top());
584 }
585 427
586 // Prints the footers onto the |canvas| if there is enough space to print 428 base::StringValue html(
587 // them. 429 ResourceBundle::GetSharedInstance().GetLocalizedString(
588 string16 page_of_total_pages = base::IntToString16(page_number) + 430 IDR_PRINT_PREVIEW_PAGE));
589 UTF8ToUTF16("/") + 431 // Load page with script to avoid async operations.
590 base::IntToString16(total_pages); 432 ExecuteScript(frame, kPageLoadScriptFormat, html);
591 string16 url;
592 if (!header_footer_info.GetString(printing::kSettingHeaderFooterURL, &url)) {
593 NOTREACHED();
594 }
595 string16 footer_text = page_of_total_pages + url;
596 433
597 // Used for height calculations. Note that the width may be undefined. 434 scoped_ptr<base::DictionaryValue> options(header_footer_info.DeepCopy());
598 SkRect footer_vertical_bounds; 435 options->SetDouble("width", page_size.width);
599 #if defined(USE_RENDER_TEXT) 436 options->SetDouble("height", page_size.height);
600 paint->SetFontList(font_list); 437 options->SetDouble("topMargin", page_layout.margin_top);
601 paint->SetText(footer_text); 438 options->SetDouble("bottomMargin", page_layout.margin_bottom);
602 { 439 options->SetString("pageNumber",
603 gfx::Rect rect(gfx::Point(), paint->GetStringSize()); 440 StringPrintf("%d/%d", page_number, total_pages));
604 footer_vertical_bounds = gfx::RectToSkRect(rect);
605 footer_vertical_bounds.offset(0, -paint->GetBaseline());
606 }
607 #else
608 paint.measureText(footer_text.c_str(), footer_text.length() * sizeof(char16),
609 &footer_vertical_bounds, 0);
610 #endif
611 441
612 text_height = printing::kSettingHeaderFooterInterstice + 442 ExecuteScript(frame, kPageSetupScriptFormat, *options);
613 footer_vertical_bounds.height(); 443
614 if (text_height <= page_layout.margin_bottom) { 444 WebKit::WebPrintParams webkit_params(page_size);
615 PrintHeaderFooterText(page_of_total_pages, canvas, paint, 445 webkit_params.printerDPI = GetDPI(&params);
616 webkit_scale_factor, page_layout, printing::RIGHT, 446
617 printing::BOTTOM, footer_vertical_bounds.bottom()); 447 frame->printBegin(webkit_params, WebKit::WebNode(), NULL);
618 PrintHeaderFooterText(url, canvas, paint, webkit_scale_factor, page_layout, 448 frame->printPage(0, canvas);
619 printing::LEFT, printing::BOTTOM, 449 frame->printEnd();
620 footer_vertical_bounds.bottom()); 450
621 } 451 web_view->close();
622 452
623 device->setDrawingArea(SkPDFDevice::kContent_DrawingArea); 453 device->setDrawingArea(SkPDFDevice::kContent_DrawingArea);
624 } 454 }
625 455
456 // static - Not anonymous so that platform implementations can use it.
457 float PrintWebViewHelper::RenderPageContent(WebKit::WebFrame* frame,
458 int page_number,
459 const gfx::Rect& canvas_area,
460 const gfx::Rect& content_area,
461 double scale_factor,
462 WebKit::WebCanvas* canvas) {
463 SkAutoCanvasRestore auto_restore(canvas, true);
464 if (content_area != canvas_area) {
465 canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
466 (content_area.y() - canvas_area.y()) / scale_factor);
467 SkRect clip_rect(
468 SkRect::MakeXYWH(content_area.origin().x() / scale_factor,
469 content_area.origin().y() / scale_factor,
470 content_area.size().width() / scale_factor,
471 content_area.size().height() / scale_factor));
472 SkIRect clip_int_rect;
473 clip_rect.roundOut(&clip_int_rect);
474 SkRegion clip_region(clip_int_rect);
475 canvas->setClipRegion(clip_region);
476 }
477 return frame->printPage(page_number, canvas);
478 }
479
626 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( 480 PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
627 const PrintMsg_Print_Params& print_params, 481 const PrintMsg_Print_Params& print_params,
628 WebKit::WebFrame* frame, 482 WebKit::WebFrame* frame,
629 const WebKit::WebNode& node) 483 const WebKit::WebNode& node)
630 : frame_(frame), 484 : frame_(frame),
631 node_to_print_(node), 485 node_to_print_(node),
632 web_view_(frame->view()), 486 web_view_(frame->view()),
633 expected_pages_count_(0), 487 expected_pages_count_(0),
634 use_browser_overlays_(true), 488 use_browser_overlays_(true),
635 finished_(false) { 489 finished_(false) {
(...skipping 1262 matching lines...) Expand 10 before | Expand all | Expand 10 after
1898 DCHECK(IsRendering()); 1752 DCHECK(IsRendering());
1899 return prep_frame_view_->GetPrintCanvasSize(); 1753 return prep_frame_view_->GetPrintCanvasSize();
1900 } 1754 }
1901 1755
1902 void PrintWebViewHelper::PrintPreviewContext::ClearContext() { 1756 void PrintWebViewHelper::PrintPreviewContext::ClearContext() {
1903 prep_frame_view_.reset(); 1757 prep_frame_view_.reset();
1904 metafile_.reset(); 1758 metafile_.reset();
1905 pages_to_render_.clear(); 1759 pages_to_render_.clear();
1906 error_ = PREVIEW_ERROR_NONE; 1760 error_ = PREVIEW_ERROR_NONE;
1907 } 1761 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698