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.
5 #include "chrome/renderer/pepper/ppb_pdf_impl.h"
7 #include "base/files/scoped_file.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/render_messages.h"
13 #include "chrome/renderer/printing/print_web_view_helper.h"
14 #include "content/app/resources/grit/content_resources.h"
15 #include "content/app/strings/grit/content_strings.h"
16 #include "content/public/common/child_process_sandbox_support_linux.h"
17 #include "content/public/common/referrer.h"
18 #include "content/public/renderer/pepper_plugin_instance.h"
19 #include "content/public/renderer/render_thread.h"
20 #include "content/public/renderer/render_view.h"
21 #include "ppapi/c/pp_resource.h"
22 #include "ppapi/c/private/ppb_pdf.h"
23 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
24 #include "ppapi/shared_impl/ppapi_globals.h"
25 #include "ppapi/shared_impl/resource.h"
26 #include "ppapi/shared_impl/resource_tracker.h"
27 #include "ppapi/shared_impl/var.h"
28 #include "third_party/WebKit/public/web/WebDocument.h"
29 #include "third_party/WebKit/public/web/WebElement.h"
30 #include "third_party/WebKit/public/web/WebLocalFrame.h"
31 #include "third_party/WebKit/public/web/WebPluginContainer.h"
32 #include "third_party/WebKit/public/web/WebView.h"
33 #include "third_party/icu/source/i18n/unicode/usearch.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/resource/resource_bundle.h"
40 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
41 class PrivateFontFile
: public ppapi::Resource
{
43 PrivateFontFile(PP_Instance instance
, int fd
)
44 : Resource(ppapi::OBJECT_IS_IMPL
, instance
), fd_(fd
) {}
46 bool GetFontTable(uint32_t table
, void* output
, uint32_t* output_length
) {
47 size_t temp_size
= static_cast<size_t>(*output_length
);
48 bool rv
= content::GetFontTable(
49 fd_
.get(), table
, 0 /* offset */, static_cast<uint8_t*>(output
),
51 *output_length
= base::checked_cast
<uint32_t>(temp_size
);
56 virtual ~PrivateFontFile() {}
63 struct ResourceImageInfo
{
64 PP_ResourceImage pp_id
;
68 static const ResourceImageInfo kResourceImageMap
[] = {
69 {PP_RESOURCEIMAGE_PDF_BUTTON_FTP
, IDR_PDF_BUTTON_FTP
},
70 {PP_RESOURCEIMAGE_PDF_BUTTON_FTP_HOVER
, IDR_PDF_BUTTON_FTP_HOVER
},
71 {PP_RESOURCEIMAGE_PDF_BUTTON_FTP_PRESSED
, IDR_PDF_BUTTON_FTP_PRESSED
},
72 {PP_RESOURCEIMAGE_PDF_BUTTON_FTW
, IDR_PDF_BUTTON_FTW
},
73 {PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER
, IDR_PDF_BUTTON_FTW_HOVER
},
74 {PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED
, IDR_PDF_BUTTON_FTW_PRESSED
},
75 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END
, IDR_PDF_BUTTON_ZOOMIN_END
},
76 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_HOVER
,
77 IDR_PDF_BUTTON_ZOOMIN_END_HOVER
},
78 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_END_PRESSED
,
79 IDR_PDF_BUTTON_ZOOMIN_END_PRESSED
},
80 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN
, IDR_PDF_BUTTON_ZOOMIN
},
81 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER
, IDR_PDF_BUTTON_ZOOMIN_HOVER
},
82 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED
, IDR_PDF_BUTTON_ZOOMIN_PRESSED
},
83 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT
, IDR_PDF_BUTTON_ZOOMOUT
},
84 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER
, IDR_PDF_BUTTON_ZOOMOUT_HOVER
},
85 {PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED
,
86 IDR_PDF_BUTTON_ZOOMOUT_PRESSED
},
87 {PP_RESOURCEIMAGE_PDF_BUTTON_SAVE
, IDR_PDF_BUTTON_SAVE
},
88 {PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_HOVER
, IDR_PDF_BUTTON_SAVE_HOVER
},
89 {PP_RESOURCEIMAGE_PDF_BUTTON_SAVE_PRESSED
, IDR_PDF_BUTTON_SAVE_PRESSED
},
90 {PP_RESOURCEIMAGE_PDF_BUTTON_PRINT
, IDR_PDF_BUTTON_PRINT
},
91 {PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_HOVER
, IDR_PDF_BUTTON_PRINT_HOVER
},
92 {PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_PRESSED
, IDR_PDF_BUTTON_PRINT_PRESSED
},
93 {PP_RESOURCEIMAGE_PDF_BUTTON_PRINT_DISABLED
, IDR_PDF_BUTTON_PRINT_DISABLED
},
94 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0
, IDR_PDF_THUMBNAIL_0
},
95 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1
, IDR_PDF_THUMBNAIL_1
},
96 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2
, IDR_PDF_THUMBNAIL_2
},
97 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3
, IDR_PDF_THUMBNAIL_3
},
98 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4
, IDR_PDF_THUMBNAIL_4
},
99 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5
, IDR_PDF_THUMBNAIL_5
},
100 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6
, IDR_PDF_THUMBNAIL_6
},
101 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7
, IDR_PDF_THUMBNAIL_7
},
102 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8
, IDR_PDF_THUMBNAIL_8
},
103 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9
, IDR_PDF_THUMBNAIL_9
},
104 {PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND
,
105 IDR_PDF_THUMBNAIL_NUM_BACKGROUND
},
106 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_0
, IDR_PDF_PROGRESS_BAR_0
},
107 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_1
, IDR_PDF_PROGRESS_BAR_1
},
108 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_2
, IDR_PDF_PROGRESS_BAR_2
},
109 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_3
, IDR_PDF_PROGRESS_BAR_3
},
110 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_4
, IDR_PDF_PROGRESS_BAR_4
},
111 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_5
, IDR_PDF_PROGRESS_BAR_5
},
112 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_6
, IDR_PDF_PROGRESS_BAR_6
},
113 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_7
, IDR_PDF_PROGRESS_BAR_7
},
114 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_8
, IDR_PDF_PROGRESS_BAR_8
},
115 {PP_RESOURCEIMAGE_PDF_PROGRESS_BAR_BACKGROUND
,
116 IDR_PDF_PROGRESS_BAR_BACKGROUND
},
117 {PP_RESOURCEIMAGE_PDF_PAGE_INDICATOR_BACKGROUND
,
118 IDR_PDF_PAGE_INDICATOR_BACKGROUND
},
119 {PP_RESOURCEIMAGE_PDF_PAGE_DROPSHADOW
, IDR_PDF_PAGE_DROPSHADOW
},
120 {PP_RESOURCEIMAGE_PDF_PAN_SCROLL_ICON
, IDR_PAN_SCROLL_ICON
}, };
122 #if defined(ENABLE_FULL_PRINTING)
124 blink::WebElement
GetWebElement(PP_Instance instance_id
) {
125 content::PepperPluginInstance
* instance
=
126 content::PepperPluginInstance::Get(instance_id
);
128 return blink::WebElement();
129 return instance
->GetContainer()->element();
132 printing::PrintWebViewHelper
* GetPrintWebViewHelper(
133 const blink::WebElement
& element
) {
134 if (element
.isNull())
136 blink::WebView
* view
= element
.document().frame()->view();
137 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
138 return printing::PrintWebViewHelper::Get(render_view
);
141 bool IsPrintingEnabled(PP_Instance instance_id
) {
142 blink::WebElement element
= GetWebElement(instance_id
);
143 printing::PrintWebViewHelper
* helper
= GetPrintWebViewHelper(element
);
144 return helper
&& helper
->IsPrintingEnabled();
147 #else // ENABLE_FULL_PRINTING
149 bool IsPrintingEnabled(PP_Instance instance_id
) { return false; }
151 #endif // ENABLE_FULL_PRINTING
153 PP_Var
GetLocalizedString(PP_Instance instance_id
,
154 PP_ResourceString string_id
) {
155 content::PepperPluginInstance
* instance
=
156 content::PepperPluginInstance::Get(instance_id
);
158 return PP_MakeUndefined();
161 if (string_id
== PP_RESOURCESTRING_PDFGETPASSWORD
) {
162 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_NEED_PASSWORD
));
163 } else if (string_id
== PP_RESOURCESTRING_PDFLOADING
) {
164 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOADING
));
165 } else if (string_id
== PP_RESOURCESTRING_PDFLOAD_FAILED
) {
166 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PAGE_LOAD_FAILED
));
167 } else if (string_id
== PP_RESOURCESTRING_PDFPROGRESSLOADING
) {
168 rv
= base::UTF16ToUTF8(l10n_util::GetStringUTF16(IDS_PDF_PROGRESS_LOADING
));
173 return ppapi::StringVar::StringToPPVar(rv
);
176 PP_Resource
GetFontFileWithFallback(
177 PP_Instance instance_id
,
178 const PP_BrowserFont_Trusted_Description
* description
,
179 PP_PrivateFontCharset charset
) {
180 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
181 // Validate the instance before using it below.
182 if (!content::PepperPluginInstance::Get(instance_id
))
185 scoped_refptr
<ppapi::StringVar
> face_name(
186 ppapi::StringVar::FromPPVar(description
->face
));
190 int fd
= content::MatchFontWithFallback(
191 face_name
->value().c_str(),
192 description
->weight
>= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD
,
195 description
->family
);
199 scoped_refptr
<PrivateFontFile
> font(new PrivateFontFile(instance_id
, fd
));
201 return font
->GetReference();
203 // For trusted PPAPI plugins, this is only needed in Linux since font loading
204 // on Windows and Mac works through the renderer sandbox.
209 bool GetFontTableForPrivateFontFile(PP_Resource font_file
,
212 uint32_t* output_length
) {
213 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
214 ppapi::Resource
* resource
=
215 ppapi::PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file
);
219 PrivateFontFile
* font
= static_cast<PrivateFontFile
*>(resource
);
220 return font
->GetFontTable(table
, output
, output_length
);
226 void SearchString(PP_Instance instance
,
227 const unsigned short* input_string
,
228 const unsigned short* input_term
,
230 PP_PrivateFindResult
** results
,
232 const base::char16
* string
=
233 reinterpret_cast<const base::char16
*>(input_string
);
234 const base::char16
* term
= reinterpret_cast<const base::char16
*>(input_term
);
236 UErrorCode status
= U_ZERO_ERROR
;
237 UStringSearch
* searcher
=
242 content::RenderThread::Get()->GetLocale().c_str(),
245 DCHECK(status
== U_ZERO_ERROR
|| status
== U_USING_FALLBACK_WARNING
||
246 status
== U_USING_DEFAULT_WARNING
);
247 UCollationStrength strength
= case_sensitive
? UCOL_TERTIARY
: UCOL_PRIMARY
;
249 UCollator
* collator
= usearch_getCollator(searcher
);
250 if (ucol_getStrength(collator
) != strength
) {
251 ucol_setStrength(collator
, strength
);
252 usearch_reset(searcher
);
255 status
= U_ZERO_ERROR
;
256 int match_start
= usearch_first(searcher
, &status
);
257 DCHECK(status
== U_ZERO_ERROR
);
259 std::vector
<PP_PrivateFindResult
> pp_results
;
260 while (match_start
!= USEARCH_DONE
) {
261 size_t matched_length
= usearch_getMatchedLength(searcher
);
262 PP_PrivateFindResult result
;
263 result
.start_index
= match_start
;
264 result
.length
= matched_length
;
265 pp_results
.push_back(result
);
266 match_start
= usearch_next(searcher
, &status
);
267 DCHECK(status
== U_ZERO_ERROR
);
270 *count
= pp_results
.size();
272 *results
= reinterpret_cast<PP_PrivateFindResult
*>(
273 malloc(*count
* sizeof(PP_PrivateFindResult
)));
274 memcpy(*results
, &pp_results
[0], *count
* sizeof(PP_PrivateFindResult
));
279 usearch_close(searcher
);
282 void DidStartLoading(PP_Instance instance_id
) {
283 content::PepperPluginInstance
* instance
=
284 content::PepperPluginInstance::Get(instance_id
);
287 instance
->GetRenderView()->DidStartLoading();
290 void DidStopLoading(PP_Instance instance_id
) {
291 content::PepperPluginInstance
* instance
=
292 content::PepperPluginInstance::Get(instance_id
);
295 instance
->GetRenderView()->DidStopLoading();
298 void SetContentRestriction(PP_Instance instance_id
, int restrictions
) {
299 content::PepperPluginInstance
* instance
=
300 content::PepperPluginInstance::Get(instance_id
);
303 instance
->GetRenderView()->Send(
304 new ChromeViewHostMsg_PDFUpdateContentRestrictions(
305 instance
->GetRenderView()->GetRoutingID(), restrictions
));
308 void HistogramPDFPageCount(PP_Instance instance
, int count
) {
309 UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count
);
312 void UserMetricsRecordAction(PP_Instance instance
, PP_Var action
) {
313 scoped_refptr
<ppapi::StringVar
> action_str(
314 ppapi::StringVar::FromPPVar(action
));
316 content::RenderThread::Get()->RecordComputedAction(action_str
->value());
319 void HasUnsupportedFeature(PP_Instance instance_id
) {
320 content::PepperPluginInstance
* instance
=
321 content::PepperPluginInstance::Get(instance_id
);
325 // Only want to show an info bar if the pdf is the whole tab.
326 if (!instance
->IsFullPagePlugin())
329 blink::WebView
* view
=
330 instance
->GetContainer()->element().document().frame()->view();
331 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
332 render_view
->Send(new ChromeViewHostMsg_PDFHasUnsupportedFeature(
333 render_view
->GetRoutingID()));
336 void SaveAs(PP_Instance instance_id
) {
337 content::PepperPluginInstance
* instance
=
338 content::PepperPluginInstance::Get(instance_id
);
341 GURL url
= instance
->GetPluginURL();
343 content::RenderView
* render_view
= instance
->GetRenderView();
344 blink::WebLocalFrame
* frame
=
345 render_view
->GetWebView()->mainFrame()->toWebLocalFrame();
346 content::Referrer
referrer(frame
->document().url(),
347 frame
->document().referrerPolicy());
348 render_view
->Send(new ChromeViewHostMsg_PDFSaveURLAs(
349 render_view
->GetRoutingID(), url
, referrer
));
352 PP_Bool
IsFeatureEnabled(PP_Instance instance
, PP_PDFFeature feature
) {
354 case PP_PDFFEATURE_HIDPI
:
356 case PP_PDFFEATURE_PRINTING
:
357 return IsPrintingEnabled(instance
) ? PP_TRUE
: PP_FALSE
;
362 PP_Resource
GetResourceImageForScale(PP_Instance instance_id
,
363 PP_ResourceImage image_id
,
366 for (size_t i
= 0; i
< arraysize(kResourceImageMap
); ++i
) {
367 if (kResourceImageMap
[i
].pp_id
== image_id
) {
368 res_id
= kResourceImageMap
[i
].res_id
;
375 // Validate the instance.
376 content::PepperPluginInstance
* instance
=
377 content::PepperPluginInstance::Get(instance_id
);
381 gfx::ImageSkia
* res_image_skia
=
382 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id
);
387 return instance
->CreateImage(res_image_skia
, scale
);
390 PP_Resource
GetResourceImage(PP_Instance instance_id
,
391 PP_ResourceImage image_id
) {
392 return GetResourceImageForScale(instance_id
, image_id
, 1.0f
);
395 PP_Var
ModalPromptForPassword(PP_Instance instance_id
, PP_Var message
) {
396 content::PepperPluginInstance
* instance
=
397 content::PepperPluginInstance::Get(instance_id
);
399 return PP_MakeUndefined();
401 std::string actual_value
;
402 scoped_refptr
<ppapi::StringVar
> message_string(
403 ppapi::StringVar::FromPPVar(message
));
405 IPC::SyncMessage
* msg
= new ChromeViewHostMsg_PDFModalPromptForPassword(
406 instance
->GetRenderView()->GetRoutingID(),
407 message_string
->value(),
409 msg
->EnableMessagePumping();
410 instance
->GetRenderView()->Send(msg
);
412 return ppapi::StringVar::StringToPPVar(actual_value
);
415 PP_Bool
IsOutOfProcess(PP_Instance instance_id
) { return PP_FALSE
; }
417 void SetSelectedText(PP_Instance instance_id
, const char* selected_text
) {
418 // This function is intended for out of process PDF plugin.
421 void SetLinkUnderCursor(PP_Instance instance_id
, const char* url
) {
422 content::PepperPluginInstance
* instance
=
423 content::PepperPluginInstance::Get(instance_id
);
426 instance
->SetLinkUnderCursor(url
);
429 const PPB_PDF ppb_pdf
= { //
430 &GetLocalizedString
, //
431 &GetResourceImage
, //
432 &GetFontFileWithFallback
, //
433 &GetFontTableForPrivateFontFile
, //
437 &SetContentRestriction
, //
438 &HistogramPDFPageCount
, //
439 &UserMetricsRecordAction
, //
440 &HasUnsupportedFeature
, //
442 &PPB_PDF_Impl::InvokePrintingForInstance
, //
443 &IsFeatureEnabled
, //
444 &GetResourceImageForScale
, //
445 &ModalPromptForPassword
, //
448 &SetLinkUnderCursor
, //
454 const PPB_PDF
* PPB_PDF_Impl::GetInterface() { return &ppb_pdf
; }
457 void PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id
) {
458 #if defined(ENABLE_FULL_PRINTING)
459 blink::WebElement element
= GetWebElement(instance_id
);
460 printing::PrintWebViewHelper
* helper
= GetPrintWebViewHelper(element
);
462 helper
->PrintNode(element
);
463 #endif // ENABLE_FULL_PRINTING