Home | History | Annotate | Download | only in renderer
      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:
     41   PrivateFontFile(PP_Instance instance, int fd)
     42       : Resource(ppapi::OBJECT_IS_IMPL, instance), fd_(fd) {}
     43 
     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:
     56   virtual ~PrivateFontFile() {}
     57 
     58  private:
     59   base::ScopedFD fd_;
     60 };
     61 #endif
     62 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    205 void HistogramPDFPageCount(PP_Instance instance, int count) {
    206   UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
    207 }
    208 
    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 
    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 
    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 
    249 void Print(PP_Instance instance) {
    250   PPB_PDF_Impl::InvokePrintingForInstance(instance);
    251 }
    252 
    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 
    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 
    282 PP_Resource GetResourceImage(PP_Instance instance_id,
    283                              PP_ResourceImage image_id) {
    284   return GetResourceImageForScale(instance_id, image_id, 1.0f);
    285 }
    286 
    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 
    307 PP_Bool IsOutOfProcess(PP_Instance instance_id) {
    308   return PP_FALSE;
    309 }
    310 
    311 void SetSelectedText(PP_Instance instance_id, const char* selected_text) {
    312   // This function is intended for out of process PDF plugin.
    313 }
    314 
    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
    348 const PPB_PDF* PPB_PDF_Impl::GetInterface() {
    349   return &ppb_pdf;
    350 }
    351 
    352 // static
    353 bool PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id) {
    354   return g_print_client ? g_print_client->Print(instance_id) : false;
    355 }
    356 
    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