1 // Copyright (c) 2011 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 "chrome/renderer/print_web_view_helper.h"
7 #include "base/file_descriptor_posix.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h"
11 #include "chrome/common/print_messages.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "printing/metafile.h"
14 #include "printing/metafile_impl.h"
15 #include "printing/metafile_skia_wrapper.h"
16 #include "printing/page_size_margins.h"
17 #include "skia/ext/platform_device.h"
18 #include "skia/ext/vector_canvas.h"
19 #include "third_party/skia/include/core/SkRefCnt.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
22 #if !defined(OS_CHROMEOS)
23 #include "base/process_util.h"
24 #endif // !defined(OS_CHROMEOS)
26 using WebKit::WebFrame
;
27 using WebKit::WebNode
;
29 bool PrintWebViewHelper::RenderPreviewPage(int page_number
) {
30 PrintMsg_PrintPage_Params page_params
;
31 page_params
.params
= print_preview_context_
.print_params();
32 page_params
.page_number
= page_number
;
33 scoped_ptr
<printing::Metafile
> draft_metafile
;
34 printing::Metafile
* initial_render_metafile
=
35 print_preview_context_
.metafile();
36 if (print_preview_context_
.IsModifiable() && is_print_ready_metafile_sent_
) {
37 draft_metafile
.reset(new printing::PreviewMetafile
);
38 initial_render_metafile
= draft_metafile
.get();
41 base::TimeTicks begin_time
= base::TimeTicks::Now();
42 PrintPageInternal(page_params
,
43 print_preview_context_
.GetPrintCanvasSize(),
44 print_preview_context_
.frame(), initial_render_metafile
);
45 print_preview_context_
.RenderedPreviewPage(
46 base::TimeTicks::Now() - begin_time
);
47 if (draft_metafile
.get()) {
48 draft_metafile
->FinishDocument();
49 } else if (print_preview_context_
.IsModifiable() &&
50 print_preview_context_
.generate_draft_pages()){
51 DCHECK(!draft_metafile
.get());
53 print_preview_context_
.metafile()->GetMetafileForCurrentPage());
55 return PreviewPageRendered(page_number
, draft_metafile
.get());
58 bool PrintWebViewHelper::PrintPages(const PrintMsg_PrintPages_Params
& params
,
60 const WebNode
& node
) {
61 printing::NativeMetafile metafile
;
65 PrepareFrameAndViewForPrint
prep_frame_view(params
.params
, frame
, node
);
67 if (!RenderPages(params
, frame
, node
, &page_count
, &prep_frame_view
,
72 // Get the size of the resulting metafile.
73 uint32 buf_size
= metafile
.GetDataSize();
74 DCHECK_GT(buf_size
, 0u);
76 #if defined(OS_CHROMEOS)
77 int sequence_number
= -1;
78 base::FileDescriptor fd
;
80 // Ask the browser to open a file for us.
81 Send(new PrintHostMsg_AllocateTempFileForPrinting(&fd
, &sequence_number
));
82 if (!metafile
.SaveToFD(fd
))
85 // Tell the browser we've finished writing the file.
86 Send(new PrintHostMsg_TempFileForPrintingWritten(sequence_number
));
89 PrintHostMsg_DidPrintPage_Params printed_page_params
;
90 printed_page_params
.data_size
= 0;
91 printed_page_params
.document_cookie
= params
.params
.document_cookie
;
93 base::SharedMemoryHandle shared_mem_handle
=
94 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(buf_size
);
95 if (!base::SharedMemory::IsHandleValid(shared_mem_handle
)) {
96 NOTREACHED() << "AllocateSharedMemoryBuffer returned bad handle";
101 base::SharedMemory
shared_buf(shared_mem_handle
, false);
102 if (!shared_buf
.Map(buf_size
)) {
103 NOTREACHED() << "Map failed";
106 metafile
.GetData(shared_buf
.memory(), buf_size
);
107 printed_page_params
.data_size
= buf_size
;
108 shared_buf
.GiveToProcess(base::GetCurrentProcessHandle(),
109 &(printed_page_params
.metafile_data_handle
));
112 if (params
.pages
.empty()) {
113 // Send the first page with a valid handle.
114 printed_page_params
.page_number
= 0;
115 Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params
));
117 // Send the rest of the pages with an invalid metafile handle.
118 printed_page_params
.metafile_data_handle
.fd
= -1;
119 for (int i
= 1; i
< page_count
; ++i
) {
120 printed_page_params
.page_number
= i
;
121 Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params
));
124 // Send the first page with a valid handle.
125 printed_page_params
.page_number
= params
.pages
[0];
126 Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params
));
128 // Send the rest of the pages with an invalid metafile handle.
129 printed_page_params
.metafile_data_handle
.fd
= -1;
130 for (size_t i
= 1; i
< params
.pages
.size(); ++i
) {
131 printed_page_params
.page_number
= params
.pages
[i
];
132 Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params
));
136 #endif // defined(OS_CHROMEOS)
139 bool PrintWebViewHelper::RenderPages(const PrintMsg_PrintPages_Params
& params
,
140 WebKit::WebFrame
* frame
,
141 const WebKit::WebNode
& node
,
143 PrepareFrameAndViewForPrint
* prepare
,
144 printing::Metafile
* metafile
) {
145 PrintMsg_Print_Params print_params
= params
.params
;
146 UpdatePrintableSizeInPrintParameters(frame
, node
, prepare
, &print_params
);
148 *page_count
= prepare
->GetExpectedPageCount();
152 #if !defined(OS_CHROMEOS)
153 Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
154 print_params
.document_cookie
,
158 PrintMsg_PrintPage_Params page_params
;
159 page_params
.params
= print_params
;
160 const gfx::Size
& canvas_size
= prepare
->GetPrintCanvasSize();
161 if (params
.pages
.empty()) {
162 for (int i
= 0; i
< *page_count
; ++i
) {
163 page_params
.page_number
= i
;
164 PrintPageInternal(page_params
, canvas_size
, frame
, metafile
);
167 for (size_t i
= 0; i
< params
.pages
.size(); ++i
) {
168 page_params
.page_number
= params
.pages
[i
];
169 PrintPageInternal(page_params
, canvas_size
, frame
, metafile
);
173 prepare
->FinishPrinting();
174 metafile
->FinishDocument();
178 void PrintWebViewHelper::PrintPageInternal(
179 const PrintMsg_PrintPage_Params
& params
,
180 const gfx::Size
& canvas_size
,
182 printing::Metafile
* metafile
) {
183 printing::PageSizeMargins page_layout_in_points
;
184 GetPageSizeAndMarginsInPoints(frame
, params
.page_number
, params
.params
,
185 &page_layout_in_points
);
188 page_layout_in_points
.content_width
+
189 page_layout_in_points
.margin_right
+
190 page_layout_in_points
.margin_left
,
191 page_layout_in_points
.content_height
+
192 page_layout_in_points
.margin_top
+
193 page_layout_in_points
.margin_bottom
);
194 gfx::Rect
content_area(page_layout_in_points
.margin_left
,
195 page_layout_in_points
.margin_top
,
196 page_layout_in_points
.content_width
,
197 page_layout_in_points
.content_height
);
199 SkDevice
* device
= metafile
->StartPageForVectorCanvas(
200 page_size
, content_area
, 1.0f
);
204 // The printPage method take a reference to the canvas we pass down, so it
205 // can't be a stack object.
206 SkRefPtr
<skia::VectorCanvas
> canvas
= new skia::VectorCanvas(device
);
207 canvas
->unref(); // SkRefPtr and new both took a reference.
208 printing::MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas
, metafile
);
209 skia::SetIsDraftMode(*canvas
, is_print_ready_metafile_sent_
);
210 frame
->printPage(params
.page_number
, canvas
.get());
212 if (params
.params
.display_header_footer
) {
213 // |page_number| is 0-based, so 1 is added.
214 // The scale factor on Linux is 1.
215 PrintHeaderAndFooter(canvas
.get(), params
.page_number
+ 1,
216 print_preview_context_
.total_page_count(), 1,
217 page_layout_in_points
, *header_footer_info_
);
220 // Done printing. Close the device context to retrieve the compiled metafile.
221 if (!metafile
->FinishPage())
222 NOTREACHED() << "metafile failed";