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