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