Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / pepper / pepper_pdf_host.cc
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.
4
5 #include "chrome/renderer/pepper/pepper_pdf_host.h"
6
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"
40
41 namespace {
42
43 struct ResourceImageInfo {
44   PP_ResourceImage pp_id;
45   int res_id;
46 };
47
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 },
101 };
102
103 // Valid strings for user metrics actions.
104 static const char* kValidUserMetricsActions[] = {
105   "PDF.PrintPage",
106   "PDF.ZoomFromBrowser",
107   "PDF.FitToPageButton",
108   "PDF.FitToWidthButton",
109   "PDF.ZoomOutButton",
110   "PDF.ZoomInButton",
111   "PDF.SaveButton",
112   "PDF.PrintButton",
113   "PDF.LoadSuccess",
114   "PDF.LoadFailure",
115   "PDF.PreviewDocumentLoadFailure",
116 };
117
118 }  // namespace
119
120 PepperPDFHost::PepperPDFHost(
121     content::RendererPpapiHost* host,
122     PP_Instance instance,
123     PP_Resource resource)
124     : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
125       host_(host) {
126 }
127
128 PepperPDFHost::~PepperPDFHost() {
129 }
130
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,
146                                         OnHostMsgPrint)
147     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs,
148                                         OnHostMsgSaveAs)
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;
157 }
158
159 int32_t PepperPDFHost::OnHostMsgGetLocalizedString(
160     ppapi::host::HostMessageContext* context,
161     PP_ResourceString string_id) {
162   std::string rv;
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));
171   } else {
172     NOTREACHED();
173     return PP_ERROR_FAILED;
174   }
175
176   context->reply_msg = PpapiPluginMsg_PDF_GetLocalizedStringReply(rv);
177   return PP_OK;
178 }
179
180 int32_t PepperPDFHost::OnHostMsgDidStartLoading(
181     ppapi::host::HostMessageContext* context) {
182   content::PepperPluginInstance* instance =
183       host_->GetPluginInstance(pp_instance());
184   if (!instance)
185     return PP_ERROR_FAILED;
186   instance->GetRenderView()->DidStartLoading();
187   return PP_OK;
188 }
189
190 int32_t PepperPDFHost::OnHostMsgDidStopLoading(
191     ppapi::host::HostMessageContext* context) {
192   content::PepperPluginInstance* instance =
193       host_->GetPluginInstance(pp_instance());
194   if (!instance)
195     return PP_ERROR_FAILED;
196   instance->GetRenderView()->DidStopLoading();
197   return PP_OK;
198 }
199
200 int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
201     ppapi::host::HostMessageContext* context, int restrictions) {
202   content::PepperPluginInstance* instance =
203       host_->GetPluginInstance(pp_instance());
204   if (!instance)
205     return PP_ERROR_FAILED;
206   instance->GetRenderView()->Send(
207       new ChromeViewHostMsg_PDFUpdateContentRestrictions(
208           instance->GetRenderView()->GetRoutingID(), restrictions));
209   return PP_OK;
210 }
211
212 int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
213     ppapi::host::HostMessageContext* context,
214     const std::string& action) {
215   bool valid = false;
216   for (size_t i = 0; i < arraysize(kValidUserMetricsActions); ++i) {
217     if (action == kValidUserMetricsActions[i]) {
218       valid = true;
219       break;
220     }
221   }
222   if (!valid) {
223     NOTREACHED();
224     return PP_ERROR_FAILED;
225   }
226   content::RenderThread::Get()->RecordComputedAction(action);
227   return PP_OK;
228 }
229
230 int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
231     ppapi::host::HostMessageContext* context) {
232   content::PepperPluginInstance* instance =
233       host_->GetPluginInstance(pp_instance());
234   if (!instance)
235     return PP_ERROR_FAILED;
236
237   // Only want to show an info bar if the pdf is the whole tab.
238   if (!instance->IsFullPagePlugin())
239     return PP_OK;
240
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()));
246   return PP_OK;
247 }
248
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());
254   if (!instance)
255     return PP_ERROR_FAILED;
256
257   blink::WebElement element = instance->GetContainer()->element();
258   blink::WebView* view = element.document().frame()->view();
259   content::RenderView* render_view = content::RenderView::FromWebView(view);
260
261   using printing::PrintWebViewHelper;
262   PrintWebViewHelper* print_view_helper = PrintWebViewHelper::Get(render_view);
263   if (print_view_helper) {
264     print_view_helper->PrintNode(element);
265     return PP_OK;
266   }
267 #endif
268   return PP_ERROR_FAILED;
269 }
270
271 int32_t PepperPDFHost::OnHostMsgSaveAs(
272     ppapi::host::HostMessageContext* context) {
273   content::PepperPluginInstance* instance =
274       host_->GetPluginInstance(pp_instance());
275   if (!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));
284   return PP_OK;
285 }
286
287 int32_t PepperPDFHost::OnHostMsgGetResourceImage(
288     ppapi::host::HostMessageContext* context,
289     PP_ResourceImage image_id,
290     float scale) {
291   int res_id = 0;
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;
295       break;
296     }
297   }
298   if (res_id == 0)
299     return PP_ERROR_FAILED;
300
301   gfx::ImageSkia* res_image_skia =
302       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id);
303
304   if (!res_image_skia)
305     return PP_ERROR_FAILED;
306
307   gfx::ImageSkiaRep image_skia_rep = res_image_skia->GetRepresentation(scale);
308
309   if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
310     return PP_ERROR_FAILED;
311
312   PP_Size pp_size;
313   pp_size.width = image_skia_rep.pixel_width();
314   pp_size.height = image_skia_rep.pixel_height();
315
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(
321       pp_instance(),
322       ppapi::PPB_ImageData_Shared::GetNativeImageDataFormat(),
323       pp_size,
324       image_skia_rep.sk_bitmap(),
325       &host_resource,
326       &image_data_desc,
327       &image_handle,
328       &byte_count);
329   ppapi::ScopedPPResource image_data_resource(
330       ppapi::ScopedPPResource::PassRef(), host_resource.host_resource());
331   if (!success)
332     return PP_ERROR_FAILED;
333
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,
341                                                      image_data_desc));
342
343   // Keep a reference to the resource only if the function succeeds.
344   image_data_resource.Release();
345
346   return PP_OK_COMPLETIONPENDING;
347 }
348
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());
354   if (!instance)
355     return PP_ERROR_FAILED;
356   instance->SetSelectedText(selected_text);
357   return PP_OK;
358 }
359
360 int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
361     ppapi::host::HostMessageContext* context,
362     const std::string& url) {
363   content::PepperPluginInstance* instance =
364       host_->GetPluginInstance(pp_instance());
365   if (!instance)
366     return PP_ERROR_FAILED;
367   instance->SetLinkUnderCursor(url);
368   return PP_OK;
369 }
370
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
374 // non-null.
375 bool PepperPDFHost::CreateImageData(
376     PP_Instance instance,
377     PP_ImageDataFormat format,
378     const PP_Size& size,
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(
385       instance,
386       ppapi::PPB_ImageData_Shared::SIMPLE,
387       format, size,
388       false /* init_to_zero */,
389       out_image_data_desc, out_image_handle, out_byte_count);
390   if (!resource)
391     return false;
392
393   result->SetHostResource(instance, resource);
394
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())
399     return false;
400
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;
405   if (!canvas) {
406     needs_unmapping = true;
407     image_data->Map();
408     canvas = image_data->GetCanvas();
409     if (!canvas)
410       return false;  // Failure mapping.
411   }
412
413   const SkBitmap* bitmap = &skia::GetTopDevice(*canvas)->accessBitmap(false);
414   pixels_to_write.copyPixelsTo(bitmap->getPixels(),
415                                bitmap->getSize(),
416                                bitmap->rowBytes());
417
418   if (needs_unmapping)
419     image_data->Unmap();
420
421   return true;
422 }