1 // Copyright (c) 2012 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/ppb_pdf_impl.h"
6
7 #include "base/files/scoped_file.h"
8 #include "base/metrics/histogram.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "build/build_config.h"
11 #include "components/pdf/common/pdf_messages.h"
12 #include "components/pdf/renderer/pdf_resource_util.h"
13 #include "content/public/common/child_process_sandbox_support_linux.h"
14 #include "content/public/common/referrer.h"
15 #include "content/public/renderer/pepper_plugin_instance.h"
16 #include "content/public/renderer/render_thread.h"
17 #include "content/public/renderer/render_view.h"
18 #include "ppapi/c/pp_resource.h"
19 #include "ppapi/c/private/ppb_pdf.h"
20 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
21 #include "ppapi/shared_impl/ppapi_globals.h"
22 #include "ppapi/shared_impl/resource.h"
23 #include "ppapi/shared_impl/resource_tracker.h"
24 #include "ppapi/shared_impl/var.h"
25 #include "third_party/WebKit/public/web/WebDocument.h"
26 #include "third_party/WebKit/public/web/WebElement.h"
27 #include "third_party/WebKit/public/web/WebLocalFrame.h"
28 #include "third_party/WebKit/public/web/WebPluginContainer.h"
29 #include "third_party/WebKit/public/web/WebView.h"
30 #include "third_party/icu/source/i18n/unicode/usearch.h"
31 #include "third_party/skia/include/core/SkBitmap.h"
32
33 namespace pdf {
34 namespace {
35
36 PPB_PDF_Impl::PrintClient* g_print_client = NULL;
37
38 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
39 class PrivateFontFile : public ppapi::Resource {
40 public:
PrivateFontFile(PP_Instance instance,int fd)41 PrivateFontFile(PP_Instance instance, int fd)
42 : Resource(ppapi::OBJECT_IS_IMPL, instance), fd_(fd) {}
43
GetFontTable(uint32_t table,void * output,uint32_t * output_length)44 bool GetFontTable(uint32_t table, void* output, uint32_t* output_length) {
45 size_t temp_size = static_cast<size_t>(*output_length);
46 bool rv = content::GetFontTable(fd_.get(),
47 table,
48 0 /* offset */,
49 static_cast<uint8_t*>(output),
50 &temp_size);
51 *output_length = base::checked_cast<uint32_t>(temp_size);
52 return rv;
53 }
54
55 protected:
~PrivateFontFile()56 virtual ~PrivateFontFile() {}
57
58 private:
59 base::ScopedFD fd_;
60 };
61 #endif
62
GetLocalizedString(PP_Instance instance_id,PP_ResourceString string_id)63 PP_Var GetLocalizedString(PP_Instance instance_id,
64 PP_ResourceString string_id) {
65 content::PepperPluginInstance* instance =
66 content::PepperPluginInstance::Get(instance_id);
67 if (!instance)
68 return PP_MakeUndefined();
69
70 std::string rv = GetStringResource(string_id);
71 return ppapi::StringVar::StringToPPVar(rv);
72 }
73
GetFontFileWithFallback(PP_Instance instance_id,const PP_BrowserFont_Trusted_Description * description,PP_PrivateFontCharset charset)74 PP_Resource GetFontFileWithFallback(
75 PP_Instance instance_id,
76 const PP_BrowserFont_Trusted_Description* description,
77 PP_PrivateFontCharset charset) {
78 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
79 // Validate the instance before using it below.
80 if (!content::PepperPluginInstance::Get(instance_id))
81 return 0;
82
83 scoped_refptr<ppapi::StringVar> face_name(
84 ppapi::StringVar::FromPPVar(description->face));
85 if (!face_name.get())
86 return 0;
87
88 int fd = content::MatchFontWithFallback(
89 face_name->value().c_str(),
90 description->weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD,
91 description->italic,
92 charset,
93 description->family);
94 if (fd == -1)
95 return 0;
96
97 scoped_refptr<PrivateFontFile> font(new PrivateFontFile(instance_id, fd));
98
99 return font->GetReference();
100 #else
101 // For trusted PPAPI plugins, this is only needed in Linux since font loading
102 // on Windows and Mac works through the renderer sandbox.
103 return 0;
104 #endif
105 }
106
GetFontTableForPrivateFontFile(PP_Resource font_file,uint32_t table,void * output,uint32_t * output_length)107 bool GetFontTableForPrivateFontFile(PP_Resource font_file,
108 uint32_t table,
109 void* output,
110 uint32_t* output_length) {
111 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
112 ppapi::Resource* resource =
113 ppapi::PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file);
114 if (!resource)
115 return false;
116
117 PrivateFontFile* font = static_cast<PrivateFontFile*>(resource);
118 return font->GetFontTable(table, output, output_length);
119 #else
120 return false;
121 #endif
122 }
123
SearchString(PP_Instance instance,const unsigned short * input_string,const unsigned short * input_term,bool case_sensitive,PP_PrivateFindResult ** results,int * count)124 void SearchString(PP_Instance instance,
125 const unsigned short* input_string,
126 const unsigned short* input_term,
127 bool case_sensitive,
128 PP_PrivateFindResult** results,
129 int* count) {
130 const base::char16* string =
131 reinterpret_cast<const base::char16*>(input_string);
132 const base::char16* term = reinterpret_cast<const base::char16*>(input_term);
133
134 UErrorCode status = U_ZERO_ERROR;
135 UStringSearch* searcher =
136 usearch_open(term,
137 -1,
138 string,
139 -1,
140 content::RenderThread::Get()->GetLocale().c_str(),
141 0,
142 &status);
143 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
144 status == U_USING_DEFAULT_WARNING);
145 UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
146
147 UCollator* collator = usearch_getCollator(searcher);
148 if (ucol_getStrength(collator) != strength) {
149 ucol_setStrength(collator, strength);
150 usearch_reset(searcher);
151 }
152
153 status = U_ZERO_ERROR;
154 int match_start = usearch_first(searcher, &status);
155 DCHECK(status == U_ZERO_ERROR);
156
157 std::vector<PP_PrivateFindResult> pp_results;
158 while (match_start != USEARCH_DONE) {
159 size_t matched_length = usearch_getMatchedLength(searcher);
160 PP_PrivateFindResult result;
161 result.start_index = match_start;
162 result.length = matched_length;
163 pp_results.push_back(result);
164 match_start = usearch_next(searcher, &status);
165 DCHECK(status == U_ZERO_ERROR);
166 }
167
168 *count = pp_results.size();
169 if (*count) {
170 *results = reinterpret_cast<PP_PrivateFindResult*>(
171 malloc(*count * sizeof(PP_PrivateFindResult)));
172 memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
173 } else {
174 *results = NULL;
175 }
176
177 usearch_close(searcher);
178 }
179
DidStartLoading(PP_Instance instance_id)180 void DidStartLoading(PP_Instance instance_id) {
181 content::PepperPluginInstance* instance =
182 content::PepperPluginInstance::Get(instance_id);
183 if (!instance)
184 return;
185 instance->GetRenderView()->DidStartLoading();
186 }
187
DidStopLoading(PP_Instance instance_id)188 void DidStopLoading(PP_Instance instance_id) {
189 content::PepperPluginInstance* instance =
190 content::PepperPluginInstance::Get(instance_id);
191 if (!instance)
192 return;
193 instance->GetRenderView()->DidStopLoading();
194 }
195
SetContentRestriction(PP_Instance instance_id,int restrictions)196 void SetContentRestriction(PP_Instance instance_id, int restrictions) {
197 content::PepperPluginInstance* instance =
198 content::PepperPluginInstance::Get(instance_id);
199 if (!instance)
200 return;
201 instance->GetRenderView()->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
202 instance->GetRenderView()->GetRoutingID(), restrictions));
203 }
204
HistogramPDFPageCount(PP_Instance instance,int count)205 void HistogramPDFPageCount(PP_Instance instance, int count) {
206 UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
207 }
208
UserMetricsRecordAction(PP_Instance instance,PP_Var action)209 void UserMetricsRecordAction(PP_Instance instance, PP_Var action) {
210 scoped_refptr<ppapi::StringVar> action_str(
211 ppapi::StringVar::FromPPVar(action));
212 if (action_str.get())
213 content::RenderThread::Get()->RecordComputedAction(action_str->value());
214 }
215
HasUnsupportedFeature(PP_Instance instance_id)216 void HasUnsupportedFeature(PP_Instance instance_id) {
217 content::PepperPluginInstance* instance =
218 content::PepperPluginInstance::Get(instance_id);
219 if (!instance)
220 return;
221
222 // Only want to show an info bar if the pdf is the whole tab.
223 if (!instance->IsFullPagePlugin())
224 return;
225
226 blink::WebView* view =
227 instance->GetContainer()->element().document().frame()->view();
228 content::RenderView* render_view = content::RenderView::FromWebView(view);
229 render_view->Send(
230 new PDFHostMsg_PDFHasUnsupportedFeature(render_view->GetRoutingID()));
231 }
232
SaveAs(PP_Instance instance_id)233 void SaveAs(PP_Instance instance_id) {
234 content::PepperPluginInstance* instance =
235 content::PepperPluginInstance::Get(instance_id);
236 if (!instance)
237 return;
238 GURL url = instance->GetPluginURL();
239
240 content::RenderView* render_view = instance->GetRenderView();
241 blink::WebLocalFrame* frame =
242 render_view->GetWebView()->mainFrame()->toWebLocalFrame();
243 content::Referrer referrer(frame->document().url(),
244 frame->document().referrerPolicy());
245 render_view->Send(
246 new PDFHostMsg_PDFSaveURLAs(render_view->GetRoutingID(), url, referrer));
247 }
248
Print(PP_Instance instance)249 void Print(PP_Instance instance) {
250 PPB_PDF_Impl::InvokePrintingForInstance(instance);
251 }
252
IsFeatureEnabled(PP_Instance instance,PP_PDFFeature feature)253 PP_Bool IsFeatureEnabled(PP_Instance instance, PP_PDFFeature feature) {
254 switch (feature) {
255 case PP_PDFFEATURE_HIDPI:
256 return PP_TRUE;
257 case PP_PDFFEATURE_PRINTING:
258 return (g_print_client && g_print_client->IsPrintingEnabled(instance))
259 ? PP_TRUE
260 : PP_FALSE;
261 }
262 return PP_FALSE;
263 }
264
GetResourceImageForScale(PP_Instance instance_id,PP_ResourceImage image_id,float scale)265 PP_Resource GetResourceImageForScale(PP_Instance instance_id,
266 PP_ResourceImage image_id,
267 float scale) {
268 // Validate the instance.
269 content::PepperPluginInstance* instance =
270 content::PepperPluginInstance::Get(instance_id);
271 if (!instance)
272 return 0;
273
274 gfx::ImageSkia* res_image_skia = GetImageResource(image_id);
275
276 if (!res_image_skia)
277 return 0;
278
279 return instance->CreateImage(res_image_skia, scale);
280 }
281
GetResourceImage(PP_Instance instance_id,PP_ResourceImage image_id)282 PP_Resource GetResourceImage(PP_Instance instance_id,
283 PP_ResourceImage image_id) {
284 return GetResourceImageForScale(instance_id, image_id, 1.0f);
285 }
286
ModalPromptForPassword(PP_Instance instance_id,PP_Var message)287 PP_Var ModalPromptForPassword(PP_Instance instance_id, PP_Var message) {
288 content::PepperPluginInstance* instance =
289 content::PepperPluginInstance::Get(instance_id);
290 if (!instance)
291 return PP_MakeUndefined();
292
293 std::string actual_value;
294 scoped_refptr<ppapi::StringVar> message_string(
295 ppapi::StringVar::FromPPVar(message));
296
297 IPC::SyncMessage* msg = new PDFHostMsg_PDFModalPromptForPassword(
298 instance->GetRenderView()->GetRoutingID(),
299 message_string->value(),
300 &actual_value);
301 msg->EnableMessagePumping();
302 instance->GetRenderView()->Send(msg);
303
304 return ppapi::StringVar::StringToPPVar(actual_value);
305 }
306
IsOutOfProcess(PP_Instance instance_id)307 PP_Bool IsOutOfProcess(PP_Instance instance_id) {
308 return PP_FALSE;
309 }
310
SetSelectedText(PP_Instance instance_id,const char * selected_text)311 void SetSelectedText(PP_Instance instance_id, const char* selected_text) {
312 // This function is intended for out of process PDF plugin.
313 }
314
SetLinkUnderCursor(PP_Instance instance_id,const char * url)315 void SetLinkUnderCursor(PP_Instance instance_id, const char* url) {
316 content::PepperPluginInstance* instance =
317 content::PepperPluginInstance::Get(instance_id);
318 if (!instance)
319 return;
320 instance->SetLinkUnderCursor(url);
321 }
322
323 const PPB_PDF ppb_pdf = { //
324 &GetLocalizedString, //
325 &GetResourceImage, //
326 &GetFontFileWithFallback, //
327 &GetFontTableForPrivateFontFile, //
328 &SearchString, //
329 &DidStartLoading, //
330 &DidStopLoading, //
331 &SetContentRestriction, //
332 &HistogramPDFPageCount, //
333 &UserMetricsRecordAction, //
334 &HasUnsupportedFeature, //
335 &SaveAs, //
336 &Print, //
337 &IsFeatureEnabled, //
338 &GetResourceImageForScale, //
339 &ModalPromptForPassword, //
340 &IsOutOfProcess, //
341 &SetSelectedText, //
342 &SetLinkUnderCursor, //
343 };
344
345 } // namespace
346
347 // static
GetInterface()348 const PPB_PDF* PPB_PDF_Impl::GetInterface() {
349 return &ppb_pdf;
350 }
351
352 // static
InvokePrintingForInstance(PP_Instance instance_id)353 bool PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id) {
354 return g_print_client ? g_print_client->Print(instance_id) : false;
355 }
356
SetPrintClient(PPB_PDF_Impl::PrintClient * client)357 void PPB_PDF_Impl::SetPrintClient(PPB_PDF_Impl::PrintClient* client) {
358 CHECK(!g_print_client) << "There should only be a single PrintClient.";
359 g_print_client = client;
360 }
361
362 } // namespace pdf
363