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 "components/pdf/renderer/ppb_pdf_impl.h"
7 #include "base/files/scoped_file.h"
8 #include "base/lazy_instance.h"
9 #include "base/metrics/histogram.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/threading/thread_local.h"
13 #include "build/build_config.h"
14 #include "components/pdf/common/pdf_messages.h"
15 #include "components/pdf/renderer/pdf_resource_util.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 "gin/public/isolate_holder.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"
40 // --single-process model may fail in CHECK(!g_print_client) if there exist
41 // more than two RenderThreads, so here we use TLS for g_print_client.
42 // See http://crbug.com/457580.
43 base::LazyInstance
<base::ThreadLocalPointer
<PPB_PDF_Impl::PrintClient
> >::Leaky
44 g_print_client_tls
= LAZY_INSTANCE_INITIALIZER
;
46 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
47 class PrivateFontFile
: public ppapi::Resource
{
49 PrivateFontFile(PP_Instance instance
, int fd
)
50 : Resource(ppapi::OBJECT_IS_IMPL
, instance
), fd_(fd
) {}
52 bool GetFontTable(uint32_t table
, void* output
, uint32_t* output_length
) {
53 size_t temp_size
= static_cast<size_t>(*output_length
);
54 bool rv
= content::GetFontTable(fd_
.get(),
57 static_cast<uint8_t*>(output
),
59 *output_length
= base::checked_cast
<uint32_t>(temp_size
);
64 virtual ~PrivateFontFile() {}
71 PP_Var
GetLocalizedString(PP_Instance instance_id
,
72 PP_ResourceString string_id
) {
73 content::PepperPluginInstance
* instance
=
74 content::PepperPluginInstance::Get(instance_id
);
76 return PP_MakeUndefined();
78 std::string rv
= GetStringResource(string_id
);
79 return ppapi::StringVar::StringToPPVar(rv
);
82 PP_Resource
GetFontFileWithFallback(
83 PP_Instance instance_id
,
84 const PP_BrowserFont_Trusted_Description
* description
,
85 PP_PrivateFontCharset charset
) {
86 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
87 // Validate the instance before using it below.
88 if (!content::PepperPluginInstance::Get(instance_id
))
91 scoped_refptr
<ppapi::StringVar
> face_name(
92 ppapi::StringVar::FromPPVar(description
->face
));
96 int fd
= content::MatchFontWithFallback(
97 face_name
->value().c_str(),
98 description
->weight
>= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD
,
101 description
->family
);
105 scoped_refptr
<PrivateFontFile
> font(new PrivateFontFile(instance_id
, fd
));
107 return font
->GetReference();
109 // For trusted PPAPI plugins, this is only needed in Linux since font loading
110 // on Windows and Mac works through the renderer sandbox.
115 bool GetFontTableForPrivateFontFile(PP_Resource font_file
,
118 uint32_t* output_length
) {
119 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
120 ppapi::Resource
* resource
=
121 ppapi::PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file
);
125 PrivateFontFile
* font
= static_cast<PrivateFontFile
*>(resource
);
126 return font
->GetFontTable(table
, output
, output_length
);
132 void SearchString(PP_Instance instance
,
133 const unsigned short* input_string
,
134 const unsigned short* input_term
,
136 PP_PrivateFindResult
** results
,
138 const base::char16
* string
=
139 reinterpret_cast<const base::char16
*>(input_string
);
140 const base::char16
* term
= reinterpret_cast<const base::char16
*>(input_term
);
142 UErrorCode status
= U_ZERO_ERROR
;
143 UStringSearch
* searcher
=
148 content::RenderThread::Get()->GetLocale().c_str(),
151 DCHECK(status
== U_ZERO_ERROR
|| status
== U_USING_FALLBACK_WARNING
||
152 status
== U_USING_DEFAULT_WARNING
);
153 UCollationStrength strength
= case_sensitive
? UCOL_TERTIARY
: UCOL_PRIMARY
;
155 UCollator
* collator
= usearch_getCollator(searcher
);
156 if (ucol_getStrength(collator
) != strength
) {
157 ucol_setStrength(collator
, strength
);
158 usearch_reset(searcher
);
161 status
= U_ZERO_ERROR
;
162 int match_start
= usearch_first(searcher
, &status
);
163 DCHECK(status
== U_ZERO_ERROR
);
165 std::vector
<PP_PrivateFindResult
> pp_results
;
166 while (match_start
!= USEARCH_DONE
) {
167 size_t matched_length
= usearch_getMatchedLength(searcher
);
168 PP_PrivateFindResult result
;
169 result
.start_index
= match_start
;
170 result
.length
= matched_length
;
171 pp_results
.push_back(result
);
172 match_start
= usearch_next(searcher
, &status
);
173 DCHECK(status
== U_ZERO_ERROR
);
176 *count
= pp_results
.size();
178 *results
= reinterpret_cast<PP_PrivateFindResult
*>(
179 malloc(*count
* sizeof(PP_PrivateFindResult
)));
180 memcpy(*results
, &pp_results
[0], *count
* sizeof(PP_PrivateFindResult
));
185 usearch_close(searcher
);
188 void DidStartLoading(PP_Instance instance_id
) {
189 content::PepperPluginInstance
* instance
=
190 content::PepperPluginInstance::Get(instance_id
);
193 instance
->GetRenderView()->DidStartLoading();
196 void DidStopLoading(PP_Instance instance_id
) {
197 content::PepperPluginInstance
* instance
=
198 content::PepperPluginInstance::Get(instance_id
);
201 instance
->GetRenderView()->DidStopLoading();
204 void SetContentRestriction(PP_Instance instance_id
, int restrictions
) {
205 content::PepperPluginInstance
* instance
=
206 content::PepperPluginInstance::Get(instance_id
);
209 instance
->GetRenderView()->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
210 instance
->GetRenderView()->GetRoutingID(), restrictions
));
213 void HistogramPDFPageCount(PP_Instance instance
, int count
) {
214 UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count
);
217 void UserMetricsRecordAction(PP_Instance instance
, PP_Var action
) {
218 scoped_refptr
<ppapi::StringVar
> action_str(
219 ppapi::StringVar::FromPPVar(action
));
220 if (action_str
.get())
221 content::RenderThread::Get()->RecordComputedAction(action_str
->value());
224 void HasUnsupportedFeature(PP_Instance instance_id
) {
225 content::PepperPluginInstance
* instance
=
226 content::PepperPluginInstance::Get(instance_id
);
230 // Only want to show an info bar if the pdf is the whole tab.
231 if (!instance
->IsFullPagePlugin())
234 blink::WebView
* view
=
235 instance
->GetContainer()->element().document().frame()->view();
236 content::RenderView
* render_view
= content::RenderView::FromWebView(view
);
238 new PDFHostMsg_PDFHasUnsupportedFeature(render_view
->GetRoutingID()));
241 void SaveAs(PP_Instance instance_id
) {
242 content::PepperPluginInstance
* instance
=
243 content::PepperPluginInstance::Get(instance_id
);
246 GURL url
= instance
->GetPluginURL();
248 content::RenderView
* render_view
= instance
->GetRenderView();
249 blink::WebLocalFrame
* frame
=
250 render_view
->GetWebView()->mainFrame()->toWebLocalFrame();
251 content::Referrer referrer
= content::Referrer::SanitizeForRequest(
252 url
, content::Referrer(frame
->document().url(),
253 frame
->document().referrerPolicy()));
255 new PDFHostMsg_PDFSaveURLAs(render_view
->GetRoutingID(), url
, referrer
));
258 void Print(PP_Instance instance
) {
259 PPB_PDF_Impl::InvokePrintingForInstance(instance
);
262 PP_Bool
IsFeatureEnabled(PP_Instance instance
, PP_PDFFeature feature
) {
264 case PP_PDFFEATURE_HIDPI
:
266 case PP_PDFFEATURE_PRINTING
:
267 return (g_print_client_tls
.Pointer()->Get() &&
268 g_print_client_tls
.Pointer()->Get()->IsPrintingEnabled(instance
))
275 PP_Resource
GetResourceImageForScale(PP_Instance instance_id
,
276 PP_ResourceImage image_id
,
278 // Validate the instance.
279 content::PepperPluginInstance
* instance
=
280 content::PepperPluginInstance::Get(instance_id
);
284 gfx::ImageSkia
* res_image_skia
= GetImageResource(image_id
);
289 return instance
->CreateImage(res_image_skia
, scale
);
292 PP_Resource
GetResourceImage(PP_Instance instance_id
,
293 PP_ResourceImage image_id
) {
294 return GetResourceImageForScale(instance_id
, image_id
, 1.0f
);
297 PP_Var
ModalPromptForPassword(PP_Instance instance_id
, PP_Var message
) {
298 content::PepperPluginInstance
* instance
=
299 content::PepperPluginInstance::Get(instance_id
);
301 return PP_MakeUndefined();
303 std::string actual_value
;
304 scoped_refptr
<ppapi::StringVar
> message_string(
305 ppapi::StringVar::FromPPVar(message
));
307 IPC::SyncMessage
* msg
= new PDFHostMsg_PDFModalPromptForPassword(
308 instance
->GetRenderView()->GetRoutingID(),
309 message_string
->value(),
311 msg
->EnableMessagePumping();
312 instance
->GetRenderView()->Send(msg
);
314 return ppapi::StringVar::StringToPPVar(actual_value
);
317 PP_Bool
IsOutOfProcess(PP_Instance instance_id
) {
321 // This function is intended for both in-process and out-of-process pdf.
322 void SetSelectedText(PP_Instance instance_id
, const char* selected_text
) {
323 content::PepperPluginInstance
* instance
=
324 content::PepperPluginInstance::Get(instance_id
);
328 base::string16 selection_text
;
329 base::UTF8ToUTF16(selected_text
, strlen(selected_text
), &selection_text
);
330 instance
->SetSelectedText(selection_text
);
333 void SetLinkUnderCursor(PP_Instance instance_id
, const char* url
) {
334 content::PepperPluginInstance
* instance
=
335 content::PepperPluginInstance::Get(instance_id
);
338 instance
->SetLinkUnderCursor(url
);
341 void GetV8ExternalSnapshotData(PP_Instance instance_id
,
342 const char** natives_data_out
,
343 int* natives_size_out
,
344 const char** snapshot_data_out
,
345 int* snapshot_size_out
) {
346 gin::IsolateHolder::GetV8ExternalSnapshotData(natives_data_out
,
347 natives_size_out
, snapshot_data_out
, snapshot_size_out
);
350 const PPB_PDF ppb_pdf
= { //
351 &GetLocalizedString
, //
352 &GetResourceImage
, //
353 &GetFontFileWithFallback
, //
354 &GetFontTableForPrivateFontFile
, //
358 &SetContentRestriction
, //
359 &HistogramPDFPageCount
, //
360 &UserMetricsRecordAction
, //
361 &HasUnsupportedFeature
, //
364 &IsFeatureEnabled
, //
365 &GetResourceImageForScale
, //
366 &ModalPromptForPassword
, //
369 &SetLinkUnderCursor
, //
370 &GetV8ExternalSnapshotData
, //
376 const PPB_PDF
* PPB_PDF_Impl::GetInterface() {
381 bool PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id
) {
382 return g_print_client_tls
.Pointer()->Get()
383 ? g_print_client_tls
.Pointer()->Get()->Print(instance_id
)
387 void PPB_PDF_Impl::SetPrintClient(PPB_PDF_Impl::PrintClient
* client
) {
388 CHECK(!g_print_client_tls
.Pointer()->Get())
389 << "There should only be a single PrintClient for one RenderThread.";
390 g_print_client_tls
.Pointer()->Set(client
);