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