1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/printing/renderer/print_web_view_helper.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/process/process_handle.h"
10 #include "components/printing/common/print_messages.h"
11 #include "content/public/renderer/render_thread.h"
12 #include "printing/metafile_skia_wrapper.h"
13 #include "printing/page_size_margins.h"
14 #include "printing/pdf_metafile_skia.h"
15 #include "printing/units.h"
16 #include "skia/ext/platform_device.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
21 using blink::WebFrame
;
23 bool PrintWebViewHelper::RenderPreviewPage(
25 const PrintMsg_Print_Params
& print_params
) {
26 PrintMsg_PrintPage_Params page_params
;
27 page_params
.params
= print_params
;
28 page_params
.page_number
= page_number
;
29 scoped_ptr
<PdfMetafileSkia
> draft_metafile
;
30 PdfMetafileSkia
* initial_render_metafile
= print_preview_context_
.metafile();
31 if (print_preview_context_
.IsModifiable() && is_print_ready_metafile_sent_
) {
32 draft_metafile
.reset(new PdfMetafileSkia
);
33 initial_render_metafile
= draft_metafile
.get();
36 base::TimeTicks begin_time
= base::TimeTicks::Now();
37 PrintPageInternal(page_params
,
38 print_preview_context_
.prepared_frame(),
39 initial_render_metafile
,
42 print_preview_context_
.RenderedPreviewPage(
43 base::TimeTicks::Now() - begin_time
);
44 if (draft_metafile
.get()) {
45 draft_metafile
->FinishDocument();
46 } else if (print_preview_context_
.IsModifiable() &&
47 print_preview_context_
.generate_draft_pages()) {
48 DCHECK(!draft_metafile
.get());
50 print_preview_context_
.metafile()->GetMetafileForCurrentPage();
52 return PreviewPageRendered(page_number
, draft_metafile
.get());
55 bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame
* frame
,
57 PdfMetafileSkia metafile
;
61 const PrintMsg_PrintPages_Params
& params
= *print_pages_params_
;
62 std::vector
<int> printed_pages
;
63 if (params
.pages
.empty()) {
64 for (int i
= 0; i
< page_count
; ++i
) {
65 printed_pages
.push_back(i
);
68 // TODO(vitalybuka): redesign to make more code cross platform.
69 for (size_t i
= 0; i
< params
.pages
.size(); ++i
) {
70 if (params
.pages
[i
] >= 0 && params
.pages
[i
] < page_count
) {
71 printed_pages
.push_back(params
.pages
[i
]);
75 if (printed_pages
.empty())
78 std::vector
<gfx::Size
> page_size_in_dpi(printed_pages
.size());
79 std::vector
<gfx::Rect
> content_area_in_dpi(printed_pages
.size());
81 PrintMsg_PrintPage_Params page_params
;
82 page_params
.params
= params
.params
;
83 for (size_t i
= 0; i
< printed_pages
.size(); ++i
) {
84 page_params
.page_number
= printed_pages
[i
];
85 PrintPageInternal(page_params
,
89 &content_area_in_dpi
[i
]);
92 // blink::printEnd() for PDF should be called before metafile is closed.
93 FinishFramePrinting();
95 metafile
.FinishDocument();
97 // Get the size of the resulting metafile.
98 uint32 buf_size
= metafile
.GetDataSize();
99 DCHECK_GT(buf_size
, 0u);
101 PrintHostMsg_DidPrintPage_Params printed_page_params
;
102 printed_page_params
.data_size
= 0;
103 printed_page_params
.document_cookie
= params
.params
.document_cookie
;
104 printed_page_params
.page_size
= params
.params
.page_size
;
105 printed_page_params
.content_area
= params
.params
.printable_area
;
108 base::SharedMemory shared_buf
;
109 // Allocate a shared memory buffer to hold the generated metafile data.
110 if (!shared_buf
.CreateAndMapAnonymous(buf_size
)) {
111 NOTREACHED() << "Buffer allocation failed";
115 // Copy the bits into shared memory.
116 if (!metafile
.GetData(shared_buf
.memory(), buf_size
)) {
117 NOTREACHED() << "GetData() failed";
121 shared_buf
.GiveToProcess(base::GetCurrentProcessHandle(),
122 &printed_page_params
.metafile_data_handle
);
125 printed_page_params
.data_size
= buf_size
;
126 Send(new PrintHostMsg_DuplicateSection(
128 printed_page_params
.metafile_data_handle
,
129 &printed_page_params
.metafile_data_handle
));
132 for (size_t i
= 0; i
< printed_pages
.size(); ++i
) {
133 printed_page_params
.page_number
= printed_pages
[i
];
134 printed_page_params
.page_size
= page_size_in_dpi
[i
];
135 printed_page_params
.content_area
= content_area_in_dpi
[i
];
136 Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params
));
137 printed_page_params
.metafile_data_handle
= INVALID_HANDLE_VALUE
;
142 void PrintWebViewHelper::PrintPageInternal(
143 const PrintMsg_PrintPage_Params
& params
,
145 PdfMetafileSkia
* metafile
,
146 gfx::Size
* page_size_in_dpi
,
147 gfx::Rect
* content_area_in_dpi
) {
148 PageSizeMargins page_layout_in_points
;
149 double css_scale_factor
= 1.0f
;
150 ComputePageLayoutInPointsForCss(frame
, params
.page_number
, params
.params
,
151 ignore_css_margins_
, &css_scale_factor
,
152 &page_layout_in_points
);
154 gfx::Rect content_area
;
155 GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points
, &page_size
,
157 int dpi
= static_cast<int>(params
.params
.dpi
);
158 // Calculate the actual page size and content area in dpi.
159 if (page_size_in_dpi
) {
161 gfx::Size(static_cast<int>(ConvertUnitDouble(page_size
.width(),
162 kPointsPerInch
, dpi
)),
163 static_cast<int>(ConvertUnitDouble(page_size
.height(),
164 kPointsPerInch
, dpi
)));
167 if (content_area_in_dpi
) {
168 // Output PDF matches paper size and should be printer edge to edge.
169 *content_area_in_dpi
=
170 gfx::Rect(0, 0, page_size_in_dpi
->width(), page_size_in_dpi
->height());
173 gfx::Rect canvas_area
=
174 params
.params
.display_header_footer
? gfx::Rect(page_size
) : content_area
;
176 float webkit_page_shrink_factor
=
177 frame
->getPrintPageShrink(params
.page_number
);
178 float scale_factor
= css_scale_factor
* webkit_page_shrink_factor
;
180 skia::PlatformCanvas
* canvas
=
181 metafile
->GetVectorCanvasForNewPage(page_size
, canvas_area
, scale_factor
);
185 MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas
, metafile
);
186 skia::SetIsDraftMode(*canvas
, is_print_ready_metafile_sent_
);
188 #if defined(ENABLE_PRINT_PREVIEW)
189 if (params
.params
.display_header_footer
) {
190 // |page_number| is 0-based, so 1 is added.
191 PrintHeaderAndFooter(canvas
, params
.page_number
+ 1,
192 print_preview_context_
.total_page_count(), *frame
,
193 scale_factor
, page_layout_in_points
, params
.params
);
195 #endif // defined(ENABLE_PRINT_PREVIEW)
197 float webkit_scale_factor
=
198 RenderPageContent(frame
, params
.page_number
, canvas_area
, content_area
,
199 scale_factor
, canvas
);
200 DCHECK_GT(webkit_scale_factor
, 0.0f
);
201 // Done printing. Close the canvas to retrieve the compiled metafile.
202 if (!metafile
->FinishPage())
203 NOTREACHED() << "metafile failed";
206 bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
207 PdfMetafileSkia
* metafile
,
208 base::SharedMemoryHandle
* shared_mem_handle
) {
209 uint32 buf_size
= metafile
->GetDataSize();
210 base::SharedMemory shared_buf
;
211 // Allocate a shared memory buffer to hold the generated metafile data.
212 if (!shared_buf
.CreateAndMapAnonymous(buf_size
)) {
213 NOTREACHED() << "Buffer allocation failed";
217 // Copy the bits into shared memory.
218 if (!metafile
->GetData(shared_buf
.memory(), buf_size
)) {
219 NOTREACHED() << "GetData() failed";
223 shared_buf
.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle
);
226 Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle
,
231 } // namespace printing