1// Copyright (c) 2013 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 "ppapi/proxy/pdf_resource.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10#include "base/command_line.h"
11#include "base/metrics/histogram.h"
12#include "base/strings/utf_string_conversions.h"
13#include "ppapi/c/pp_errors.h"
14#include "ppapi/c/private/ppb_pdf.h"
15#include "ppapi/proxy/ppapi_messages.h"
16#include "ppapi/proxy/ppb_image_data_proxy.h"
17#include "ppapi/shared_impl/var.h"
18#include "third_party/icu/source/i18n/unicode/usearch.h"
19
20namespace ppapi {
21namespace proxy {
22
23namespace {
24
25// TODO(raymes): This is just copied from render_thread_impl.cc. We should have
26// generic code somewhere to get the locale in the plugin.
27std::string GetLocale() {
28  // The browser process should have passed the locale to the plugin via the
29  // --lang command line flag.
30  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
31  const std::string& lang = parsed_command_line.GetSwitchValueASCII("lang");
32  DCHECK(!lang.empty());
33  return lang;
34}
35
36}  // namespace
37
38PDFResource::PDFResource(Connection connection, PP_Instance instance)
39    : PluginResource(connection, instance) {
40  SendCreate(RENDERER, PpapiHostMsg_PDF_Create());
41}
42
43PDFResource::~PDFResource() {
44}
45
46thunk::PPB_PDF_API* PDFResource::AsPPB_PDF_API() {
47  return this;
48}
49
50PP_Var PDFResource::GetLocalizedString(PP_ResourceString string_id) {
51  std::string localized_string;
52  int32_t result = SyncCall<PpapiPluginMsg_PDF_GetLocalizedStringReply>(
53      RENDERER, PpapiHostMsg_PDF_GetLocalizedString(string_id),
54      &localized_string);
55  if (result != PP_OK)
56    return PP_MakeUndefined();
57  return ppapi::StringVar::StringToPPVar(localized_string);
58}
59
60void PDFResource::SearchString(const unsigned short* input_string,
61                               const unsigned short* input_term,
62                               bool case_sensitive,
63                               PP_PrivateFindResult** results, int* count) {
64  if (locale_.empty())
65    locale_ = GetLocale();
66  const base::char16* string =
67      reinterpret_cast<const base::char16*>(input_string);
68  const base::char16* term =
69      reinterpret_cast<const base::char16*>(input_term);
70
71  UErrorCode status = U_ZERO_ERROR;
72  UStringSearch* searcher = usearch_open(term, -1, string, -1, locale_.c_str(),
73                                         0, &status);
74  DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
75         status == U_USING_DEFAULT_WARNING);
76  UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
77
78  UCollator* collator = usearch_getCollator(searcher);
79  if (ucol_getStrength(collator) != strength) {
80    ucol_setStrength(collator, strength);
81    usearch_reset(searcher);
82  }
83
84  status = U_ZERO_ERROR;
85  int match_start = usearch_first(searcher, &status);
86  DCHECK(status == U_ZERO_ERROR);
87
88  std::vector<PP_PrivateFindResult> pp_results;
89  while (match_start != USEARCH_DONE) {
90    size_t matched_length = usearch_getMatchedLength(searcher);
91    PP_PrivateFindResult result;
92    result.start_index = match_start;
93    result.length = matched_length;
94    pp_results.push_back(result);
95    match_start = usearch_next(searcher, &status);
96    DCHECK(status == U_ZERO_ERROR);
97  }
98
99  *count = pp_results.size();
100  if (*count) {
101    *results = reinterpret_cast<PP_PrivateFindResult*>(malloc(
102        *count * sizeof(PP_PrivateFindResult)));
103    memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
104  } else {
105    *results = NULL;
106  }
107
108  usearch_close(searcher);
109}
110
111void PDFResource::DidStartLoading() {
112  Post(RENDERER, PpapiHostMsg_PDF_DidStartLoading());
113}
114
115void PDFResource::DidStopLoading() {
116  Post(RENDERER, PpapiHostMsg_PDF_DidStopLoading());
117}
118
119void PDFResource::SetContentRestriction(int restrictions) {
120  Post(RENDERER, PpapiHostMsg_PDF_SetContentRestriction(restrictions));
121}
122
123void PDFResource::HistogramPDFPageCount(int count) {
124  UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
125}
126
127void PDFResource::UserMetricsRecordAction(const PP_Var& action) {
128  scoped_refptr<ppapi::StringVar> action_str(
129      ppapi::StringVar::FromPPVar(action));
130  if (action_str.get()) {
131    Post(RENDERER,
132         PpapiHostMsg_PDF_UserMetricsRecordAction(action_str->value()));
133  }
134}
135
136void PDFResource::HasUnsupportedFeature() {
137  Post(RENDERER, PpapiHostMsg_PDF_HasUnsupportedFeature());
138}
139
140void PDFResource::Print() {
141  Post(RENDERER, PpapiHostMsg_PDF_Print());
142}
143
144void PDFResource::SaveAs() {
145  Post(RENDERER, PpapiHostMsg_PDF_SaveAs());
146}
147
148PP_Bool PDFResource::IsFeatureEnabled(PP_PDFFeature feature) {
149  PP_Bool result = PP_FALSE;
150  switch (feature) {
151    case PP_PDFFEATURE_HIDPI:
152      result = PP_TRUE;
153      break;
154    case PP_PDFFEATURE_PRINTING:
155      // TODO(raymes): Use PrintWebViewHelper::IsPrintingEnabled.
156      result = PP_FALSE;
157      break;
158  }
159  return result;
160}
161
162PP_Resource PDFResource::GetResourceImageForScale(PP_ResourceImage image_id,
163                                                  float scale) {
164  IPC::Message reply;
165  ResourceMessageReplyParams reply_params;
166  int32_t result = GenericSyncCall(
167      RENDERER, PpapiHostMsg_PDF_GetResourceImage(image_id, scale), &reply,
168      &reply_params);
169  if (result != PP_OK)
170    return 0;
171
172  HostResource resource;
173  PP_ImageDataDesc image_desc;
174  if (!UnpackMessage<PpapiPluginMsg_PDF_GetResourceImageReply>(
175      reply, &resource, &image_desc)) {
176    return 0;
177  }
178
179  if (resource.is_null())
180    return 0;
181  if (!PPB_ImageData_Shared::IsImageDataDescValid(image_desc))
182    return 0;
183
184  base::SharedMemoryHandle handle;
185  if (!reply_params.TakeSharedMemoryHandleAtIndex(0, &handle))
186    return 0;
187  return (new SimpleImageData(resource, image_desc, handle))->GetReference();
188}
189
190PP_Resource PDFResource::GetResourceImage(PP_ResourceImage image_id) {
191  return GetResourceImageForScale(image_id, 1.0f);
192}
193
194PP_Bool PDFResource::IsOutOfProcess() {
195  return PP_TRUE;
196}
197
198void PDFResource::SetSelectedText(const char* selected_text) {
199  Post(RENDERER,
200       PpapiHostMsg_PDF_SetSelectedText(base::UTF8ToUTF16(selected_text)));
201}
202
203void PDFResource::SetLinkUnderCursor(const char* url) {
204  Post(RENDERER, PpapiHostMsg_PDF_SetLinkUnderCursor(url));
205}
206
207}  // namespace proxy
208}  // namespace ppapi
209