Home | History | Annotate | Download | only in renderer
      1 // Copyright 2014 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 "components/pdf/renderer/pepper_pdf_host.h"
      6 
      7 #include "components/pdf/common/pdf_messages.h"
      8 #include "components/pdf/renderer/pdf_resource_util.h"
      9 #include "components/pdf/renderer/ppb_pdf_impl.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 "ppapi/host/dispatch_host_message.h"
     16 #include "ppapi/host/host_message_context.h"
     17 #include "ppapi/host/ppapi_host.h"
     18 #include "ppapi/proxy/host_dispatcher.h"
     19 #include "ppapi/proxy/ppapi_messages.h"
     20 #include "ppapi/proxy/ppb_image_data_proxy.h"
     21 #include "ppapi/shared_impl/ppb_image_data_shared.h"
     22 #include "ppapi/shared_impl/scoped_pp_resource.h"
     23 #include "ppapi/thunk/enter.h"
     24 #include "ppapi/thunk/ppb_image_data_api.h"
     25 #include "skia/ext/platform_canvas.h"
     26 #include "third_party/WebKit/public/web/WebDocument.h"
     27 #include "third_party/WebKit/public/web/WebElement.h"
     28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     29 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     30 #include "third_party/WebKit/public/web/WebView.h"
     31 #include "third_party/skia/include/core/SkBitmap.h"
     32 #include "ui/base/layout.h"
     33 #include "ui/gfx/image/image_skia.h"
     34 #include "ui/gfx/image/image_skia_rep.h"
     35 #include "ui/gfx/point.h"
     36 
     37 namespace pdf {
     38 
     39 PepperPDFHost::PepperPDFHost(content::RendererPpapiHost* host,
     40                              PP_Instance instance,
     41                              PP_Resource resource)
     42     : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
     43       host_(host) {}
     44 
     45 PepperPDFHost::~PepperPDFHost() {}
     46 
     47 int32_t PepperPDFHost::OnResourceMessageReceived(
     48     const IPC::Message& msg,
     49     ppapi::host::HostMessageContext* context) {
     50   PPAPI_BEGIN_MESSAGE_MAP(PepperPDFHost, msg)
     51     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetLocalizedString,
     52                                       OnHostMsgGetLocalizedString)
     53     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStartLoading,
     54                                         OnHostMsgDidStartLoading)
     55     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_DidStopLoading,
     56                                         OnHostMsgDidStopLoading)
     57     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_UserMetricsRecordAction,
     58                                       OnHostMsgUserMetricsRecordAction)
     59     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_HasUnsupportedFeature,
     60                                         OnHostMsgHasUnsupportedFeature)
     61     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_Print, OnHostMsgPrint)
     62     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_PDF_SaveAs,
     63                                         OnHostMsgSaveAs)
     64     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_GetResourceImage,
     65                                       OnHostMsgGetResourceImage)
     66     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetSelectedText,
     67                                       OnHostMsgSetSelectedText)
     68     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_PDF_SetLinkUnderCursor,
     69                                       OnHostMsgSetLinkUnderCursor)
     70   PPAPI_END_MESSAGE_MAP()
     71   return PP_ERROR_FAILED;
     72 }
     73 
     74 int32_t PepperPDFHost::OnHostMsgGetLocalizedString(
     75     ppapi::host::HostMessageContext* context,
     76     PP_ResourceString string_id) {
     77   std::string rv = GetStringResource(string_id);
     78   context->reply_msg = PpapiPluginMsg_PDF_GetLocalizedStringReply(rv);
     79   return PP_OK;
     80 }
     81 
     82 int32_t PepperPDFHost::OnHostMsgDidStartLoading(
     83     ppapi::host::HostMessageContext* context) {
     84   content::PepperPluginInstance* instance =
     85       host_->GetPluginInstance(pp_instance());
     86   if (!instance)
     87     return PP_ERROR_FAILED;
     88   instance->GetRenderView()->DidStartLoading();
     89   return PP_OK;
     90 }
     91 
     92 int32_t PepperPDFHost::OnHostMsgDidStopLoading(
     93     ppapi::host::HostMessageContext* context) {
     94   content::PepperPluginInstance* instance =
     95       host_->GetPluginInstance(pp_instance());
     96   if (!instance)
     97     return PP_ERROR_FAILED;
     98   instance->GetRenderView()->DidStopLoading();
     99   return PP_OK;
    100 }
    101 
    102 int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
    103     ppapi::host::HostMessageContext* context,
    104     int restrictions) {
    105   content::PepperPluginInstance* instance =
    106       host_->GetPluginInstance(pp_instance());
    107   if (!instance)
    108     return PP_ERROR_FAILED;
    109   instance->GetRenderView()->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
    110       instance->GetRenderView()->GetRoutingID(), restrictions));
    111   return PP_OK;
    112 }
    113 
    114 int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
    115     ppapi::host::HostMessageContext* context,
    116     const std::string& action) {
    117   if (action.empty())
    118     return PP_ERROR_FAILED;
    119   content::RenderThread::Get()->RecordComputedAction(action);
    120   return PP_OK;
    121 }
    122 
    123 int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
    124     ppapi::host::HostMessageContext* context) {
    125   content::PepperPluginInstance* instance =
    126       host_->GetPluginInstance(pp_instance());
    127   if (!instance)
    128     return PP_ERROR_FAILED;
    129 
    130   blink::WebView* view =
    131       instance->GetContainer()->element().document().frame()->view();
    132   content::RenderView* render_view = content::RenderView::FromWebView(view);
    133   render_view->Send(
    134       new PDFHostMsg_PDFHasUnsupportedFeature(render_view->GetRoutingID()));
    135   return PP_OK;
    136 }
    137 
    138 int32_t PepperPDFHost::OnHostMsgPrint(
    139     ppapi::host::HostMessageContext* context) {
    140   return PPB_PDF_Impl::InvokePrintingForInstance(pp_instance()) ? PP_OK :
    141       PP_ERROR_FAILED;
    142 }
    143 
    144 int32_t PepperPDFHost::OnHostMsgSaveAs(
    145     ppapi::host::HostMessageContext* context) {
    146   content::PepperPluginInstance* instance =
    147       host_->GetPluginInstance(pp_instance());
    148   if (!instance)
    149     return PP_ERROR_FAILED;
    150   GURL url = instance->GetPluginURL();
    151   content::RenderView* render_view = instance->GetRenderView();
    152   blink::WebLocalFrame* frame =
    153       render_view->GetWebView()->mainFrame()->toWebLocalFrame();
    154   content::Referrer referrer(frame->document().url(),
    155                              frame->document().referrerPolicy());
    156   render_view->Send(
    157       new PDFHostMsg_PDFSaveURLAs(render_view->GetRoutingID(), url, referrer));
    158   return PP_OK;
    159 }
    160 
    161 int32_t PepperPDFHost::OnHostMsgGetResourceImage(
    162     ppapi::host::HostMessageContext* context,
    163     PP_ResourceImage image_id,
    164     float scale) {
    165   gfx::ImageSkia* res_image_skia = GetImageResource(image_id);
    166 
    167   if (!res_image_skia)
    168     return PP_ERROR_FAILED;
    169 
    170   gfx::ImageSkiaRep image_skia_rep = res_image_skia->GetRepresentation(scale);
    171 
    172   if (image_skia_rep.is_null() || image_skia_rep.scale() != scale)
    173     return PP_ERROR_FAILED;
    174 
    175   PP_Size pp_size;
    176   pp_size.width = image_skia_rep.pixel_width();
    177   pp_size.height = image_skia_rep.pixel_height();
    178 
    179   ppapi::HostResource host_resource;
    180   PP_ImageDataDesc image_data_desc;
    181   IPC::PlatformFileForTransit image_handle;
    182   uint32_t byte_count = 0;
    183   bool success =
    184       CreateImageData(pp_instance(),
    185                       ppapi::PPB_ImageData_Shared::GetNativeImageDataFormat(),
    186                       pp_size,
    187                       image_skia_rep.sk_bitmap(),
    188                       &host_resource,
    189                       &image_data_desc,
    190                       &image_handle,
    191                       &byte_count);
    192   ppapi::ScopedPPResource image_data_resource(
    193       ppapi::ScopedPPResource::PassRef(), host_resource.host_resource());
    194   if (!success)
    195     return PP_ERROR_FAILED;
    196 
    197   ppapi::host::ReplyMessageContext reply_context =
    198       context->MakeReplyMessageContext();
    199   ppapi::proxy::SerializedHandle serialized_handle;
    200   serialized_handle.set_shmem(image_handle, byte_count);
    201   reply_context.params.AppendHandle(serialized_handle);
    202   SendReply(
    203       reply_context,
    204       PpapiPluginMsg_PDF_GetResourceImageReply(host_resource, image_data_desc));
    205 
    206   // Keep a reference to the resource only if the function succeeds.
    207   image_data_resource.Release();
    208 
    209   return PP_OK_COMPLETIONPENDING;
    210 }
    211 
    212 int32_t PepperPDFHost::OnHostMsgSetSelectedText(
    213     ppapi::host::HostMessageContext* context,
    214     const base::string16& selected_text) {
    215   content::PepperPluginInstance* instance =
    216       host_->GetPluginInstance(pp_instance());
    217   if (!instance)
    218     return PP_ERROR_FAILED;
    219   instance->SetSelectedText(selected_text);
    220   return PP_OK;
    221 }
    222 
    223 int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
    224     ppapi::host::HostMessageContext* context,
    225     const std::string& url) {
    226   content::PepperPluginInstance* instance =
    227       host_->GetPluginInstance(pp_instance());
    228   if (!instance)
    229     return PP_ERROR_FAILED;
    230   instance->SetLinkUnderCursor(url);
    231   return PP_OK;
    232 }
    233 
    234 // TODO(raymes): This function is mainly copied from ppb_image_data_proxy.cc.
    235 // It's a mess and needs to be fixed in several ways but this is better done
    236 // when we refactor PPB_ImageData. On success, the image handle will be
    237 // non-null.
    238 bool PepperPDFHost::CreateImageData(
    239     PP_Instance instance,
    240     PP_ImageDataFormat format,
    241     const PP_Size& size,
    242     const SkBitmap& pixels_to_write,
    243     ppapi::HostResource* result,
    244     PP_ImageDataDesc* out_image_data_desc,
    245     IPC::PlatformFileForTransit* out_image_handle,
    246     uint32_t* out_byte_count) {
    247   PP_Resource resource = ppapi::proxy::PPB_ImageData_Proxy::CreateImageData(
    248       instance,
    249       ppapi::PPB_ImageData_Shared::SIMPLE,
    250       format,
    251       size,
    252       false /* init_to_zero */,
    253       out_image_data_desc,
    254       out_image_handle,
    255       out_byte_count);
    256   if (!resource)
    257     return false;
    258 
    259   result->SetHostResource(instance, resource);
    260 
    261   // Write the image to the resource shared memory.
    262   ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API>
    263       enter_resource(resource, false);
    264   if (enter_resource.failed())
    265     return false;
    266 
    267   ppapi::thunk::PPB_ImageData_API* image_data =
    268       static_cast<ppapi::thunk::PPB_ImageData_API*>(enter_resource.object());
    269   SkCanvas* canvas = image_data->GetCanvas();
    270   bool needs_unmapping = false;
    271   if (!canvas) {
    272     needs_unmapping = true;
    273     image_data->Map();
    274     canvas = image_data->GetCanvas();
    275     if (!canvas)
    276       return false;  // Failure mapping.
    277   }
    278 
    279   const SkBitmap* bitmap = &skia::GetTopDevice(*canvas)->accessBitmap(false);
    280   pixels_to_write.copyPixelsTo(
    281       bitmap->getPixels(), bitmap->getSize(), bitmap->rowBytes());
    282 
    283   if (needs_unmapping)
    284     image_data->Unmap();
    285 
    286   return true;
    287 }
    288 
    289 }  // namespace pdf
    290