Home | History | Annotate | Download | only in pepper
      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/safe_numerics.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/skia/include/core/SkBitmap.h"
     30 #include "third_party/WebKit/public/web/WebDocument.h"
     31 #include "third_party/WebKit/public/web/WebElement.h"
     32 #include "third_party/WebKit/public/web/WebFrame.h"
     33 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     34 #include "third_party/WebKit/public/web/WebView.h"
     35 #include "third_party/icu/source/i18n/unicode/usearch.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 WebKit::WebElement;
     42 using WebKit::WebView;
     43 using content::RenderThread;
     44 
     45 namespace {
     46 
     47 #if defined(OS_LINUX) || defined(OS_OPENBSD)
     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_numeric_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 WebKit::WebElement GetWebElement(PP_Instance instance_id) {
    136   content::PepperPluginInstance* instance =
    137       content::PepperPluginInstance::Get(instance_id);
    138   if (!instance)
    139     return WebKit::WebElement();
    140   return instance->GetContainer()->element();
    141 }
    142 
    143 printing::PrintWebViewHelper* GetPrintWebViewHelper(
    144     const WebKit::WebElement& element) {
    145   if (element.isNull())
    146     return NULL;
    147   WebKit::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   WebKit::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 = UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD));
    178   } else if (string_id == PP_RESOURCESTRING_PDFLOADING) {
    179     rv = UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING));
    180   } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) {
    181     rv = UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED));
    182   } else if (string_id == PP_RESOURCESTRING_PDFPROGRESSLOADING) {
    183     rv = 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_LINUX) || defined(OS_OPENBSD)
    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_LINUX) || defined(OS_OPENBSD)
    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 char16* string = reinterpret_cast<const char16*>(input_string);
    247   const char16* term = reinterpret_cast<const char16*>(input_term);
    248 
    249   UErrorCode status = U_ZERO_ERROR;
    250   UStringSearch* searcher = usearch_open(
    251       term, -1, string, -1, RenderThread::Get()->GetLocale().c_str(), 0,
    252       &status);
    253   DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
    254          status == U_USING_DEFAULT_WARNING);
    255   UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
    256 
    257   UCollator* collator = usearch_getCollator(searcher);
    258   if (ucol_getStrength(collator) != strength) {
    259     ucol_setStrength(collator, strength);
    260     usearch_reset(searcher);
    261   }
    262 
    263   status = U_ZERO_ERROR;
    264   int match_start = usearch_first(searcher, &status);
    265   DCHECK(status == U_ZERO_ERROR);
    266 
    267   std::vector<PP_PrivateFindResult> pp_results;
    268   while (match_start != USEARCH_DONE) {
    269     size_t matched_length = usearch_getMatchedLength(searcher);
    270     PP_PrivateFindResult result;
    271     result.start_index = match_start;
    272     result.length = matched_length;
    273     pp_results.push_back(result);
    274     match_start = usearch_next(searcher, &status);
    275     DCHECK(status == U_ZERO_ERROR);
    276   }
    277 
    278   *count = pp_results.size();
    279   if (*count) {
    280     *results = reinterpret_cast<PP_PrivateFindResult*>(
    281         malloc(*count * sizeof(PP_PrivateFindResult)));
    282     memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
    283   } else {
    284     *results = NULL;
    285   }
    286 
    287   usearch_close(searcher);
    288 }
    289 
    290 void DidStartLoading(PP_Instance instance_id) {
    291   content::PepperPluginInstance* instance =
    292       content::PepperPluginInstance::Get(instance_id);
    293   if (!instance)
    294     return;
    295   instance->GetRenderView()->DidStartLoading();
    296 }
    297 
    298 void DidStopLoading(PP_Instance instance_id) {
    299   content::PepperPluginInstance* instance =
    300       content::PepperPluginInstance::Get(instance_id);
    301   if (!instance)
    302     return;
    303   instance->GetRenderView()->DidStopLoading();
    304 }
    305 
    306 void SetContentRestriction(PP_Instance instance_id, int restrictions) {
    307   content::PepperPluginInstance* instance =
    308       content::PepperPluginInstance::Get(instance_id);
    309   if (!instance)
    310     return;
    311   instance->GetRenderView()->Send(
    312       new ChromeViewHostMsg_PDFUpdateContentRestrictions(
    313           instance->GetRenderView()->GetRoutingID(), restrictions));
    314 }
    315 
    316 void HistogramPDFPageCount(PP_Instance instance, int count) {
    317   UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
    318 }
    319 
    320 void UserMetricsRecordAction(PP_Instance instance, PP_Var action) {
    321   scoped_refptr<ppapi::StringVar> action_str(
    322       ppapi::StringVar::FromPPVar(action));
    323   if (action_str.get())
    324     RenderThread::Get()->RecordUserMetrics(action_str->value());
    325 }
    326 
    327 void HasUnsupportedFeature(PP_Instance instance_id) {
    328   content::PepperPluginInstance* instance =
    329       content::PepperPluginInstance::Get(instance_id);
    330   if (!instance)
    331     return;
    332 
    333   // Only want to show an info bar if the pdf is the whole tab.
    334   if (!instance->IsFullPagePlugin())
    335     return;
    336 
    337   WebView* view = instance->GetContainer()->element().document().frame()->view();
    338   content::RenderView* render_view = content::RenderView::FromWebView(view);
    339   render_view->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
    340       render_view->GetRoutingID()));
    341 }
    342 
    343 void SaveAs(PP_Instance instance_id) {
    344   content::PepperPluginInstance* instance =
    345       content::PepperPluginInstance::Get(instance_id);
    346   if (!instance)
    347     return;
    348   GURL url = instance->GetPluginURL();
    349 
    350   content::RenderView* render_view = instance->GetRenderView();
    351   WebKit::WebFrame* frame = render_view->GetWebView()->mainFrame();
    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   int res_id = 0;
    372   for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) {
    373     if (kResourceImageMap[i].pp_id == image_id) {
    374       res_id = kResourceImageMap[i].res_id;
    375       break;
    376     }
    377   }
    378   if (res_id == 0)
    379     return 0;
    380 
    381   // Validate the instance.
    382   content::PepperPluginInstance* instance =
    383       content::PepperPluginInstance::Get(instance_id);
    384   if (!instance)
    385     return 0;
    386 
    387   gfx::ImageSkia* res_image_skia =
    388       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id);
    389 
    390   if (!res_image_skia)
    391     return 0;
    392 
    393   return instance->CreateImage(res_image_skia, scale);
    394 }
    395 
    396 PP_Resource GetResourceImage(PP_Instance instance_id,
    397                              PP_ResourceImage image_id) {
    398   return GetResourceImageForScale(instance_id, image_id, 1.0f);
    399 }
    400 
    401 const PPB_PDF ppb_pdf = {
    402   &GetLocalizedString,
    403   &GetResourceImage,
    404   &GetFontFileWithFallback,
    405   &GetFontTableForPrivateFontFile,
    406   &SearchString,
    407   &DidStartLoading,
    408   &DidStopLoading,
    409   &SetContentRestriction,
    410   &HistogramPDFPageCount,
    411   &UserMetricsRecordAction,
    412   &HasUnsupportedFeature,
    413   &SaveAs,
    414   &PPB_PDF_Impl::InvokePrintingForInstance,
    415   &IsFeatureEnabled,
    416   &GetResourceImageForScale
    417 };
    418 
    419 }  // namespace
    420 
    421 // static
    422 const PPB_PDF* PPB_PDF_Impl::GetInterface() {
    423   return &ppb_pdf;
    424 }
    425 
    426 // static
    427 void PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id) {
    428 #if defined(ENABLE_FULL_PRINTING)
    429   WebKit::WebElement element = GetWebElement(instance_id);
    430   printing::PrintWebViewHelper* helper = GetPrintWebViewHelper(element);
    431   if (helper)
    432     helper->PrintNode(element);
    433 #endif  // ENABLE_FULL_PRINTING
    434 }
    435