Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / pepper / ppb_pdf_impl.cc
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 "chrome/renderer/pepper/ppb_pdf_impl.h"
6
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "build/build_config.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/render_messages.h"
14 #include "chrome/renderer/printing/print_web_view_helper.h"
15 #include "content/public/common/child_process_sandbox_support_linux.h"
16 #include "content/public/common/referrer.h"
17 #include "content/public/renderer/pepper_plugin_instance.h"
18 #include "content/public/renderer/render_thread.h"
19 #include "content/public/renderer/render_view.h"
20 #include "grit/webkit_resources.h"
21 #include "grit/webkit_strings.h"
22 #include "ppapi/c/pp_resource.h"
23 #include "ppapi/c/private/ppb_pdf.h"
24 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
25 #include "ppapi/shared_impl/ppapi_globals.h"
26 #include "ppapi/shared_impl/resource.h"
27 #include "ppapi/shared_impl/resource_tracker.h"
28 #include "ppapi/shared_impl/var.h"
29 #include "third_party/WebKit/public/web/WebDocument.h"
30 #include "third_party/WebKit/public/web/WebElement.h"
31 #include "third_party/WebKit/public/web/WebFrame.h"
32 #include "third_party/WebKit/public/web/WebPluginContainer.h"
33 #include "third_party/WebKit/public/web/WebView.h"
34 #include "third_party/icu/source/i18n/unicode/usearch.h"
35 #include "third_party/skia/include/core/SkBitmap.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/layout.h"
38 #include "ui/base/resource/resource_bundle.h"
39
40 using ppapi::PpapiGlobals;
41 using blink::WebElement;
42 using blink::WebView;
43 using content::RenderThread;
44
45 namespace {
46
47 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
48 class PrivateFontFile : public ppapi::Resource {
49  public:
50   PrivateFontFile(PP_Instance instance, int fd)
51       : Resource(ppapi::OBJECT_IS_IMPL, instance),
52         fd_(fd) {
53   }
54
55   bool GetFontTable(uint32_t table,
56                     void* output,
57                     uint32_t* output_length) {
58     size_t temp_size = static_cast<size_t>(*output_length);
59     bool rv = content::GetFontTable(
60         fd_, table, 0 /* offset */, static_cast<uint8_t*>(output), &temp_size);
61     *output_length = base::checked_cast<uint32_t>(temp_size);
62     return rv;
63   }
64
65  protected:
66   virtual ~PrivateFontFile() {}
67
68  private:
69   int fd_;
70 };
71 #endif
72
73 struct ResourceImageInfo {
74   PP_ResourceImage pp_id;
75   int res_id;
76 };
77
78 static const ResourceImageInfo kResourceImageMap[] = {
79   { PP_RESOURCEIMAGE_PDF_BUTTON_FTP, IDR_PDF_BUTTON_FTP },
80   { PP_RESOURCEIMAGE_PDF_BUTTON_FTP_HOVER, IDR_PDF_BUTTON_FTP_HOVER },
81   { PP_RESOURCEIMAGE_PDF_BUTTON_FTP_PRESSED, IDR_PDF_BUTTON_FTP_PRESSED },
82   { PP_RESOURCEIMAGE_PDF_BUTTON_FTW, IDR_PDF_BUTTON_FTW },
83   { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER, IDR_PDF_BUTTON_FTW_HOVER },
84   { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED, IDR_PDF_BUTTON_FTW_PRESSED },
85   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END, IDR_PDF_BUTTON_ZOOMIN_END },
86   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_HOVER,
87       IDR_PDF_BUTTON_ZOOMIN_END_HOVER },
88   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_PRESSED,
89       IDR_PDF_BUTTON_ZOOMIN_END_PRESSED },
90   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN, IDR_PDF_BUTTON_ZOOMIN },
91   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER, IDR_PDF_BUTTON_ZOOMIN_HOVER },
92   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED, IDR_PDF_BUTTON_ZOOMIN_PRESSED },
93   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT, IDR_PDF_BUTTON_ZOOMOUT },
94   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER, IDR_PDF_BUTTON_ZOOMOUT_HOVER },
95   { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED,
96       IDR_PDF_BUTTON_ZOOMOUT_PRESSED },
97   { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE, IDR_PDF_BUTTON_SAVE },
98   { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_HOVER, IDR_PDF_BUTTON_SAVE_HOVER },
99   { PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_PRESSED, IDR_PDF_BUTTON_SAVE_PRESSED },
100   { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT, IDR_PDF_BUTTON_PRINT },
101   { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_HOVER, IDR_PDF_BUTTON_PRINT_HOVER },
102   { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_PRESSED, IDR_PDF_BUTTON_PRINT_PRESSED },
103   { PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_DISABLED, IDR_PDF_BUTTON_PRINT_DISABLED },
104   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0, IDR_PDF_THUMBNAIL_0 },
105   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1, IDR_PDF_THUMBNAIL_1 },
106   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2, IDR_PDF_THUMBNAIL_2 },
107   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3, IDR_PDF_THUMBNAIL_3 },
108   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4, IDR_PDF_THUMBNAIL_4 },
109   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5, IDR_PDF_THUMBNAIL_5 },
110   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6, IDR_PDF_THUMBNAIL_6 },
111   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7, IDR_PDF_THUMBNAIL_7 },
112   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8, IDR_PDF_THUMBNAIL_8 },
113   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9, IDR_PDF_THUMBNAIL_9 },
114   { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND,
115       IDR_PDF_THUMBNAIL_NUM_BACKGROUND },
116   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_0, IDR_PDF_PROGRESS_BAR_0 },
117   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_1, IDR_PDF_PROGRESS_BAR_1 },
118   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_2, IDR_PDF_PROGRESS_BAR_2 },
119   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_3, IDR_PDF_PROGRESS_BAR_3 },
120   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_4, IDR_PDF_PROGRESS_BAR_4 },
121   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_5, IDR_PDF_PROGRESS_BAR_5 },
122   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_6, IDR_PDF_PROGRESS_BAR_6 },
123   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_7, IDR_PDF_PROGRESS_BAR_7 },
124   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_8, IDR_PDF_PROGRESS_BAR_8 },
125   { PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_BACKGROUND,
126       IDR_PDF_PROGRESS_BAR_BACKGROUND },
127   { PP_RESOURCEIMAGE_PDF_PAGE_INDICATOR_BACKGROUND,
128       IDR_PDF_PAGE_INDICATOR_BACKGROUND },
129   { PP_RESOURCEIMAGE_PDF_PAGE_DROPSHADOW, IDR_PDF_PAGE_DROPSHADOW },
130   { PP_RESOURCEIMAGE_PDF_PAN_SCROLL_ICON, IDR_PAN_SCROLL_ICON },
131 };
132
133 #if defined(ENABLE_FULL_PRINTING)
134
135 blink::WebElement GetWebElement(PP_Instance instance_id) {
136   content::PepperPluginInstance* instance =
137       content::PepperPluginInstance::Get(instance_id);
138   if (!instance)
139     return blink::WebElement();
140   return instance->GetContainer()->element();
141 }
142
143 printing::PrintWebViewHelper* GetPrintWebViewHelper(
144     const blink::WebElement& element) {
145   if (element.isNull())
146     return NULL;
147   blink::WebView* view = element.document().frame()->view();
148   content::RenderView* render_view = content::RenderView::FromWebView(view);
149   return printing::PrintWebViewHelper::Get(render_view);
150 }
151
152 bool IsPrintingEnabled(PP_Instance instance_id) {
153   blink::WebElement element = GetWebElement(instance_id);
154   printing::PrintWebViewHelper* helper = GetPrintWebViewHelper(element);
155   return helper && helper->IsPrintingEnabled();
156 }
157
158 #else  // ENABLE_FULL_PRINTING
159
160 bool IsPrintingEnabled(PP_Instance instance_id) {
161   return false;
162 }
163
164 #endif  // ENABLE_FULL_PRINTING
165
166
167
168 PP_Var GetLocalizedString(PP_Instance instance_id,
169                           PP_ResourceString string_id) {
170   content::PepperPluginInstance* instance =
171       content::PepperPluginInstance::Get(instance_id);
172   if (!instance)
173     return PP_MakeUndefined();
174
175   std::string rv;
176   if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD) {
177     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD));
178   } else if (string_id == PP_RESOURCESTRING_PDFLOADING) {
179     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING));
180   } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) {
181     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED));
182   } else if (string_id == PP_RESOURCESTRING_PDFPROGRESSLOADING) {
183     rv = base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PROGRESS_LOADING));
184   } else {
185     NOTREACHED();
186   }
187
188   return ppapi::StringVar::StringToPPVar(rv);
189 }
190
191 PP_Resource GetFontFileWithFallback(
192     PP_Instance instance_id,
193     const PP_BrowserFont_Trusted_Description* description,
194     PP_PrivateFontCharset charset) {
195 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
196   // Validate the instance before using it below.
197   if (!content::PepperPluginInstance::Get(instance_id))
198     return 0;
199
200   scoped_refptr<ppapi::StringVar> face_name(ppapi::StringVar::FromPPVar(
201       description->face));
202   if (!face_name.get())
203     return 0;
204
205   int fd = content::MatchFontWithFallback(
206       face_name->value().c_str(),
207       description->weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD,
208       description->italic,
209       charset);
210   if (fd == -1)
211     return 0;
212
213   scoped_refptr<PrivateFontFile> font(new PrivateFontFile(instance_id, fd));
214
215   return font->GetReference();
216 #else
217   // For trusted PPAPI plugins, this is only needed in Linux since font loading
218   // on Windows and Mac works through the renderer sandbox.
219   return 0;
220 #endif
221 }
222
223 bool GetFontTableForPrivateFontFile(PP_Resource font_file,
224                                     uint32_t table,
225                                     void* output,
226                                     uint32_t* output_length) {
227 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
228   ppapi::Resource* resource =
229       PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file);
230   if (!resource)
231     return false;
232
233   PrivateFontFile* font = static_cast<PrivateFontFile*>(resource);
234   return font->GetFontTable(table, output, output_length);
235 #else
236   return false;
237 #endif
238 }
239
240 void SearchString(PP_Instance instance,
241                   const unsigned short* input_string,
242                   const unsigned short* input_term,
243                   bool case_sensitive,
244                   PP_PrivateFindResult** results,
245                   int* count) {
246   const base::char16* string =
247       reinterpret_cast<const base::char16*>(input_string);
248   const base::char16* term =
249       reinterpret_cast<const base::char16*>(input_term);
250
251   UErrorCode status = U_ZERO_ERROR;
252   UStringSearch* searcher = usearch_open(
253       term, -1, string, -1, RenderThread::Get()->GetLocale().c_str(), 0,
254       &status);
255   DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
256          status == U_USING_DEFAULT_WARNING);
257   UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
258
259   UCollator* collator = usearch_getCollator(searcher);
260   if (ucol_getStrength(collator) != strength) {
261     ucol_setStrength(collator, strength);
262     usearch_reset(searcher);
263   }
264
265   status = U_ZERO_ERROR;
266   int match_start = usearch_first(searcher, &status);
267   DCHECK(status == U_ZERO_ERROR);
268
269   std::vector<PP_PrivateFindResult> pp_results;
270   while (match_start != USEARCH_DONE) {
271     size_t matched_length = usearch_getMatchedLength(searcher);
272     PP_PrivateFindResult result;
273     result.start_index = match_start;
274     result.length = matched_length;
275     pp_results.push_back(result);
276     match_start = usearch_next(searcher, &status);
277     DCHECK(status == U_ZERO_ERROR);
278   }
279
280   *count = pp_results.size();
281   if (*count) {
282     *results = reinterpret_cast<PP_PrivateFindResult*>(
283         malloc(*count * sizeof(PP_PrivateFindResult)));
284     memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
285   } else {
286     *results = NULL;
287   }
288
289   usearch_close(searcher);
290 }
291
292 void DidStartLoading(PP_Instance instance_id) {
293   content::PepperPluginInstance* instance =
294       content::PepperPluginInstance::Get(instance_id);
295   if (!instance)
296     return;
297   instance->GetRenderView()->DidStartLoading();
298 }
299
300 void DidStopLoading(PP_Instance instance_id) {
301   content::PepperPluginInstance* instance =
302       content::PepperPluginInstance::Get(instance_id);
303   if (!instance)
304     return;
305   instance->GetRenderView()->DidStopLoading();
306 }
307
308 void SetContentRestriction(PP_Instance instance_id, int restrictions) {
309   content::PepperPluginInstance* instance =
310       content::PepperPluginInstance::Get(instance_id);
311   if (!instance)
312     return;
313   instance->GetRenderView()->Send(
314       new ChromeViewHostMsg_PDFUpdateContentRestrictions(
315           instance->GetRenderView()->GetRoutingID(), restrictions));
316 }
317
318 void HistogramPDFPageCount(PP_Instance instance, int count) {
319   UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
320 }
321
322 void UserMetricsRecordAction(PP_Instance instance, PP_Var action) {
323   scoped_refptr<ppapi::StringVar> action_str(
324       ppapi::StringVar::FromPPVar(action));
325   if (action_str.get())
326     RenderThread::Get()->RecordComputedAction(action_str->value());
327 }
328
329 void HasUnsupportedFeature(PP_Instance instance_id) {
330   content::PepperPluginInstance* instance =
331       content::PepperPluginInstance::Get(instance_id);
332   if (!instance)
333     return;
334
335   // Only want to show an info bar if the pdf is the whole tab.
336   if (!instance->IsFullPagePlugin())
337     return;
338
339   WebView* view = instance->GetContainer()->element().document().frame()->view();
340   content::RenderView* render_view = content::RenderView::FromWebView(view);
341   render_view->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
342       render_view->GetRoutingID()));
343 }
344
345 void SaveAs(PP_Instance instance_id) {
346   content::PepperPluginInstance* instance =
347       content::PepperPluginInstance::Get(instance_id);
348   if (!instance)
349     return;
350   GURL url = instance->GetPluginURL();
351
352   content::RenderView* render_view = instance->GetRenderView();
353   blink::WebFrame* frame = render_view->GetWebView()->mainFrame();
354   content::Referrer referrer(frame->document().url(),
355                              frame->document().referrerPolicy());
356   render_view->Send(new ChromeViewHostMsg_PDFSaveURLAs(
357       render_view->GetRoutingID(), url, referrer));
358 }
359
360 PP_Bool IsFeatureEnabled(PP_Instance instance, PP_PDFFeature feature) {
361   switch (feature) {
362     case PP_PDFFEATURE_HIDPI:
363 #if defined(OS_WIN)
364       // Disable this for Windows until scaled resources become available.
365       return PP_FALSE;
366 #endif
367       return PP_TRUE;
368     case PP_PDFFEATURE_PRINTING:
369       return IsPrintingEnabled(instance) ? PP_TRUE : PP_FALSE;
370   }
371   return PP_FALSE;
372 }
373
374 PP_Resource GetResourceImageForScale(PP_Instance instance_id,
375                                      PP_ResourceImage image_id,
376                                      float scale) {
377   int res_id = 0;
378   for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) {
379     if (kResourceImageMap[i].pp_id == image_id) {
380       res_id = kResourceImageMap[i].res_id;
381       break;
382     }
383   }
384   if (res_id == 0)
385     return 0;
386
387   // Validate the instance.
388   content::PepperPluginInstance* instance =
389       content::PepperPluginInstance::Get(instance_id);
390   if (!instance)
391     return 0;
392
393   gfx::ImageSkia* res_image_skia =
394       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id);
395
396   if (!res_image_skia)
397     return 0;
398
399   return instance->CreateImage(res_image_skia, scale);
400 }
401
402 PP_Resource GetResourceImage(PP_Instance instance_id,
403                              PP_ResourceImage image_id) {
404   return GetResourceImageForScale(instance_id, image_id, 1.0f);
405 }
406
407 PP_Var ModalPromptForPassword(PP_Instance instance_id,
408                               PP_Var message) {
409   content::PepperPluginInstance* instance =
410       content::PepperPluginInstance::Get(instance_id);
411   if (!instance)
412     return PP_MakeUndefined();
413
414   std::string actual_value;
415   scoped_refptr<ppapi::StringVar> message_string(
416       ppapi::StringVar::FromPPVar(message));
417
418   IPC::SyncMessage* msg = new ChromeViewHostMsg_PDFModalPromptForPassword(
419       instance->GetRenderView()->GetRoutingID(),
420       message_string->value(),
421       &actual_value);
422   msg->EnableMessagePumping();
423   instance->GetRenderView()->Send(msg);
424
425   return ppapi::StringVar::StringToPPVar(actual_value);
426 }
427
428 PP_Bool IsOutOfProcess(PP_Instance instance_id) {
429   return PP_FALSE;
430 }
431
432 void SetSelectedText(PP_Instance instance_id, const char* selected_text) {
433   // This function is intended for out of process PDF plugin.
434   NOTIMPLEMENTED();
435 }
436
437 void SetLinkUnderCursor(PP_Instance instance_id, const char* url) {
438   content::PepperPluginInstance* instance =
439       content::PepperPluginInstance::Get(instance_id);
440   if (!instance)
441     return;
442   instance->SetLinkUnderCursor(url);
443 }
444
445 const PPB_PDF ppb_pdf = {
446   &GetLocalizedString,
447   &GetResourceImage,
448   &GetFontFileWithFallback,
449   &GetFontTableForPrivateFontFile,
450   &SearchString,
451   &DidStartLoading,
452   &DidStopLoading,
453   &SetContentRestriction,
454   &HistogramPDFPageCount,
455   &UserMetricsRecordAction,
456   &HasUnsupportedFeature,
457   &SaveAs,
458   &PPB_PDF_Impl::InvokePrintingForInstance,
459   &IsFeatureEnabled,
460   &GetResourceImageForScale,
461   &ModalPromptForPassword,
462   &IsOutOfProcess,
463   &SetSelectedText,
464   &SetLinkUnderCursor,
465 };
466
467 }  // namespace
468
469 // static
470 const PPB_PDF* PPB_PDF_Impl::GetInterface() {
471   return &ppb_pdf;
472 }
473
474 // static
475 void PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id) {
476 #if defined(ENABLE_FULL_PRINTING)
477   blink::WebElement element = GetWebElement(instance_id);
478   printing::PrintWebViewHelper* helper = GetPrintWebViewHelper(element);
479   if (helper)
480     helper->PrintNode(element);
481 #endif  // ENABLE_FULL_PRINTING
482 }