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/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"
40 using ppapi::PpapiGlobals
;
41 using WebKit::WebElement
;
42 using WebKit::WebView
;
43 using content::RenderThread
;
47 #if defined(OS_LINUX) || defined(OS_OPENBSD)
48 class PrivateFontFile
: public ppapi::Resource
{
50 PrivateFontFile(PP_Instance instance
, int fd
)
51 : Resource(ppapi::OBJECT_IS_IMPL
, instance
),
55 bool GetFontTable(uint32_t table
,
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
);
66 virtual ~PrivateFontFile() {}
73 struct ResourceImageInfo
{
74 PP_ResourceImage pp_id
;
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
},
133 #if defined(ENABLE_PRINTING)
135 WebKit::WebElement
GetWebElement(PP_Instance instance_id
) {
136 content::PepperPluginInstance
* instance
=
137 content::PepperPluginInstance::Get(instance_id
);
139 return WebKit::WebElement();
140 return instance
->GetContainer()->element();
143 printing::PrintWebViewHelper
* GetPrintWebViewHelper(
144 const WebKit::WebElement
& element
) {
145 if (element
.isNull())
147 WebKit::WebView
* view
= element
.document().frame()->view();
148 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
149 return printing::PrintWebViewHelper::Get(render_view
);
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();
158 #else // ENABLE_PRINTING
160 bool IsPrintingEnabled(PP_Instance instance_id
) {
164 #endif // ENABLE_PRINTING
168 PP_Var
GetLocalizedString(PP_Instance instance_id
,
169 PP_ResourceString string_id
) {
170 content::PepperPluginInstance
* instance
=
171 content::PepperPluginInstance::Get(instance_id
);
173 return PP_MakeUndefined();
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
));
188 return ppapi::StringVar::StringToPPVar(rv
);
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
))
200 scoped_refptr
<ppapi::StringVar
> face_name(ppapi::StringVar::FromPPVar(
202 if (!face_name
.get())
205 int fd
= content::MatchFontWithFallback(
206 face_name
->value().c_str(),
207 description
->weight
>= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD
,
213 scoped_refptr
<PrivateFontFile
> font(new PrivateFontFile(instance_id
, fd
));
215 return font
->GetReference();
217 // For trusted PPAPI plugins, this is only needed in Linux since font loading
218 // on Windows and Mac works through the renderer sandbox.
223 bool GetFontTableForPrivateFontFile(PP_Resource font_file
,
226 uint32_t* output_length
) {
227 #if defined(OS_LINUX) || defined(OS_OPENBSD)
228 ppapi::Resource
* resource
=
229 PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file
);
233 PrivateFontFile
* font
= static_cast<PrivateFontFile
*>(resource
);
234 return font
->GetFontTable(table
, output
, output_length
);
240 void SearchString(PP_Instance instance
,
241 const unsigned short* input_string
,
242 const unsigned short* input_term
,
244 PP_PrivateFindResult
** results
,
246 const char16
* string
= reinterpret_cast<const char16
*>(input_string
);
247 const char16
* term
= reinterpret_cast<const char16
*>(input_term
);
249 UErrorCode status
= U_ZERO_ERROR
;
250 UStringSearch
* searcher
= usearch_open(
251 term
, -1, string
, -1, RenderThread::Get()->GetLocale().c_str(), 0,
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
;
257 UCollator
* collator
= usearch_getCollator(searcher
);
258 if (ucol_getStrength(collator
) != strength
) {
259 ucol_setStrength(collator
, strength
);
260 usearch_reset(searcher
);
263 status
= U_ZERO_ERROR
;
264 int match_start
= usearch_first(searcher
, &status
);
265 DCHECK(status
== U_ZERO_ERROR
);
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
);
278 *count
= pp_results
.size();
280 *results
= reinterpret_cast<PP_PrivateFindResult
*>(
281 malloc(*count
* sizeof(PP_PrivateFindResult
)));
282 memcpy(*results
, &pp_results
[0], *count
* sizeof(PP_PrivateFindResult
));
287 usearch_close(searcher
);
290 void DidStartLoading(PP_Instance instance_id
) {
291 content::PepperPluginInstance
* instance
=
292 content::PepperPluginInstance::Get(instance_id
);
295 instance
->GetRenderView()->DidStartLoading();
298 void DidStopLoading(PP_Instance instance_id
) {
299 content::PepperPluginInstance
* instance
=
300 content::PepperPluginInstance::Get(instance_id
);
303 instance
->GetRenderView()->DidStopLoading();
306 void SetContentRestriction(PP_Instance instance_id
, int restrictions
) {
307 content::PepperPluginInstance
* instance
=
308 content::PepperPluginInstance::Get(instance_id
);
311 instance
->GetRenderView()->Send(
312 new ChromeViewHostMsg_PDFUpdateContentRestrictions(
313 instance
->GetRenderView()->GetRoutingID(), restrictions
));
316 void HistogramPDFPageCount(PP_Instance instance
, int count
) {
317 UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count
);
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());
327 void HasUnsupportedFeature(PP_Instance instance_id
) {
328 content::PepperPluginInstance
* instance
=
329 content::PepperPluginInstance::Get(instance_id
);
333 // Only want to show an info bar if the pdf is the whole tab.
334 if (!instance
->IsFullPagePlugin())
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()));
343 void SaveAs(PP_Instance instance_id
) {
344 content::PepperPluginInstance
* instance
=
345 content::PepperPluginInstance::Get(instance_id
);
348 GURL url
= instance
->GetPluginURL();
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
));
358 PP_Bool
IsFeatureEnabled(PP_Instance instance
, PP_PDFFeature feature
) {
360 case PP_PDFFEATURE_HIDPI
:
362 case PP_PDFFEATURE_PRINTING
:
363 return IsPrintingEnabled(instance
) ? PP_TRUE
: PP_FALSE
;
368 PP_Resource
GetResourceImageForScale(PP_Instance instance_id
,
369 PP_ResourceImage image_id
,
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
;
381 // Validate the instance.
382 content::PepperPluginInstance
* instance
=
383 content::PepperPluginInstance::Get(instance_id
);
387 gfx::ImageSkia
* res_image_skia
=
388 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(res_id
);
393 return instance
->CreateImage(res_image_skia
, scale
);
396 PP_Resource
GetResourceImage(PP_Instance instance_id
,
397 PP_ResourceImage image_id
) {
398 return GetResourceImageForScale(instance_id
, image_id
, 1.0f
);
401 const PPB_PDF ppb_pdf
= {
404 &GetFontFileWithFallback
,
405 &GetFontTableForPrivateFontFile
,
409 &SetContentRestriction
,
410 &HistogramPDFPageCount
,
411 &UserMetricsRecordAction
,
412 &HasUnsupportedFeature
,
414 &PPB_PDF_Impl::InvokePrintingForInstance
,
416 &GetResourceImageForScale
422 const PPB_PDF
* PPB_PDF_Impl::GetInterface() {
427 void PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id
) {
428 #if defined(ENABLE_PRINTING)
429 WebKit::WebElement element
= GetWebElement(instance_id
);
430 printing::PrintWebViewHelper
* helper
= GetPrintWebViewHelper(element
);
432 helper
->PrintNode(element
);
433 #endif // ENABLE_PRINTING