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 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetLinkUnderCursor,
154 OnHostMsgSetLinkUnderCursor)
155 IPC_END_MESSAGE_MAP()
156 return PP_ERROR_FAILED;
159 int32_t PepperPDFHost::OnHostMsgGetLocalizedString(
160 ppapi::host::HostMessageContext* context,
161 PP_ResourceString string_id) {
163 if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD) {
164 rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD));
165 } else if (string_id == PP_RESOURCESTRING_PDFLOADING) {
166 rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING));
167 } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) {
168 rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED));
169 } else if (string_id == PP_RESOURCESTRING_PDFPROGRESSLOADING) {
170 rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PROGRESS_LOADING));
173 return PP_ERROR_FAILED;
176 context->reply_msg = PpapiPluginMsg_PDF_GetLocalizedStringReply(rv);
180 int32_t PepperPDFHost::OnHostMsgDidStartLoading(
181 ppapi::host::HostMessageContext* context) {
182 content::PepperPluginInstance* instance =
183 host_->GetPluginInstance(pp_instance());
185 return PP_ERROR_FAILED;
186 instance->GetRenderView()->DidStartLoading();
190 int32_t PepperPDFHost::OnHostMsgDidStopLoading(
191 ppapi::host::HostMessageContext* context) {
192 content::PepperPluginInstance* instance =
193 host_->GetPluginInstance(pp_instance());
195 return PP_ERROR_FAILED;
196 instance->GetRenderView()->DidStopLoading();
200 int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
201 ppapi::host::HostMessageContext* context, int restrictions) {
202 content::PepperPluginInstance* instance =
203 host_->GetPluginInstance(pp_instance());
205 return PP_ERROR_FAILED;
206 instance->GetRenderView()->Send(
207 new ChromeViewHostMsg_PDFUpdateContentRestrictions(
208 instance->GetRenderView()->GetRoutingID(), restrictions));
212 int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
213 ppapi::host::HostMessageContext* context,
214 const std::string& action) {
216 for (size_t i = 0; i < arraysize(kValidUserMetricsActions); ++i) {
217 if (action == kValidUserMetricsActions[i]) {
224 return PP_ERROR_FAILED;
226 content::RenderThread::Get()->RecordComputedAction(action);
230 int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
231 ppapi::host::HostMessageContext* context) {
232 content::PepperPluginInstance* instance =
233 host_->GetPluginInstance(pp_instance());
235 return PP_ERROR_FAILED;
237 // Only want to show an info bar if the pdf is the whole tab.
238 if (!instance->IsFullPagePlugin())
241 blink::WebView* view =
242 instance->GetContainer()->element().document().frame()->view();
243 content::RenderView* render_view = content::RenderView::FromWebView(view);
244 render_view->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
245 render_view->GetRoutingID()));
249 int32_t PepperPDFHost::OnHostMsgPrint(
250 ppapi::host::HostMessageContext* context) {
251 #if defined(ENABLE_FULL_PRINTING)
252 content::PepperPluginInstance* instance =
253 host_->GetPluginInstance(pp_instance());
255 return PP_ERROR_FAILED;
257 blink::WebElement element = instance->GetContainer()->element();
258 blink::WebView* view = element.document().frame()->view();
259 content::RenderView* render_view = content::RenderView::FromWebView(view);
261 using printing::PrintWebViewHelper;
262 PrintWebViewHelper* print_view_helper = PrintWebViewHelper::Get(render_view);
263 if (print_view_helper) {
264 print_view_helper->PrintNode(element);
268 return PP_ERROR_FAILED;
271 int32_t PepperPDFHost::OnHostMsgSaveAs(
272 ppapi::host::HostMessageContext* context) {
273 content::PepperPluginInstance* instance =
274 host_->GetPluginInstance(pp_instance());
276 return PP_ERROR_FAILED;
277 GURL url = instance->GetPluginURL();
278 content::RenderView* render_view = instance->GetRenderView();
279 blink::WebFrame* frame = render_view->GetWebView()->mainFrame();
280 content::Referrer referrer(frame->document().url(),
281 frame->document().referrerPolicy());
282 render_view->Send(new ChromeViewHostMsg_PDFSaveURLAs(
283 render_view->GetRoutingID(), url, referrer));
287 int32_t PepperPDFHost::OnHostMsgGetResourceImage(
288 ppapi::host::HostMessageContext* context,
289 PP_ResourceImage image_id,
292 for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) {
293 if (kResourceImageMap[i].pp_id == image_id) {
294 res_id = kResourceImageMap[i].res_id;
299 return PP_ERROR_FAILED;
301 gfx::ImageSkia* res_image_skia =
302 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id);
305 return PP_ERROR_FAILED;
307 gfx::ImageSkiaRep image_skia_rep = res_image_skia->GetRepresentation(scale);
309 if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
310 return PP_ERROR_FAILED;
313 pp_size.width = image_skia_rep.pixel_width();
314 pp_size.height = image_skia_rep.pixel_height();
316 ppapi::HostResource host_resource;
317 PP_ImageDataDesc image_data_desc;
318 IPC::PlatformFileForTransit image_handle;
319 uint32_t byte_count = 0;
320 bool success = CreateImageData(
322 ppapi::PPB_ImageData_Shared::GetNativeImageDataFormat(),
324 image_skia_rep.sk_bitmap(),
329 ppapi::ScopedPPResource image_data_resource(
330 ppapi::ScopedPPResource::PassRef(), host_resource.host_resource());
332 return PP_ERROR_FAILED;
334 ppapi::host::ReplyMessageContext reply_context =
335 context->MakeReplyMessageContext();
336 ppapi::proxy::SerializedHandle serialized_handle;
337 serialized_handle.set_shmem(image_handle, byte_count);
338 reply_context.params.AppendHandle(serialized_handle);
339 SendReply(reply_context,
340 PpapiPluginMsg_PDF_GetResourceImageReply(host_resource,
343 // Keep a reference to the resource only if the function succeeds.
344 image_data_resource.Release();
346 return PP_OK_COMPLETIONPENDING;
349 int32_t PepperPDFHost::OnHostMsgSetSelectedText(
350 ppapi::host::HostMessageContext* context,
351 const base::string16& selected_text) {
352 content::PepperPluginInstance* instance =
353 host_->GetPluginInstance(pp_instance());
355 return PP_ERROR_FAILED;
356 instance->SetSelectedText(selected_text);
360 int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
361 ppapi::host::HostMessageContext* context,
362 const std::string& url) {
363 content::PepperPluginInstance* instance =
364 host_->GetPluginInstance(pp_instance());
366 return PP_ERROR_FAILED;
367 instance->SetLinkUnderCursor(url);
371 // TODO(raymes): This function is mainly copied from ppb_image_data_proxy.cc.
372 // It's a mess and needs to be fixed in several ways but this is better done
373 // when we refactor PPB_ImageData. On success, the image handle will be
375 bool PepperPDFHost::CreateImageData(
376 PP_Instance instance,
377 PP_ImageDataFormat format,
379 const SkBitmap& pixels_to_write,
380 ppapi::HostResource* result,
381 PP_ImageDataDesc* out_image_data_desc,
382 IPC::PlatformFileForTransit* out_image_handle,
383 uint32_t* out_byte_count) {
384 PP_Resource resource = ppapi::proxy::PPB_ImageData_Proxy::CreateImageData(
386 ppapi::PPB_ImageData_Shared::SIMPLE,
388 false /* init_to_zero */,
389 out_image_data_desc, out_image_handle, out_byte_count);
393 result->SetHostResource(instance, resource);
395 // Write the image to the resource shared memory.
396 ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API>
397 enter_resource(resource, false);
398 if (enter_resource.failed())
401 ppapi::thunk::PPB_ImageData_API* image_data =
402 static_cast<ppapi::thunk::PPB_ImageData_API*>(enter_resource.object());
403 SkCanvas* canvas = image_data->GetCanvas();
404 bool needs_unmapping = false;
406 needs_unmapping = true;
408 canvas = image_data->GetCanvas();
410 return false; // Failure mapping.
413 const SkBitmap* bitmap = &skia::GetTopDevice(*canvas)->accessBitmap(false);
414 pixels_to_write.copyPixelsTo(bitmap->getPixels(),