0

Added Header and Footer support in Linux, Windows and Mac for Skia

BUG=67514
TEST=
In the preview tab, note added options for printing headers and footers.  Toggle with the checkbox and ensure that the correct headers and footers are displayed.

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=97219

Review URL: http://codereview.chromium.org/7348010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97233 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
aayushkumar@chromium.org
2011-08-17 23:09:36 +00:00
parent 4e8e0d15fc
commit 55b23a0e5a
36 changed files with 738 additions and 20 deletions

@ -5994,6 +5994,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_PRINT_PREVIEW_PRINT_PAGES_LABEL" desc="ARIA label used by screen reader to explain the purpose of the page selection textbox">
Print Specific Pages
</message>
<message name="IDS_PRINT_PREVIEW_OPTIONS_LABEL" desc="Options label currently providing the choice to print headers and footers.">
Options
</message>
<message name="IDS_PRINT_PREVIEW_OPTION_HEADER_FOOTER" desc="Checkbox label that provides a choice to print the headers and footers.">
Headers and footers
</message>
<!-- Load State -->
<message name="IDS_LOAD_STATE_WAITING_FOR_DELEGATE">

@ -56,6 +56,13 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
params->document_cookie = 0;
params->selection_only = settings.selection_only;
params->supports_alpha_blend = settings.supports_alpha_blend();
params->display_header_footer = settings.display_header_footer;
if (!settings.display_header_footer)
return;
params->date = settings.date;
params->title = settings.title;
params->url = settings.url;
}
} // namespace

@ -0,0 +1,7 @@
<div id="header-footer-option" class="two-column option visible">
<h1 i18n-content="optionsLabel"></h1>
<div>
<input id="header-footer" type="checkbox" checked>
<label for="header-footer" i18n-content="optionHeaderFooter"></label>
</div>
</div>

@ -0,0 +1,68 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cr.define('print_preview', function() {
'use strict';
/**
* Creates a HeaderFooterSettings object. This object encapsulates all
* settings and logic related to the headers and footers checkbox.
* @constructor
*/
function HeaderFooterSettings() {
this.headerFooterOption_ = $('header-footer-option');
this.headerFooterCheckbox_ = $('header-footer');
}
cr.addSingletonGetter(HeaderFooterSettings);
HeaderFooterSettings.prototype = {
/**
* The checkbox corresponding to the headers and footers option.
* @type {HTMLInputElement}
*/
get headerFooterCheckbox() {
return this.headerFooterCheckbox_;
},
/**
* Checks whether the Headers and Footers checkbox is checked or not.
* @return {boolean} true if Headers and Footers are checked.
*/
hasHeaderFooter: function() {
return this.headerFooterCheckbox_.checked;
},
/**
* Adding listeners to header footer related controls.
*/
addEventListeners: function() {
this.headerFooterCheckbox_.onclick =
this.onHeaderFooterChanged_.bind(this);
document.addEventListener('PDFLoaded', this.onPDFLoaded_.bind(this));
},
/**
* Listener executing when the user selects or de-selects the headers
* and footers option.
* @private
*/
onHeaderFooterChanged_: function() {
requestPrintPreview();
},
/**
* Listener executing when a PDFLoaded event occurs.
* @private
*/
onPDFLoaded_: function() {
if (!previewModifiable)
fadeOutElement(this.headerFooterOption_);
},
};
return {
HeaderFooterSettings: HeaderFooterSettings,
};
});

@ -346,6 +346,14 @@ html[os=mac] input[type='checkbox']:checked::before {
top: 2px;
}
html[os=mac] #options-horizontal-separator {
display: none;
}
html[os=mac] #options-option {
display: none;
}
input[type='radio'] {
-webkit-box-shadow: inset 0 1px 2px white,
0 1px 2px rgba(0, 0, 0, .2);

@ -39,6 +39,8 @@
<hr>
<include src="color_settings.html"></include>
<hr>
<include src="header_footer_settings.html"></include>
<hr id="options-horizontal-separator">
<div id="system-dialog-div">
<button id="system-dialog-link" class="link-button"
i18n-content="systemDialogOption"></button>

@ -51,6 +51,9 @@ var copiesSettings;
// Object holding all the layout related settings.
var layoutSettings;
// Object holding all the header footer related settings.
var headerFooterSettings;
// Object holding all the color related settings.
var colorSettings;
@ -104,10 +107,12 @@ function onLoad() {
pageSettings = print_preview.PageSettings.getInstance();
copiesSettings = print_preview.CopiesSettings.getInstance();
layoutSettings = print_preview.LayoutSettings.getInstance();
headerFooterSettings = print_preview.HeaderFooterSettings.getInstance();
colorSettings = print_preview.ColorSettings.getInstance();
printHeader.addEventListeners();
pageSettings.addEventListeners();
copiesSettings.addEventListeners();
headerFooterSettings.addEventListeners();
layoutSettings.addEventListeners();
colorSettings.addEventListeners();
$('printer-list').onchange = updateControlsWithSelectedPrinterCapabilities;
@ -311,6 +316,7 @@ function getSettings() {
'color': colorSettings.isColor(),
'printToPDF': printToPDF,
'isFirstRequest' : false,
'headerFooterEnabled': headerFooterSettings.hasHeaderFooter(),
'requestID': -1};
var printerList = $('printer-list');
@ -957,5 +963,6 @@ function setDefaultValuesAndRegeneratePreview() {
<include src="print_header.js"/>
<include src="page_settings.js"/>
<include src="copies_settings.js"/>
<include src="header_footer_settings.js"/>
<include src="layout_settings.js"/>
<include src="color_settings.js"/>

@ -95,6 +95,9 @@ PrintPreviewDataSource::PrintPreviewDataSource()
AddLocalizedString("incrementTitle", IDS_PRINT_PREVIEW_INCREMENT_TITLE);
AddLocalizedString("decrementTitle", IDS_PRINT_PREVIEW_DECREMENT_TITLE);
AddLocalizedString("printPagesLabel", IDS_PRINT_PREVIEW_PRINT_PAGES_LABEL);
AddLocalizedString("optionsLabel", IDS_PRINT_PREVIEW_OPTIONS_LABEL);
AddLocalizedString("optionHeaderFooter",
IDS_PRINT_PREVIEW_OPTION_HEADER_FOOTER);
set_json_path("strings.js");
add_resource_path("print_preview.js", IDR_PRINT_PREVIEW_JS);

@ -493,6 +493,24 @@ void PrintPreviewHandler::HandleGetPreview(const ListValue* args) {
print_preview_ui->OnPrintPreviewFailed();
return;
}
// Retrieve the page title and url and send it to the renderer process if
// headers and footers are to be displayed.
bool display_header_footer = false;
if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
&display_header_footer)) {
NOTREACHED();
}
if (display_header_footer) {
settings->SetString(printing::kSettingHeaderFooterTitle,
initiator_tab->GetTitle());
std::string url;
NavigationEntry* entry = initiator_tab->controller().GetActiveEntry();
if (entry)
url = entry->virtual_url().spec();
settings->SetString(printing::kSettingHeaderFooterURL, url);
}
VLOG(1) << "Print preview request start";
RenderViewHost* rvh = initiator_tab->render_view_host();
rvh->Send(new PrintMsg_PrintPreview(rvh->routing_id(), *settings));
@ -522,6 +540,8 @@ void PrintPreviewHandler::HandlePrint(const ListValue* args) {
bool print_to_pdf = false;
settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
TabContentsWrapper* preview_tab_wrapper =
TabContentsWrapper::GetCurrentWrapperForContents(preview_tab());

@ -54,6 +54,18 @@ IPC_STRUCT_BEGIN(PrintMsg_Print_Params)
// True if this is the first preview request, used only for print preview.
IPC_STRUCT_MEMBER(bool, is_first_request)
// Specifies if the header and footer should be rendered.
IPC_STRUCT_MEMBER(bool, display_header_footer)
// Date string to be printed as header if requested by the user.
IPC_STRUCT_MEMBER(string16, date)
// Title string to be printed as header if requested by the user.
IPC_STRUCT_MEMBER(string16, title)
// URL string to be printed as footer if requested by the user.
IPC_STRUCT_MEMBER(string16, url)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params)

@ -4,14 +4,78 @@
#include "chrome/renderer/mock_printer.h"
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/shared_memory.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/print_messages.h"
#include "ipc/ipc_message_utils.h"
#include "printing/metafile_impl.h"
#include "printing/units.h"
#include "testing/gtest/include/gtest/gtest.h"
PrintMsg_Print_Params_Clone::PrintMsg_Print_Params_Clone()
: page_size_(),
printable_size_(),
margin_top_(0),
margin_left_(0),
dpi_(0),
min_shrink_(0),
max_shrink_(0),
desired_dpi_(0),
document_cookie_(0),
selection_only_(0),
supports_alpha_blend_(0),
preview_request_id_(0),
is_first_request_(0),
display_header_footer_(0),
date_(),
title_(),
url_() {
}
PrintMsg_Print_Params_Clone::~PrintMsg_Print_Params_Clone(){}
void PrintMsg_Print_Params_Clone::ResetParams(PrintMsg_Print_Params* params) {
params->dpi = dpi_;
params->max_shrink = max_shrink_;
params->min_shrink = min_shrink_;
params->desired_dpi = desired_dpi_;
params->selection_only = selection_only_;
params->document_cookie = document_cookie_;
params->page_size = page_size_;
params->printable_size = printable_size_;
params->margin_left = margin_left_;
params->margin_top = margin_top_;
params->is_first_request = is_first_request_;
params->preview_request_id = preview_request_id_;
params->display_header_footer = display_header_footer_;
params->date = date_;
params->title = title_;
params->url = url_;
COMPILE_ASSERT(sizeof(PrintMsg_Print_Params_Clone) ==
sizeof(PrintMsg_Print_Params),
PrintMsg_Print_Params);
}
PrintMsg_PrintPages_Params_Clone::PrintMsg_PrintPages_Params_Clone()
: pages_(0) {
}
PrintMsg_PrintPages_Params_Clone::~PrintMsg_PrintPages_Params_Clone(){}
void PrintMsg_PrintPages_Params_Clone::ResetParams(
PrintMsg_PrintPages_Params* params) {
params_.ResetParams(&params->params);
params->pages = pages_;
COMPILE_ASSERT(sizeof(PrintMsg_PrintPages_Params_Clone) ==
sizeof(PrintMsg_PrintPages_Params_Clone),
PrintMsg_PrintPages_Params);
}
MockPrinterPage::MockPrinterPage(const void* source_data,
uint32 source_size,
const printing::Image& image)
@ -37,7 +101,11 @@ MockPrinter::MockPrinter()
number_pages_(0),
page_number_(0),
is_first_request_(true),
preview_request_id_(0) {
preview_request_id_(0),
display_header_footer_(false),
date_(ASCIIToUTF16("date")),
title_(ASCIIToUTF16("title")),
url_(ASCIIToUTF16("url")) {
page_size_.SetSize(static_cast<int>(8.5 * dpi_),
static_cast<int>(11.0 * dpi_));
printable_size_.SetSize(static_cast<int>((7.5 * dpi_)),
@ -60,7 +128,8 @@ void MockPrinter::GetDefaultPrintSettings(PrintMsg_Print_Params* params) {
// Assign a unit document cookie and set the print settings.
document_cookie_ = CreateDocumentCookie();
memset(params, 0, sizeof(PrintMsg_Print_Params));
PrintMsg_Print_Params_Clone params_clone;
params_clone.ResetParams(params);
SetPrintParams(params);
}
@ -74,6 +143,10 @@ void MockPrinter::SetDefaultPrintSettings(const PrintMsg_Print_Params& params) {
printable_size_ = params.printable_size;
margin_left_ = params.margin_left;
margin_top_ = params.margin_top;
display_header_footer_ = params.display_header_footer;
date_ = params.date;
title_ = params.title;
url_ = params.url;
}
void MockPrinter::ScriptedPrint(int cookie,
@ -83,7 +156,9 @@ void MockPrinter::ScriptedPrint(int cookie,
// Verify the input parameters.
EXPECT_EQ(document_cookie_, cookie);
memset(settings, 0, sizeof(PrintMsg_PrintPages_Params));
PrintMsg_PrintPages_Params_Clone params_clone;
params_clone.ResetParams(settings);
settings->params.dpi = dpi_;
settings->params.max_shrink = max_shrink_;
settings->params.min_shrink = min_shrink_;
@ -94,6 +169,10 @@ void MockPrinter::ScriptedPrint(int cookie,
settings->params.printable_size = printable_size_;
settings->params.is_first_request = is_first_request_;
settings->params.preview_request_id = preview_request_id_;
settings->params.display_header_footer = display_header_footer_;
settings->params.date = date_;
settings->params.title = title_;
settings->params.url = url_;
printer_status_ = PRINTER_PRINTING;
}
@ -101,7 +180,8 @@ void MockPrinter::UpdateSettings(int cookie,
PrintMsg_PrintPages_Params* params) {
EXPECT_EQ(document_cookie_, cookie);
memset(params, 0, sizeof(PrintMsg_PrintPages_Params));
PrintMsg_PrintPages_Params_Clone params_clone;
params_clone.ResetParams(params);
SetPrintParams(&(params->params));
printer_status_ = PRINTER_PRINTING;
}
@ -236,4 +316,8 @@ void MockPrinter::SetPrintParams(PrintMsg_Print_Params* params) {
params->margin_top = margin_top_;
params->is_first_request = is_first_request_;
params->preview_request_id = preview_request_id_;
params->display_header_footer = display_header_footer_;
params->date = date_;
params->title = title_;
params->url = url_;
}

@ -12,6 +12,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "printing/image.h"
#include "ui/gfx/size.h"
@ -134,9 +135,66 @@ class MockPrinter {
bool is_first_request_;
int preview_request_id_;
// Used for displaying headers and footers.
bool display_header_footer_;
string16 date_;
string16 title_;
string16 url_;
std::vector<scoped_refptr<MockPrinterPage> > pages_;
DISALLOW_COPY_AND_ASSIGN(MockPrinter);
};
// A clone of PrintMsg_Print_Params struct.
class PrintMsg_Print_Params_Clone {
public:
PrintMsg_Print_Params_Clone();
~PrintMsg_Print_Params_Clone();
// Resets the members of |params| to 0. Checks to see if
// PrintMsg_Print_Params and PrintMsg_Print_Params_Clone have identical
// member variables.
void ResetParams(PrintMsg_Print_Params* params);
private:
gfx::Size page_size_;
gfx::Size printable_size_;
int margin_top_;
int margin_left_;
double dpi_;
double min_shrink_;
double max_shrink_;
int desired_dpi_;
int document_cookie_;
bool selection_only_;
bool supports_alpha_blend_;
int preview_request_id_;
bool is_first_request_;
bool display_header_footer_;
string16 date_;
string16 title_;
string16 url_;
DISALLOW_COPY_AND_ASSIGN(PrintMsg_Print_Params_Clone);
};
// A clone of PrintMsg_PrintPages_Params struct.
class PrintMsg_PrintPages_Params_Clone {
public:
PrintMsg_PrintPages_Params_Clone();
~PrintMsg_PrintPages_Params_Clone();
// Resets the members of |params| to 0. Checks to see if
// PrintMsg_PrintPages_Params and PrintMsg_PrintPages_Params_Clone have
// identical member variables.
void ResetParams(PrintMsg_PrintPages_Params* params);
private:
PrintMsg_Print_Params_Clone params_;
std::vector<int> pages_;
DISALLOW_COPY_AND_ASSIGN(PrintMsg_PrintPages_Params_Clone);
};
#endif // CHROME_RENDERER_MOCK_PRINTER_H_

@ -36,10 +36,19 @@
#include "content/common/view_messages.h"
#endif
#if defined(USE_SKIA)
#include "base/string_number_conversions.h"
#include "skia/ext/vector_canvas.h"
#include "skia/ext/vector_platform_device_skia.h"
#include "third_party/skia/include/core/SkTypeface.h"
#endif // defined(USE_SKIA)
using base::Time;
using printing::ConvertPixelsToPoint;
using printing::ConvertPixelsToPointDouble;
using printing::ConvertUnit;
using printing::ConvertUnitDouble;
using printing::GetHeaderFooterSegmentWidth;
using WebKit::WebConsoleMessage;
using WebKit::WebDocument;
using WebKit::WebElement;
@ -87,6 +96,11 @@ bool PrintMsg_Print_Params_IsEqual(
oldParams.params.supports_alpha_blend ==
newParams.params.supports_alpha_blend &&
oldParams.pages.size() == newParams.pages.size() &&
oldParams.params.display_header_footer ==
newParams.params.display_header_footer &&
oldParams.params.date == newParams.params.date &&
oldParams.params.title == newParams.params.title &&
oldParams.params.url == newParams.params.url &&
std::equal(oldParams.pages.begin(), oldParams.pages.end(),
newParams.pages.begin());
}
@ -101,8 +115,147 @@ void CalculatePrintCanvasSize(const PrintMsg_Print_Params& print_params,
print_params.desired_dpi));
}
#if defined(USE_SKIA)
// Given a text, the positions, and the paint object, this method gets the
// coordinates and prints the text at those coordinates on the canvas.
void PrintHeaderFooterText(
string16 text,
skia::VectorCanvas* canvas,
SkPaint paint,
float webkit_scale_factor,
const PageSizeMargins& page_layout,
printing::HorizontalHeaderFooterPosition horizontal_position,
printing::VerticalHeaderFooterPosition vertical_position,
SkScalar offset_to_baseline) {
size_t text_byte_length = text.length() * sizeof(char16);
// Get the (x, y) coordinate from where printing of the current text should
// start depending on the horizontal alignment (LEFT, RIGHT, CENTER) and
// vertical alignment (TOP, BOTTOM).
SkScalar text_width_in_points = paint.measureText(text.c_str(),
text_byte_length);
SkScalar x = 0;
switch (horizontal_position) {
case printing::LEFT: {
x = printing::kSettingHeaderFooterInterstice - page_layout.margin_left;
break;
}
case printing::RIGHT: {
x = page_layout.content_width + page_layout.margin_right -
printing::kSettingHeaderFooterInterstice - text_width_in_points;
break;
}
case printing::CENTER: {
SkScalar available_width = GetHeaderFooterSegmentWidth(
page_layout.margin_left + page_layout.margin_right +
page_layout.content_width);
x = available_width - page_layout.margin_left +
(available_width - text_width_in_points) / 2;
break;
}
default: {
NOTREACHED();
}
}
SkScalar y = 0;
switch (vertical_position) {
case printing::TOP:
y = printing::kSettingHeaderFooterInterstice -
page_layout.margin_top - offset_to_baseline;
break;
case printing::BOTTOM:
y = page_layout.margin_bottom + page_layout.content_height -
printing::kSettingHeaderFooterInterstice - offset_to_baseline;
break;
default:
NOTREACHED();
}
x = x / webkit_scale_factor;
y = y / webkit_scale_factor;
paint.setTextSize(paint.getTextSize() / webkit_scale_factor);
canvas->drawText(text.c_str(), text_byte_length, x, y, paint);
}
#endif // defined(USE_SKIA)
} // namespace
#if defined(USE_SKIA)
// static - Not anonymous so that platform implementations can use it.
void PrintWebViewHelper::PrintHeaderAndFooter(
SkDevice* device,
skia::VectorCanvas* canvas,
int page_number,
int total_pages,
float webkit_scale_factor,
const PageSizeMargins& page_layout,
const DictionaryValue& header_footer_info) {
static_cast<skia::VectorPlatformDeviceSkia*>(device)->setDrawingArea(
SkPDFDevice::kMargin_DrawingArea);
SkPaint paint;
paint.setColor(SK_ColorBLACK);
paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
paint.setTextSize(printing::kSettingHeaderFooterFontSize);
paint.setTypeface(SkTypeface::CreateFromName(
printing::kSettingHeaderFooterFontFamilyName, SkTypeface::kNormal));
// Print the headers onto the |canvas| if there is enough space to print
// them.
string16 date;
string16 title;
if (!header_footer_info.GetString(printing::kSettingHeaderFooterTitle,
&title) ||
!header_footer_info.GetString(printing::kSettingHeaderFooterDate,
&date)) {
NOTREACHED();
}
string16 header_text = date + title;
SkRect header_bounds;
paint.measureText(header_text.c_str(), header_text.length() * sizeof(char16),
&header_bounds, 0);
SkScalar text_height =
printing::kSettingHeaderFooterInterstice + header_bounds.height();
if (text_height <= page_layout.margin_top) {
PrintHeaderFooterText(date, canvas, paint, webkit_scale_factor, page_layout,
printing::LEFT, printing::TOP, header_bounds.top());
PrintHeaderFooterText(title, canvas, paint, webkit_scale_factor,
page_layout, printing::CENTER, printing::TOP,
header_bounds.top());
}
// Prints the footers onto the |canvas| if there is enough space to print
// them.
string16 page_of_total_pages = base::IntToString16(page_number) +
UTF8ToUTF16("/") +
base::IntToString16(total_pages);
string16 url;
if (!header_footer_info.GetString(printing::kSettingHeaderFooterURL,
&url)) {
NOTREACHED();
}
string16 footer_text = page_of_total_pages + url;
SkRect footer_bounds;
paint.measureText(footer_text.c_str(), footer_text.length() * sizeof(char16),
&footer_bounds, 0);
text_height =
printing::kSettingHeaderFooterInterstice + footer_bounds.height();
if (text_height <= page_layout.margin_bottom) {
PrintHeaderFooterText(page_of_total_pages, canvas, paint,
webkit_scale_factor, page_layout, printing::RIGHT,
printing::BOTTOM, footer_bounds.bottom());
PrintHeaderFooterText(url, canvas, paint, webkit_scale_factor, page_layout,
printing::LEFT, printing::BOTTOM,
footer_bounds.bottom());
}
static_cast<skia::VectorPlatformDeviceSkia*>(device)->setDrawingArea(
SkPDFDevice::kContent_DrawingArea);
}
#endif // defined(USE_SKIA)
PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
const PrintMsg_Print_Params& print_params,
WebFrame* frame,
@ -766,7 +919,7 @@ bool PrintWebViewHelper::UpdatePrintSettings(
PrintMsg_PrintPages_Params settings;
Send(new PrintHostMsg_UpdatePrintSettings(routing_id(),
print_pages_params_->params.document_cookie, job_settings, &settings));
print_pages_params_->params.document_cookie, job_settings, &settings));
if (settings.params.dpi < kMinDpi || !settings.params.document_cookie)
return false;
@ -780,6 +933,17 @@ bool PrintWebViewHelper::UpdatePrintSettings(
}
print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings));
if (print_pages_params_->params.display_header_footer) {
header_footer_info_.reset(new DictionaryValue());
header_footer_info_->SetString(printing::kSettingHeaderFooterDate,
print_pages_params_->params.date);
header_footer_info_->SetString(printing::kSettingHeaderFooterURL,
print_pages_params_->params.url);
header_footer_info_->SetString(printing::kSettingHeaderFooterTitle,
print_pages_params_->params.title);
}
Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
settings.params.document_cookie));
return true;

@ -28,6 +28,11 @@ struct PrintMsg_PrintPages_Params;
namespace base {
class DictionaryValue;
}
#if defined(USE_SKIA)
namespace skia {
class VectorCanvas;
}
#endif
// Class that calls the Begin and End print functions on the frame and changes
// the size of the view temporarily to support full page printing..
@ -266,6 +271,19 @@ class PrintWebViewHelper : public RenderViewObserver,
PrepareFrameAndViewForPrint* prepare,
PrintMsg_Print_Params* params);
#if defined(USE_SKIA)
// Given the |device| and |canvas| to draw on, prints the appropriate headers
// and footers using strings from |header_footer_info| on to the canvas.
static void PrintHeaderAndFooter(
SkDevice* device,
skia::VectorCanvas* canvas,
int page_number,
int total_pages,
float webkit_scale_factor,
const PageSizeMargins& page_layout_in_points,
const base::DictionaryValue& header_footer_info);
#endif // defined(USE_SKIA)
bool GetPrintFrame(WebKit::WebFrame** frame);
// This reports the current time - |start_time| as the time to render a page.
@ -309,6 +327,10 @@ class PrintWebViewHelper : public RenderViewObserver,
scoped_ptr<PrintMsg_PrintPages_Params> old_print_pages_params_;
// Strings generated by the browser process to be printed as headers and
// footers if requested by the user.
scoped_ptr<base::DictionaryValue> header_footer_info_;
// Keeps track of the state of print preview between messages.
class PrintPreviewContext {
public:

@ -43,6 +43,7 @@ void CreatePrintSettingsDictionary(DictionaryValue* dict) {
dict->SetString(printing::kSettingDeviceName, "dummy");
dict->SetInteger(printing::kPreviewRequestID, 12345);
dict->SetBoolean(printing::kIsFirstRequest, true);
dict->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
}
} // namespace

@ -209,7 +209,13 @@ void PrintWebViewHelper::PrintPageInternal(
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile);
frame->printPage(params.page_number, canvas.get());
// TODO(myhuang): We should render the header and the footer.
if (params.params.display_header_footer) {
// |page_number| is 0-based, so 1 is added.
// The scale factor on Linux is 1.
PrintHeaderAndFooter(device, canvas.get(), params.page_number + 1,
print_preview_context_.total_page_count(), 1,
page_layout_in_points, *header_footer_info_);
}
// Done printing. Close the device context to retrieve the compiled metafile.
if (!metafile->FinishPage())

@ -148,6 +148,20 @@ void PrintWebViewHelper::RenderPage(
CGContextRef canvasPtr = cgContext;
#endif
frame->printPage(page_number, canvasPtr);
#if defined(USE_SKIA)
const PrintMsg_Print_Params& printParams =
print_preview_context_.print_params();
if (printParams.display_header_footer) {
PageSizeMargins page_layout_in_points;
GetPageSizeAndMarginsInPoints(frame, page_number, printParams,
&page_layout_in_points);
// |page_number| is 0-based, so 1 is added.
PrintHeaderAndFooter(device, canvas.get(), page_number + 1,
print_preview_context_.total_page_count(),
scale_factor, page_layout_in_points,
*header_footer_info_);
}
#endif // defined(USE_SKIA)
}
// Done printing. Close the device context to retrieve the compiled metafile.

@ -187,6 +187,15 @@ Metafile* PrintWebViewHelper::RenderPage(
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile);
float webkit_scale_factor = frame->printPage(page_number, canvas.get());
if (params.display_header_footer) {
// |page_number| is 0-based, so 1 is added.
PrintHeaderAndFooter(device, canvas.get(), page_number + 1,
print_preview_context_.total_page_count(),
webkit_scale_factor, page_layout_in_points,
*header_footer_info_);
}
if (*scale_factor <= 0 || webkit_scale_factor <= 0) {
NOTREACHED() << "Printing page " << page_number << " failed.";
} else {

@ -30,6 +30,37 @@ const char kSettingDeviceName[] = "deviceName";
// Print job duplex mode.
const char kSettingDuplexMode[] = "duplex";
// Option to print headers and Footers: true if selected, false if not.
const char kSettingHeaderFooterEnabled[] = "headerFooterEnabled";
// Default font family name for printing the headers and footers.
const char kSettingHeaderFooterFontFamilyName[] = "sans";
// Default font name for printing the headers and footers.
const char kSettingHeaderFooterFontName[] = "Helvetica";
// Default font size for printing the headers and footers.
const int kSettingHeaderFooterFontSize = 8;
// Number of horizontal regions for headers and footers.
const float kSettingHeaderFooterHorizontalRegions = 3;
// Interstice or gap between different header footer components.
// Hardcoded to 0.25cm = 1/10" = 7.2points.
const float kSettingHeaderFooterInterstice = 7.2f;
// Key that specifies the date of the page that will be printed in the headers
// and footers.
const char kSettingHeaderFooterDate[] = "date";
// Key that specifies the title of the page that will be printed in the headers
// and footers.
const char kSettingHeaderFooterTitle[] = "title";
// Key that specifies the URL of the page that will be printed in the headers
// and footers.
const char kSettingHeaderFooterURL[] = "url";
// Page orientation: true for landscape, false for portrait.
const char kSettingLandscape[] = "landscape";

@ -15,6 +15,15 @@ extern const char kSettingColor[];
extern const char kSettingCopies[];
extern const char kSettingDeviceName[];
extern const char kSettingDuplexMode[];
extern const char kSettingHeaderFooterEnabled[];
extern const char kSettingHeaderFooterFontFamilyName[];
extern const char kSettingHeaderFooterFontName[];
extern const int kSettingHeaderFooterFontSize;
extern const float kSettingHeaderFooterHorizontalRegions;
extern const float kSettingHeaderFooterInterstice;
extern const char kSettingHeaderFooterDate[];
extern const char kSettingHeaderFooterTitle[];
extern const char kSettingHeaderFooterURL[];
extern const char kSettingLandscape[];
extern const char kSettingPageRange[];
extern const char kSettingPageRangeFrom[];
@ -33,6 +42,19 @@ enum DuplexMode {
SHORT_EDGE,
};
// Specifies the horizontal alignment of the headers and footers.
enum HorizontalHeaderFooterPosition {
LEFT,
CENTER,
RIGHT
};
// Specifies the vertical alignment of the Headers and Footers.
enum VerticalHeaderFooterPosition {
TOP,
BOTTOM
};
} // namespace printing
#endif // PRINTING_PRINT_JOB_CONSTANTS_H_

@ -7,6 +7,8 @@
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "printing/page_range.h"
#include "printing/page_setup.h"
#include "ui/gfx/rect.h"
@ -95,6 +97,14 @@ class PrintSettings {
// Updates the orientation and flip the page if needed.
void SetOrientation(bool landscape);
// Strings to be printed as headers and footers if requested by the user.
string16 date;
string16 title;
string16 url;
// True if the user wants headers and footers to be displayed.
bool display_header_footer;
private:
//////////////////////////////////////////////////////////////////////////////
// Settings that can't be changed without side-effects.

@ -0,0 +1,72 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "printing/print_settings_initializer.h"
#include <algorithm>
#include <cmath>
#include "base/i18n/time_formatting.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings.h"
#include "printing/units.h"
#include "ui/base/text/text_elider.h"
using base::DictionaryValue;
using base::Time;
using printing::ConvertPointsToPixelDouble;
using printing::ConvertUnitDouble;
using printing::GetHeaderFooterSegmentWidth;
namespace printing {
void PrintSettingsInitializer::InitHeaderFooterStrings(
const DictionaryValue& job_settings,
PrintSettings* print_settings) {
if (!job_settings.GetBoolean(printing::kSettingHeaderFooterEnabled,
&print_settings->display_header_footer)) {
NOTREACHED();
}
if (!print_settings->display_header_footer)
return;
string16 date = base::TimeFormatShortDateNumeric(Time::Now());
string16 title;
std::string url;
if (!job_settings.GetString(printing::kSettingHeaderFooterTitle, &title) ||
!job_settings.GetString(printing::kSettingHeaderFooterURL, &url)) {
NOTREACHED();
}
gfx::Font font(UTF8ToUTF16(printing::kSettingHeaderFooterFontName),
ceil(ConvertPointsToPixelDouble(
printing::kSettingHeaderFooterFontSize)));
double segment_width = GetHeaderFooterSegmentWidth(ConvertUnitDouble(
print_settings->page_setup_device_units().physical_size().width(),
print_settings->device_units_per_inch(),
printing::kPixelsPerInch));
date = ui::ElideText(date, font, segment_width, false);
print_settings->date = date;
// Calculate the available title width. If the date string is not long
// enough, increase the available space for the title.
// Assumes there is no header text to RIGHT of title.
double date_width = font.GetStringWidth(date);
double max_title_width = std::min(2 * segment_width,
2 * (segment_width - date_width) +
segment_width);
print_settings->title = ui::ElideText(title, font, max_title_width, false);
double max_url_width = 2 * segment_width;
GURL gurl(url);
print_settings->url = ui::ElideUrl(gurl, font, max_url_width, std::string());
}
} // namespace printing

@ -0,0 +1,34 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PRINTING_PRINT_SETTINGS_INITIALIZER_H_
#define PRINTING_PRINT_SETTINGS_INITIALIZER_H_
#include "base/basictypes.h"
#include "base/logging.h"
namespace base {
class DictionaryValue;
}
namespace printing {
class PrintSettings;
// Initializes the header footer strings in the PrintSettings object from the
// provided |job_settings|.
class PrintSettingsInitializer {
public:
static void InitHeaderFooterStrings(
const base::DictionaryValue& job_settings,
PrintSettings* print_settings);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PrintSettingsInitializer);
};
} // namespace printing
#endif // PRINTING_PRINT_SETTINGS_INITIALIZER_H_

@ -73,6 +73,8 @@
'print_job_constants.h',
'print_settings.cc',
'print_settings.h',
'print_settings_initializer.cc',
'print_settings_initializer.h',
'print_settings_initializer_gtk.cc',
'print_settings_initializer_gtk.h',
'print_settings_initializer_mac.cc',

@ -5,6 +5,7 @@
#include "printing/printing_context.h"
#include "base/values.h"
#include "printing/print_settings_initializer.h"
namespace printing {
@ -33,4 +34,13 @@ PrintingContext::Result PrintingContext::OnError() {
return abort_printing_ ? CANCEL : FAILED;
}
PrintingContext::Result PrintingContext::UpdatePrintSettings(
const base::DictionaryValue& job_settings,
const PageRanges& ranges) {
PrintingContext::Result result = UpdatePrinterSettings(job_settings, ranges);
printing::PrintSettingsInitializer::InitHeaderFooterStrings(job_settings,
&settings_);
return result;
}
} // namespace printing

@ -51,10 +51,16 @@ class PrintingContext {
// default device settings.
virtual Result UseDefaultSettings() = 0;
// Updates print settings. |job_settings| contains all print job settings
// information. |ranges| has the new page range settings.
virtual Result UpdatePrintSettings(const base::DictionaryValue& job_settings,
const PageRanges& ranges) = 0;
// Updates printer related settings. |job_settings| contains all print job
// settings information. |ranges| has the new page range settings.
virtual Result UpdatePrinterSettings(
const base::DictionaryValue& job_settings,
const PageRanges& ranges) = 0;
// Updates Print Settings. |job_settings| contains all print job
// settings information. |ranges| has the new page range settings.
Result UpdatePrintSettings(const base::DictionaryValue& job_settings,
const PageRanges& ranges);
// Initializes with predefined settings.
virtual Result InitWithSettings(const PrintSettings& settings) = 0;

@ -140,7 +140,7 @@ PrintingContext::Result PrintingContextCairo::UseDefaultSettings() {
return OK;
}
PrintingContext::Result PrintingContextCairo::UpdatePrintSettings(
PrintingContext::Result PrintingContextCairo::UpdatePrinterSettings(
const DictionaryValue& job_settings, const PageRanges& ranges) {
#if defined(OS_CHROMEOS)
bool landscape = false;

@ -39,8 +39,9 @@ class PrintingContextCairo : public PrintingContext {
bool has_selection,
PrintSettingsCallback* callback);
virtual Result UseDefaultSettings();
virtual Result UpdatePrintSettings(const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result UpdatePrinterSettings(
const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result InitWithSettings(const PrintSettings& settings);
virtual Result NewDocument(const string16& document_name);
virtual Result NewPage();

@ -30,8 +30,9 @@ class PrintingContextMac : public PrintingContext {
bool has_selection,
PrintSettingsCallback* callback);
virtual Result UseDefaultSettings();
virtual Result UpdatePrintSettings(const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result UpdatePrinterSettings(
const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result InitWithSettings(const PrintSettings& settings);
virtual Result NewDocument(const string16& document_name);
virtual Result NewPage();

@ -98,7 +98,7 @@ PrintingContext::Result PrintingContextMac::UseDefaultSettings() {
return OK;
}
PrintingContext::Result PrintingContextMac::UpdatePrintSettings(
PrintingContext::Result PrintingContextMac::UpdatePrinterSettings(
const DictionaryValue& job_settings, const PageRanges& ranges) {
DCHECK(!in_print_job_);

@ -302,7 +302,7 @@ PrintingContext::Result PrintingContextWin::UseDefaultSettings() {
return FAILED;
}
PrintingContext::Result PrintingContextWin::UpdatePrintSettings(
PrintingContext::Result PrintingContextWin::UpdatePrinterSettings(
const DictionaryValue& job_settings,
const PageRanges& ranges) {
DCHECK(!in_print_job_);

@ -28,8 +28,9 @@ class PrintingContextWin : public PrintingContext {
bool has_selection,
PrintSettingsCallback* callback);
virtual Result UseDefaultSettings();
virtual Result UpdatePrintSettings(const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result UpdatePrinterSettings(
const base::DictionaryValue& job_settings,
const PageRanges& ranges);
virtual Result InitWithSettings(const PrintSettings& settings);
virtual Result NewDocument(const string16& document_name);
virtual Result NewPage();

@ -5,6 +5,7 @@
#include "printing/units.h"
#include "base/logging.h"
#include "printing/print_job_constants.h"
namespace printing {
@ -47,4 +48,18 @@ double ConvertPixelsToPointDouble(double pixels) {
return ConvertUnitDouble(pixels, kPixelsPerInch, kPointsPerInch);
}
double ConvertPointsToPixelDouble(double points) {
return ConvertUnitDouble(points, kPointsPerInch, kPixelsPerInch);
}
double GetHeaderFooterSegmentWidth(double page_width) {
// Interstice is left at both ends of the page as well as between
// each region, so 1 is added.
double total_interstice_width =
(printing::kSettingHeaderFooterHorizontalRegions + 1) *
printing::kSettingHeaderFooterInterstice;
return (page_width - total_interstice_width) /
printing::kSettingHeaderFooterHorizontalRegions;
}
} // namespace printing

@ -36,6 +36,13 @@ int ConvertPixelsToPoint(int pixels);
// Converts from 1 pixel to 1 point using doubles.
double ConvertPixelsToPointDouble(double pixels);
// Converts from 1 point to 1 pixel using doubles.
double ConvertPointsToPixelDouble(double points);
// Splits the horizontal width equally into segments with an interstice
// between each segment. Returns the width of a segment.
double GetHeaderFooterSegmentWidth(double page_width);
} // namespace printing
#endif // PRINTING_UNITS_H_

@ -193,6 +193,10 @@ void VectorPlatformDeviceSkia::drawDevice(const SkDraw& draw,
pdf_device_->drawDevice(draw, real_device, x, y, paint);
}
void VectorPlatformDeviceSkia::setDrawingArea(SkPDFDevice::DrawingArea area) {
pdf_device_->setDrawingArea(area);
}
#if defined(OS_WIN)
void VectorPlatformDeviceSkia::DrawToNativeContext(HDC dc,
int x,

@ -79,8 +79,12 @@ class VectorPlatformDeviceSkia : public PlatformDevice {
virtual void drawDevice(const SkDraw& draw, SkDevice*, int x, int y,
const SkPaint&);
// Sets the drawing area for the device. Subsequent draw calls are
// directed to the specific drawing area (margin or content area).
SK_API void setDrawingArea(SkPDFDevice::DrawingArea area);
protected:
virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config, int width,
virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config, int width,
int height, bool isOpaque,
Usage usage);