1 // Copyright (c) 2013 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/pepper/pepper_pdf_host.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/common/render_messages.h"
9 #include "chrome/renderer/printing/print_web_view_helper.h"
10 #include "content/public/common/referrer.h"
11 #include "content/public/renderer/pepper_plugin_instance.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "content/public/renderer/render_view.h"
14 #include "content/public/renderer/renderer_ppapi_host.h"
15 #include "grit/webkit_resources.h"
16 #include "grit/webkit_strings.h"
17 #include "ppapi/host/dispatch_host_message.h"
18 #include "ppapi/host/host_message_context.h"
19 #include "ppapi/host/ppapi_host.h"
20 #include "ppapi/proxy/host_dispatcher.h"
21 #include "ppapi/proxy/ppapi_messages.h"
22 #include "ppapi/proxy/ppb_image_data_proxy.h"
23 #include "ppapi/shared_impl/ppb_image_data_shared.h"
24 #include "ppapi/shared_impl/scoped_pp_resource.h"
25 #include "ppapi/thunk/enter.h"
26 #include "ppapi/thunk/ppb_image_data_api.h"
27 #include "skia/ext/platform_canvas.h"
28 #include "third_party/WebKit/public/web/WebDocument.h"
29 #include "third_party/WebKit/public/web/WebElement.h"
30 #include "third_party/WebKit/public/web/WebFrame.h"
31 #include "third_party/WebKit/public/web/WebPluginContainer.h"
32 #include "third_party/WebKit/public/web/WebView.h"
33 #include "third_party/skia/include/core/SkBitmap.h"
34 #include "ui/base/l10n/l10n_util.h"
35 #include "ui/base/layout.h"
36 #include "ui/base/resource/resource_bundle.h"
37 #include "ui/gfx/image/image_skia.h"
38 #include "ui/gfx/image/image_skia_rep.h"
39 #include "ui/gfx/point.h"
43 struct ResourceImageInfo
{
44 PP_ResourceImage pp_id
;
48 static const ResourceImageInfo kResourceImageMap
[] = {
49 { PP_RESOURCEIMAGE_PDF_BUTTON_FTP
, IDR_PDF_BUTTON_FTP
},
50 { PP_RESOURCEIMAGE_PDF_BUTTON_FTP_HOVER
, IDR_PDF_BUTTON_FTP_HOVER
},
51 { PP_RESOURCEIMAGE_PDF_BUTTON_FTP_PRESSED
, IDR_PDF_BUTTON_FTP_PRESSED
},
52 { PP_RESOURCEIMAGE_PDF_BUTTON_FTW
, IDR_PDF_BUTTON_FTW
},
53 { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER
, IDR_PDF_BUTTON_FTW_HOVER
},
54 { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED
, IDR_PDF_BUTTON_FTW_PRESSED
},
55 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END
, IDR_PDF_BUTTON_ZOOMIN_END
},
56 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_HOVER
,
57 IDR_PDF_BUTTON_ZOOMIN_END_HOVER
},
58 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_PRESSED
,
59 IDR_PDF_BUTTON_ZOOMIN_END_PRESSED
},
60 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN
, IDR_PDF_BUTTON_ZOOMIN
},
61 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER
, IDR_PDF_BUTTON_ZOOMIN_HOVER
},
62 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED
, IDR_PDF_BUTTON_ZOOMIN_PRESSED
},
63 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT
, IDR_PDF_BUTTON_ZOOMOUT
},
64 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER
, IDR_PDF_BUTTON_ZOOMOUT_HOVER
},
65 { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED
,
66 IDR_PDF_BUTTON_ZOOMOUT_PRESSED
},
67 { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE
, IDR_PDF_BUTTON_SAVE
},
68 { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_HOVER
, IDR_PDF_BUTTON_SAVE_HOVER
},
69 { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_PRESSED
, IDR_PDF_BUTTON_SAVE_PRESSED
},
70 { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT
, IDR_PDF_BUTTON_PRINT
},
71 { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_HOVER
, IDR_PDF_BUTTON_PRINT_HOVER
},
72 { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_PRESSED
, IDR_PDF_BUTTON_PRINT_PRESSED
},
73 { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_DISABLED
, IDR_PDF_BUTTON_PRINT_DISABLED
},
74 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0
, IDR_PDF_THUMBNAIL_0
},
75 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1
, IDR_PDF_THUMBNAIL_1
},
76 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2
, IDR_PDF_THUMBNAIL_2
},
77 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3
, IDR_PDF_THUMBNAIL_3
},
78 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4
, IDR_PDF_THUMBNAIL_4
},
79 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5
, IDR_PDF_THUMBNAIL_5
},
80 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6
, IDR_PDF_THUMBNAIL_6
},
81 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7
, IDR_PDF_THUMBNAIL_7
},
82 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8
, IDR_PDF_THUMBNAIL_8
},
83 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9
, IDR_PDF_THUMBNAIL_9
},
84 { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND
,
85 IDR_PDF_THUMBNAIL_NUM_BACKGROUND
},
86 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_0
, IDR_PDF_PROGRESS_BAR_0
},
87 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_1
, IDR_PDF_PROGRESS_BAR_1
},
88 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_2
, IDR_PDF_PROGRESS_BAR_2
},
89 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_3
, IDR_PDF_PROGRESS_BAR_3
},
90 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_4
, IDR_PDF_PROGRESS_BAR_4
},
91 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_5
, IDR_PDF_PROGRESS_BAR_5
},
92 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_6
, IDR_PDF_PROGRESS_BAR_6
},
93 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_7
, IDR_PDF_PROGRESS_BAR_7
},
94 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_8
, IDR_PDF_PROGRESS_BAR_8
},
95 { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_BACKGROUND
,
96 IDR_PDF_PROGRESS_BAR_BACKGROUND
},
97 { PP_RESOURCEIMAGE_PDF_PAGE_INDICATOR_BACKGROUND
,
98 IDR_PDF_PAGE_INDICATOR_BACKGROUND
},
99 { PP_RESOURCEIMAGE_PDF_PAGE_DROPSHADOW
, IDR_PDF_PAGE_DROPSHADOW
},
100 { PP_RESOURCEIMAGE_PDF_PAN_SCROLL_ICON
, IDR_PAN_SCROLL_ICON
},
103 // Valid strings for user metrics actions.
104 static const char* kValidUserMetricsActions
[] = {
106 "PDF.ZoomFromBrowser",
107 "PDF.FitToPageButton",
108 "PDF.FitToWidthButton",
115 "PDF.PreviewDocumentLoadFailure",
120 PepperPDFHost::PepperPDFHost(
121 content::RendererPpapiHost
* host
,
122 PP_Instance instance
,
123 PP_Resource resource
)
124 : ppapi::host::ResourceHost(host
->GetPpapiHost(), instance
, resource
),
128 PepperPDFHost::~PepperPDFHost() {
131 int32_t PepperPDFHost::OnResourceMessageReceived(
132 const IPC::Message
& msg
,
133 ppapi::host::HostMessageContext
* context
) {
134 IPC_BEGIN_MESSAGE_MAP(PepperPDFHost
, msg
)
135 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetLocalizedString
,
136 OnHostMsgGetLocalizedString
)
137 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStartLoading
,
138 OnHostMsgDidStartLoading
)
139 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStopLoading
,
140 OnHostMsgDidStopLoading
)
141 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_UserMetricsRecordAction
,
142 OnHostMsgUserMetricsRecordAction
)
143 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_HasUnsupportedFeature
,
144 OnHostMsgHasUnsupportedFeature
)
145 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_Print
,
147 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs
,
149 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetResourceImage
,
150 OnHostMsgGetResourceImage
)
151 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetSelectedText
,
152 OnHostMsgSetSelectedText
)
153 IPC_END_MESSAGE_MAP()
154 return PP_ERROR_FAILED
;
157 int32_t PepperPDFHost::OnHostMsgGetLocalizedString(
158 ppapi::host::HostMessageContext
* context
,
159 PP_ResourceString string_id
) {
161 if (string_id
== PP_RESOURCESTRING_PDFGETPASSWORD
) {
162 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD
));
163 } else if (string_id
== PP_RESOURCESTRING_PDFLOADING
) {
164 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING
));
165 } else if (string_id
== PP_RESOURCESTRING_PDFLOAD_FAILED
) {
166 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED
));
167 } else if (string_id
== PP_RESOURCESTRING_PDFPROGRESSLOADING
) {
168 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PROGRESS_LOADING
));
171 return PP_ERROR_FAILED
;
174 context
->reply_msg
= PpapiPluginMsg_PDF_GetLocalizedStringReply(rv
);
178 int32_t PepperPDFHost::OnHostMsgDidStartLoading(
179 ppapi::host::HostMessageContext
* context
) {
180 content::PepperPluginInstance
* instance
=
181 host_
->GetPluginInstance(pp_instance());
183 return PP_ERROR_FAILED
;
184 instance
->GetRenderView()->DidStartLoading();
188 int32_t PepperPDFHost::OnHostMsgDidStopLoading(
189 ppapi::host::HostMessageContext
* context
) {
190 content::PepperPluginInstance
* instance
=
191 host_
->GetPluginInstance(pp_instance());
193 return PP_ERROR_FAILED
;
194 instance
->GetRenderView()->DidStopLoading();
198 int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
199 ppapi::host::HostMessageContext
* context
, int restrictions
) {
200 content::PepperPluginInstance
* instance
=
201 host_
->GetPluginInstance(pp_instance());
203 return PP_ERROR_FAILED
;
204 instance
->GetRenderView()->Send(
205 new ChromeViewHostMsg_PDFUpdateContentRestrictions(
206 instance
->GetRenderView()->GetRoutingID(), restrictions
));
210 int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
211 ppapi::host::HostMessageContext
* context
,
212 const std::string
& action
) {
214 for (size_t i
= 0; i
< arraysize(kValidUserMetricsActions
); ++i
) {
215 if (action
== kValidUserMetricsActions
[i
]) {
222 return PP_ERROR_FAILED
;
224 content::RenderThread::Get()->RecordComputedAction(action
);
228 int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
229 ppapi::host::HostMessageContext
* context
) {
230 content::PepperPluginInstance
* instance
=
231 host_
->GetPluginInstance(pp_instance());
233 return PP_ERROR_FAILED
;
235 // Only want to show an info bar if the pdf is the whole tab.
236 if (!instance
->IsFullPagePlugin())
239 blink::WebView
* view
=
240 instance
->GetContainer()->element().document().frame()->view();
241 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
242 render_view
->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
243 render_view
->GetRoutingID()));
247 int32_t PepperPDFHost::OnHostMsgPrint(
248 ppapi::host::HostMessageContext
* context
) {
249 #if defined(ENABLE_FULL_PRINTING)
250 content::PepperPluginInstance
* instance
=
251 host_
->GetPluginInstance(pp_instance());
253 return PP_ERROR_FAILED
;
255 blink::WebElement element
= instance
->GetContainer()->element();
256 blink::WebView
* view
= element
.document().frame()->view();
257 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
259 using printing::PrintWebViewHelper
;
260 PrintWebViewHelper
* print_view_helper
= PrintWebViewHelper::Get(render_view
);
261 if (print_view_helper
) {
262 print_view_helper
->PrintNode(element
);
266 return PP_ERROR_FAILED
;
269 int32_t PepperPDFHost::OnHostMsgSaveAs(
270 ppapi::host::HostMessageContext
* context
) {
271 content::PepperPluginInstance
* instance
=
272 host_
->GetPluginInstance(pp_instance());
274 return PP_ERROR_FAILED
;
275 GURL url
= instance
->GetPluginURL();
276 content::RenderView
* render_view
= instance
->GetRenderView();
277 blink::WebFrame
* frame
= render_view
->GetWebView()->mainFrame();
278 content::Referrer
referrer(frame
->document().url(),
279 frame
->document().referrerPolicy());
280 render_view
->Send(new ChromeViewHostMsg_PDFSaveURLAs(
281 render_view
->GetRoutingID(), url
, referrer
));
285 int32_t PepperPDFHost::OnHostMsgGetResourceImage(
286 ppapi::host::HostMessageContext
* context
,
287 PP_ResourceImage image_id
,
290 for (size_t i
= 0; i
< arraysize(kResourceImageMap
); ++i
) {
291 if (kResourceImageMap
[i
].pp_id
== image_id
) {
292 res_id
= kResourceImageMap
[i
].res_id
;
297 return PP_ERROR_FAILED
;
299 gfx::ImageSkia
* res_image_skia
=
300 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id
);
303 return PP_ERROR_FAILED
;
305 gfx::ImageSkiaRep image_skia_rep
= res_image_skia
->GetRepresentation(scale
);
307 if (image_skia_rep
.is_null() || image_skia_rep
.scale() != scale
)
308 return PP_ERROR_FAILED
;
311 pp_size
.width
= image_skia_rep
.pixel_width();
312 pp_size
.height
= image_skia_rep
.pixel_height();
314 ppapi::HostResource host_resource
;
315 PP_ImageDataDesc image_data_desc
;
316 IPC::PlatformFileForTransit image_handle
;
317 uint32_t byte_count
= 0;
318 bool success
= CreateImageData(
320 ppapi::PPB_ImageData_Shared::GetNativeImageDataFormat(),
322 image_skia_rep
.sk_bitmap(),
327 ppapi::ScopedPPResource
image_data_resource(
328 ppapi::ScopedPPResource::PassRef(), host_resource
.host_resource());
330 return PP_ERROR_FAILED
;
332 ppapi::host::ReplyMessageContext reply_context
=
333 context
->MakeReplyMessageContext();
334 ppapi::proxy::SerializedHandle serialized_handle
;
335 serialized_handle
.set_shmem(image_handle
, byte_count
);
336 reply_context
.params
.AppendHandle(serialized_handle
);
337 SendReply(reply_context
,
338 PpapiPluginMsg_PDF_GetResourceImageReply(host_resource
,
341 // Keep a reference to the resource only if the function succeeds.
342 image_data_resource
.Release();
344 return PP_OK_COMPLETIONPENDING
;
347 int32_t PepperPDFHost::OnHostMsgSetSelectedText(
348 ppapi::host::HostMessageContext
* context
,
349 const base::string16
& selected_text
) {
350 content::PepperPluginInstance
* instance
=
351 host_
->GetPluginInstance(pp_instance());
353 return PP_ERROR_FAILED
;
354 instance
->SetSelectedText(selected_text
);
358 // TODO(raymes): This function is mainly copied from ppb_image_data_proxy.cc.
359 // It's a mess and needs to be fixed in several ways but this is better done
360 // when we refactor PPB_ImageData. On success, the image handle will be
362 bool PepperPDFHost::CreateImageData(
363 PP_Instance instance
,
364 PP_ImageDataFormat format
,
366 const SkBitmap
& pixels_to_write
,
367 ppapi::HostResource
* result
,
368 PP_ImageDataDesc
* out_image_data_desc
,
369 IPC::PlatformFileForTransit
* out_image_handle
,
370 uint32_t* out_byte_count
) {
371 PP_Resource resource
= ppapi::proxy::PPB_ImageData_Proxy::CreateImageData(
373 ppapi::PPB_ImageData_Shared::SIMPLE
,
375 false /* init_to_zero */,
376 out_image_data_desc
, out_image_handle
, out_byte_count
);
380 result
->SetHostResource(instance
, resource
);
382 // Write the image to the resource shared memory.
383 ppapi::thunk::EnterResourceNoLock
<ppapi::thunk::PPB_ImageData_API
>
384 enter_resource(resource
, false);
385 if (enter_resource
.failed())
388 ppapi::thunk::PPB_ImageData_API
* image_data
=
389 static_cast<ppapi::thunk::PPB_ImageData_API
*>(enter_resource
.object());
390 SkCanvas
* canvas
= image_data
->GetCanvas();
391 bool needs_unmapping
= false;
393 needs_unmapping
= true;
395 canvas
= image_data
->GetCanvas();
397 return false; // Failure mapping.
400 const SkBitmap
* bitmap
= &skia::GetTopDevice(*canvas
)->accessBitmap(false);
401 pixels_to_write
.copyPixelsTo(bitmap
->getPixels(),