Home | History | Annotate | Download | only in pepper
      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/WebLocalFrame.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 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 }  // namespace
    103 
    104 PepperPDFHost::PepperPDFHost(content::RendererPpapiHost* host,
    105                              PP_Instance instance,
    106                              PP_Resource resource)
    107     : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
    108       host_(host) {}
    109 
    110 PepperPDFHost::~PepperPDFHost() {}
    111 
    112 int32_t PepperPDFHost::OnResourceMessageReceived(
    113     const IPC::Message& msg,
    114     ppapi::host::HostMessageContext* context) {
    115   PPAPI_BEGIN_MESSAGE_MAP(PepperPDFHost, msg)
    116     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetLocalizedString,
    117                                       OnHostMsgGetLocalizedString)
    118     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStartLoading,
    119                                         OnHostMsgDidStartLoading)
    120     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStopLoading,
    121                                         OnHostMsgDidStopLoading)
    122     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_UserMetricsRecordAction,
    123                                       OnHostMsgUserMetricsRecordAction)
    124     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_HasUnsupportedFeature,
    125                                         OnHostMsgHasUnsupportedFeature)
    126     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_Print, OnHostMsgPrint)
    127     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs,
    128                                         OnHostMsgSaveAs)
    129     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetResourceImage,
    130                                       OnHostMsgGetResourceImage)
    131     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetSelectedText,
    132                                       OnHostMsgSetSelectedText)
    133     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetLinkUnderCursor,
    134                                       OnHostMsgSetLinkUnderCursor)
    135   PPAPI_END_MESSAGE_MAP()
    136   return PP_ERROR_FAILED;
    137 }
    138 
    139 int32_t PepperPDFHost::OnHostMsgGetLocalizedString(
    140     ppapi::host::HostMessageContext* context,
    141     PP_ResourceString string_id) {
    142   std::string rv;
    143   if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD) {
    144     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD));
    145   } else if (string_id == PP_RESOURCESTRING_PDFLOADING) {
    146     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING));
    147   } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) {
    148     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED));
    149   } else if (string_id == PP_RESOURCESTRING_PDFPROGRESSLOADING) {
    150     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PROGRESS_LOADING));
    151   } else {
    152     NOTREACHED();
    153     return PP_ERROR_FAILED;
    154   }
    155 
    156   context->reply_msg = PpapiPluginMsg_PDF_GetLocalizedStringReply(rv);
    157   return PP_OK;
    158 }
    159 
    160 int32_t PepperPDFHost::OnHostMsgDidStartLoading(
    161     ppapi::host::HostMessageContext* context) {
    162   content::PepperPluginInstance* instance =
    163       host_->GetPluginInstance(pp_instance());
    164   if (!instance)
    165     return PP_ERROR_FAILED;
    166   instance->GetRenderView()->DidStartLoading();
    167   return PP_OK;
    168 }
    169 
    170 int32_t PepperPDFHost::OnHostMsgDidStopLoading(
    171     ppapi::host::HostMessageContext* context) {
    172   content::PepperPluginInstance* instance =
    173       host_->GetPluginInstance(pp_instance());
    174   if (!instance)
    175     return PP_ERROR_FAILED;
    176   instance->GetRenderView()->DidStopLoading();
    177   return PP_OK;
    178 }
    179 
    180 int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
    181     ppapi::host::HostMessageContext* context,
    182     int restrictions) {
    183   content::PepperPluginInstance* instance =
    184       host_->GetPluginInstance(pp_instance());
    185   if (!instance)
    186     return PP_ERROR_FAILED;
    187   instance->GetRenderView()->Send(
    188       new ChromeViewHostMsg_PDFUpdateContentRestrictions(
    189           instance->GetRenderView()->GetRoutingID(), restrictions));
    190   return PP_OK;
    191 }
    192 
    193 int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
    194     ppapi::host::HostMessageContext* context,
    195     const std::string& action) {
    196   if (action.empty())
    197     return PP_ERROR_FAILED;
    198   content::RenderThread::Get()->RecordComputedAction(action);
    199   return PP_OK;
    200 }
    201 
    202 int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
    203     ppapi::host::HostMessageContext* context) {
    204   content::PepperPluginInstance* instance =
    205       host_->GetPluginInstance(pp_instance());
    206   if (!instance)
    207     return PP_ERROR_FAILED;
    208 
    209   blink::WebView* view =
    210       instance->GetContainer()->element().document().frame()->view();
    211   content::RenderView* render_view = content::RenderView::FromWebView(view);
    212   render_view->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
    213       render_view->GetRoutingID()));
    214   return PP_OK;
    215 }
    216 
    217 int32_t PepperPDFHost::OnHostMsgPrint(
    218     ppapi::host::HostMessageContext* context) {
    219 #if defined(ENABLE_FULL_PRINTING)
    220   content::PepperPluginInstance* instance =
    221       host_->GetPluginInstance(pp_instance());
    222   if (!instance)
    223     return PP_ERROR_FAILED;
    224 
    225   blink::WebElement element = instance->GetContainer()->element();
    226   blink::WebView* view = element.document().frame()->view();
    227   content::RenderView* render_view = content::RenderView::FromWebView(view);
    228 
    229   using printing::PrintWebViewHelper;
    230   PrintWebViewHelper* print_view_helper = PrintWebViewHelper::Get(render_view);
    231   if (print_view_helper) {
    232     print_view_helper->PrintNode(element);
    233     return PP_OK;
    234   }
    235 #endif
    236   return PP_ERROR_FAILED;
    237 }
    238 
    239 int32_t PepperPDFHost::OnHostMsgSaveAs(
    240     ppapi::host::HostMessageContext* context) {
    241   content::PepperPluginInstance* instance =
    242       host_->GetPluginInstance(pp_instance());
    243   if (!instance)
    244     return PP_ERROR_FAILED;
    245   GURL url = instance->GetPluginURL();
    246   content::RenderView* render_view = instance->GetRenderView();
    247   blink::WebLocalFrame* frame =
    248       render_view->GetWebView()->mainFrame()->toWebLocalFrame();
    249   content::Referrer referrer(frame->document().url(),
    250                              frame->document().referrerPolicy());
    251   render_view->Send(new ChromeViewHostMsg_PDFSaveURLAs(
    252       render_view->GetRoutingID(), url, referrer));
    253   return PP_OK;
    254 }
    255 
    256 int32_t PepperPDFHost::OnHostMsgGetResourceImage(
    257     ppapi::host::HostMessageContext* context,
    258     PP_ResourceImage image_id,
    259     float scale) {
    260   int res_id = 0;
    261   for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) {
    262     if (kResourceImageMap[i].pp_id == image_id) {
    263       res_id = kResourceImageMap[i].res_id;
    264       break;
    265     }
    266   }
    267   if (res_id == 0)
    268     return PP_ERROR_FAILED;
    269 
    270   gfx::ImageSkia* res_image_skia =
    271       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id);
    272 
    273   if (!res_image_skia)
    274     return PP_ERROR_FAILED;
    275 
    276   gfx::ImageSkiaRep image_skia_rep = res_image_skia->GetRepresentation(scale);
    277 
    278   if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
    279     return PP_ERROR_FAILED;
    280 
    281   PP_Size pp_size;
    282   pp_size.width = image_skia_rep.pixel_width();
    283   pp_size.height = image_skia_rep.pixel_height();
    284 
    285   ppapi::HostResource host_resource;
    286   PP_ImageDataDesc image_data_desc;
    287   IPC::PlatformFileForTransit image_handle;
    288   uint32_t byte_count = 0;
    289   bool success =
    290       CreateImageData(pp_instance(),
    291                       ppapi::PPB_ImageData_Shared::GetNativeImageDataFormat(),
    292                       pp_size,
    293                       image_skia_rep.sk_bitmap(),
    294                       &host_resource,
    295                       &image_data_desc,
    296                       &image_handle,
    297                       &byte_count);
    298   ppapi::ScopedPPResource image_data_resource(
    299       ppapi::ScopedPPResource::PassRef(), host_resource.host_resource());
    300   if (!success)
    301     return PP_ERROR_FAILED;
    302 
    303   ppapi::host::ReplyMessageContext reply_context =
    304       context->MakeReplyMessageContext();
    305   ppapi::proxy::SerializedHandle serialized_handle;
    306   serialized_handle.set_shmem(image_handle, byte_count);
    307   reply_context.params.AppendHandle(serialized_handle);
    308   SendReply(
    309       reply_context,
    310       PpapiPluginMsg_PDF_GetResourceImageReply(host_resource, image_data_desc));
    311 
    312   // Keep a reference to the resource only if the function succeeds.
    313   image_data_resource.Release();
    314 
    315   return PP_OK_COMPLETIONPENDING;
    316 }
    317 
    318 int32_t PepperPDFHost::OnHostMsgSetSelectedText(
    319     ppapi::host::HostMessageContext* context,
    320     const base::string16& selected_text) {
    321   content::PepperPluginInstance* instance =
    322       host_->GetPluginInstance(pp_instance());
    323   if (!instance)
    324     return PP_ERROR_FAILED;
    325   instance->SetSelectedText(selected_text);
    326   return PP_OK;
    327 }
    328 
    329 int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
    330     ppapi::host::HostMessageContext* context,
    331     const std::string& url) {
    332   content::PepperPluginInstance* instance =
    333       host_->GetPluginInstance(pp_instance());
    334   if (!instance)
    335     return PP_ERROR_FAILED;
    336   instance->SetLinkUnderCursor(url);
    337   return PP_OK;
    338 }
    339 
    340 // TODO(raymes): This function is mainly copied from ppb_image_data_proxy.cc.
    341 // It's a mess and needs to be fixed in several ways but this is better done
    342 // when we refactor PPB_ImageData. On success, the image handle will be
    343 // non-null.
    344 bool PepperPDFHost::CreateImageData(
    345     PP_Instance instance,
    346     PP_ImageDataFormat format,
    347     const PP_Size& size,
    348     const SkBitmap& pixels_to_write,
    349     ppapi::HostResource* result,
    350     PP_ImageDataDesc* out_image_data_desc,
    351     IPC::PlatformFileForTransit* out_image_handle,
    352     uint32_t* out_byte_count) {
    353   PP_Resource resource = ppapi::proxy::PPB_ImageData_Proxy::CreateImageData(
    354       instance,
    355       ppapi::PPB_ImageData_Shared::SIMPLE,
    356       format,
    357       size,
    358       false /* init_to_zero */,
    359       out_image_data_desc,
    360       out_image_handle,
    361       out_byte_count);
    362   if (!resource)
    363     return false;
    364 
    365   result->SetHostResource(instance, resource);
    366 
    367   // Write the image to the resource shared memory.
    368   ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API>
    369       enter_resource(resource, false);
    370   if (enter_resource.failed())
    371     return false;
    372 
    373   ppapi::thunk::PPB_ImageData_API* image_data =
    374       static_cast<ppapi::thunk::PPB_ImageData_API*>(enter_resource.object());
    375   SkCanvas* canvas = image_data->GetCanvas();
    376   bool needs_unmapping = false;
    377   if (!canvas) {
    378     needs_unmapping = true;
    379     image_data->Map();
    380     canvas = image_data->GetCanvas();
    381     if (!canvas)
    382       return false;  // Failure mapping.
    383   }
    384 
    385   const SkBitmap* bitmap = &skia::GetTopDevice(*canvas)->accessBitmap(false);
    386   pixels_to_write.copyPixelsTo(
    387       bitmap->getPixels(), bitmap->getSize(), bitmap->rowBytes());
    388 
    389   if (needs_unmapping)
    390     image_data->Unmap();
    391 
    392   return true;
    393 }
    394