Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / components / pdf / renderer / ppb_pdf_impl.cc
blobaa0a33a05747ff4484f839353d301293d8aaf6b3
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/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 "components/pdf/common/pdf_messages.h"
13 #include "components/pdf/renderer/pdf_resource_util.h"
14 #include "content/public/common/child_process_sandbox_support_linux.h"
15 #include "content/public/common/referrer.h"
16 #include "content/public/renderer/pepper_plugin_instance.h"
17 #include "content/public/renderer/render_thread.h"
18 #include "content/public/renderer/render_view.h"
19 #include "gin/public/isolate_holder.h"
20 #include "ppapi/c/pp_resource.h"
21 #include "ppapi/c/private/ppb_pdf.h"
22 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
23 #include "ppapi/shared_impl/ppapi_globals.h"
24 #include "ppapi/shared_impl/resource.h"
25 #include "ppapi/shared_impl/resource_tracker.h"
26 #include "ppapi/shared_impl/var.h"
27 #include "third_party/WebKit/public/web/WebDocument.h"
28 #include "third_party/WebKit/public/web/WebElement.h"
29 #include "third_party/WebKit/public/web/WebLocalFrame.h"
30 #include "third_party/WebKit/public/web/WebPluginContainer.h"
31 #include "third_party/WebKit/public/web/WebView.h"
32 #include "third_party/icu/source/i18n/unicode/usearch.h"
33 #include "third_party/skia/include/core/SkBitmap.h"
35 namespace pdf {
36 namespace {
38 PPB_PDF_Impl::PrintClient* g_print_client = NULL;
40 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
41 class PrivateFontFile : public ppapi::Resource {
42 public:
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(fd_.get(),
49 table,
50 0 /* offset */,
51 static_cast<uint8_t*>(output),
52 &temp_size);
53 *output_length = base::checked_cast<uint32_t>(temp_size);
54 return rv;
57 protected:
58 virtual ~PrivateFontFile() {}
60 private:
61 base::ScopedFD fd_;
63 #endif
65 PP_Var GetLocalizedString(PP_Instance instance_id,
66 PP_ResourceString string_id) {
67 content::PepperPluginInstance* instance =
68 content::PepperPluginInstance::Get(instance_id);
69 if (!instance)
70 return PP_MakeUndefined();
72 std::string rv = GetStringResource(string_id);
73 return ppapi::StringVar::StringToPPVar(rv);
76 PP_Resource GetFontFileWithFallback(
77 PP_Instance instance_id,
78 const PP_BrowserFont_Trusted_Description* description,
79 PP_PrivateFontCharset charset) {
80 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
81 // Validate the instance before using it below.
82 if (!content::PepperPluginInstance::Get(instance_id))
83 return 0;
85 scoped_refptr<ppapi::StringVar> face_name(
86 ppapi::StringVar::FromPPVar(description->face));
87 if (!face_name.get())
88 return 0;
90 int fd = content::MatchFontWithFallback(
91 face_name->value().c_str(),
92 description->weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD,
93 description->italic,
94 charset,
95 description->family);
96 if (fd == -1)
97 return 0;
99 scoped_refptr<PrivateFontFile> font(new PrivateFontFile(instance_id, fd));
101 return font->GetReference();
102 #else
103 // For trusted PPAPI plugins, this is only needed in Linux since font loading
104 // on Windows and Mac works through the renderer sandbox.
105 return 0;
106 #endif
109 bool GetFontTableForPrivateFontFile(PP_Resource font_file,
110 uint32_t table,
111 void* output,
112 uint32_t* output_length) {
113 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
114 ppapi::Resource* resource =
115 ppapi::PpapiGlobals::Get()->GetResourceTracker()->GetResource(font_file);
116 if (!resource)
117 return false;
119 PrivateFontFile* font = static_cast<PrivateFontFile*>(resource);
120 return font->GetFontTable(table, output, output_length);
121 #else
122 return false;
123 #endif
126 void SearchString(PP_Instance instance,
127 const unsigned short* input_string,
128 const unsigned short* input_term,
129 bool case_sensitive,
130 PP_PrivateFindResult** results,
131 int* count) {
132 const base::char16* string =
133 reinterpret_cast<const base::char16*>(input_string);
134 const base::char16* term = reinterpret_cast<const base::char16*>(input_term);
136 UErrorCode status = U_ZERO_ERROR;
137 UStringSearch* searcher =
138 usearch_open(term,
140 string,
142 content::RenderThread::Get()->GetLocale().c_str(),
144 &status);
145 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
146 status == U_USING_DEFAULT_WARNING);
147 UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
149 UCollator* collator = usearch_getCollator(searcher);
150 if (ucol_getStrength(collator) != strength) {
151 ucol_setStrength(collator, strength);
152 usearch_reset(searcher);
155 status = U_ZERO_ERROR;
156 int match_start = usearch_first(searcher, &status);
157 DCHECK(status == U_ZERO_ERROR);
159 std::vector<PP_PrivateFindResult> pp_results;
160 while (match_start != USEARCH_DONE) {
161 size_t matched_length = usearch_getMatchedLength(searcher);
162 PP_PrivateFindResult result;
163 result.start_index = match_start;
164 result.length = matched_length;
165 pp_results.push_back(result);
166 match_start = usearch_next(searcher, &status);
167 DCHECK(status == U_ZERO_ERROR);
170 *count = pp_results.size();
171 if (*count) {
172 *results = reinterpret_cast<PP_PrivateFindResult*>(
173 malloc(*count * sizeof(PP_PrivateFindResult)));
174 memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
175 } else {
176 *results = NULL;
179 usearch_close(searcher);
182 void DidStartLoading(PP_Instance instance_id) {
183 content::PepperPluginInstance* instance =
184 content::PepperPluginInstance::Get(instance_id);
185 if (!instance)
186 return;
187 instance->GetRenderView()->DidStartLoading();
190 void DidStopLoading(PP_Instance instance_id) {
191 content::PepperPluginInstance* instance =
192 content::PepperPluginInstance::Get(instance_id);
193 if (!instance)
194 return;
195 instance->GetRenderView()->DidStopLoading();
198 void SetContentRestriction(PP_Instance instance_id, int restrictions) {
199 content::PepperPluginInstance* instance =
200 content::PepperPluginInstance::Get(instance_id);
201 if (!instance)
202 return;
203 instance->GetRenderView()->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
204 instance->GetRenderView()->GetRoutingID(), restrictions));
207 void HistogramPDFPageCount(PP_Instance instance, int count) {
208 UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
211 void UserMetricsRecordAction(PP_Instance instance, PP_Var action) {
212 scoped_refptr<ppapi::StringVar> action_str(
213 ppapi::StringVar::FromPPVar(action));
214 if (action_str.get())
215 content::RenderThread::Get()->RecordComputedAction(action_str->value());
218 void HasUnsupportedFeature(PP_Instance instance_id) {
219 content::PepperPluginInstance* instance =
220 content::PepperPluginInstance::Get(instance_id);
221 if (!instance)
222 return;
224 // Only want to show an info bar if the pdf is the whole tab.
225 if (!instance->IsFullPagePlugin())
226 return;
228 blink::WebView* view =
229 instance->GetContainer()->element().document().frame()->view();
230 content::RenderView* render_view = content::RenderView::FromWebView(view);
231 render_view->Send(
232 new PDFHostMsg_PDFHasUnsupportedFeature(render_view->GetRoutingID()));
235 void SaveAs(PP_Instance instance_id) {
236 content::PepperPluginInstance* instance =
237 content::PepperPluginInstance::Get(instance_id);
238 if (!instance)
239 return;
240 GURL url = instance->GetPluginURL();
242 content::RenderView* render_view = instance->GetRenderView();
243 blink::WebLocalFrame* frame =
244 render_view->GetWebView()->mainFrame()->toWebLocalFrame();
245 content::Referrer referrer(frame->document().url(),
246 frame->document().referrerPolicy());
247 render_view->Send(
248 new PDFHostMsg_PDFSaveURLAs(render_view->GetRoutingID(), url, referrer));
251 void Print(PP_Instance instance) {
252 PPB_PDF_Impl::InvokePrintingForInstance(instance);
255 PP_Bool IsFeatureEnabled(PP_Instance instance, PP_PDFFeature feature) {
256 switch (feature) {
257 case PP_PDFFEATURE_HIDPI:
258 return PP_TRUE;
259 case PP_PDFFEATURE_PRINTING:
260 return (g_print_client && g_print_client->IsPrintingEnabled(instance))
261 ? PP_TRUE
262 : PP_FALSE;
264 return PP_FALSE;
267 PP_Resource GetResourceImageForScale(PP_Instance instance_id,
268 PP_ResourceImage image_id,
269 float scale) {
270 // Validate the instance.
271 content::PepperPluginInstance* instance =
272 content::PepperPluginInstance::Get(instance_id);
273 if (!instance)
274 return 0;
276 gfx::ImageSkia* res_image_skia = GetImageResource(image_id);
278 if (!res_image_skia)
279 return 0;
281 return instance->CreateImage(res_image_skia, scale);
284 PP_Resource GetResourceImage(PP_Instance instance_id,
285 PP_ResourceImage image_id) {
286 return GetResourceImageForScale(instance_id, image_id, 1.0f);
289 PP_Var ModalPromptForPassword(PP_Instance instance_id, PP_Var message) {
290 content::PepperPluginInstance* instance =
291 content::PepperPluginInstance::Get(instance_id);
292 if (!instance)
293 return PP_MakeUndefined();
295 std::string actual_value;
296 scoped_refptr<ppapi::StringVar> message_string(
297 ppapi::StringVar::FromPPVar(message));
299 IPC::SyncMessage* msg = new PDFHostMsg_PDFModalPromptForPassword(
300 instance->GetRenderView()->GetRoutingID(),
301 message_string->value(),
302 &actual_value);
303 msg->EnableMessagePumping();
304 instance->GetRenderView()->Send(msg);
306 return ppapi::StringVar::StringToPPVar(actual_value);
309 PP_Bool IsOutOfProcess(PP_Instance instance_id) {
310 return PP_FALSE;
313 // This function is intended for both in-process and out-of-process pdf.
314 void SetSelectedText(PP_Instance instance_id, const char* selected_text) {
315 content::PepperPluginInstance* instance =
316 content::PepperPluginInstance::Get(instance_id);
317 if (!instance)
318 return;
320 base::string16 selection_text;
321 base::UTF8ToUTF16(selected_text, strlen(selected_text), &selection_text);
322 instance->SetSelectedText(selection_text);
325 void SetLinkUnderCursor(PP_Instance instance_id, const char* url) {
326 content::PepperPluginInstance* instance =
327 content::PepperPluginInstance::Get(instance_id);
328 if (!instance)
329 return;
330 instance->SetLinkUnderCursor(url);
333 void GetV8ExternalSnapshotData(PP_Instance instance_id,
334 const char** natives_data_out,
335 int* natives_size_out,
336 const char** snapshot_data_out,
337 int* snapshot_size_out) {
338 gin::IsolateHolder::GetV8ExternalSnapshotData(natives_data_out,
339 natives_size_out, snapshot_data_out, snapshot_size_out);
342 const PPB_PDF ppb_pdf = { //
343 &GetLocalizedString, //
344 &GetResourceImage, //
345 &GetFontFileWithFallback, //
346 &GetFontTableForPrivateFontFile, //
347 &SearchString, //
348 &DidStartLoading, //
349 &DidStopLoading, //
350 &SetContentRestriction, //
351 &HistogramPDFPageCount, //
352 &UserMetricsRecordAction, //
353 &HasUnsupportedFeature, //
354 &SaveAs, //
355 &Print, //
356 &IsFeatureEnabled, //
357 &GetResourceImageForScale, //
358 &ModalPromptForPassword, //
359 &IsOutOfProcess, //
360 &SetSelectedText, //
361 &SetLinkUnderCursor, //
362 &GetV8ExternalSnapshotData, //
365 } // namespace
367 // static
368 const PPB_PDF* PPB_PDF_Impl::GetInterface() {
369 return &ppb_pdf;
372 // static
373 bool PPB_PDF_Impl::InvokePrintingForInstance(PP_Instance instance_id) {
374 return g_print_client ? g_print_client->Print(instance_id) : false;
377 void PPB_PDF_Impl::SetPrintClient(PPB_PDF_Impl::PrintClient* client) {
378 CHECK(!g_print_client) << "There should only be a single PrintClient.";
379 g_print_client = client;
382 } // namespace pdf