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
PepperPDFHost(content::RendererPpapiHost * host,PP_Instance instance,PP_Resource resource)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
~PepperPDFHost()45 PepperPDFHost::~PepperPDFHost() {}
46
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)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
OnHostMsgGetLocalizedString(ppapi::host::HostMessageContext * context,PP_ResourceString string_id)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
OnHostMsgDidStartLoading(ppapi::host::HostMessageContext * context)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
OnHostMsgDidStopLoading(ppapi::host::HostMessageContext * context)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
OnHostMsgSetContentRestriction(ppapi::host::HostMessageContext * context,int restrictions)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
OnHostMsgUserMetricsRecordAction(ppapi::host::HostMessageContext * context,const std::string & action)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
OnHostMsgHasUnsupportedFeature(ppapi::host::HostMessageContext * context)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
OnHostMsgPrint(ppapi::host::HostMessageContext * context)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
OnHostMsgSaveAs(ppapi::host::HostMessageContext * context)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
OnHostMsgGetResourceImage(ppapi::host::HostMessageContext * context,PP_ResourceImage image_id,float scale)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
OnHostMsgSetSelectedText(ppapi::host::HostMessageContext * context,const base::string16 & selected_text)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
OnHostMsgSetLinkUnderCursor(ppapi::host::HostMessageContext * context,const std::string & url)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.
CreateImageData(PP_Instance instance,PP_ImageDataFormat format,const PP_Size & size,const SkBitmap & pixels_to_write,ppapi::HostResource * result,PP_ImageDataDesc * out_image_data_desc,IPC::PlatformFileForTransit * out_image_handle,uint32_t * out_byte_count)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