printing_context_android.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 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 "printing/printing_context_android.h"
6
7#include <vector>
8
9#include "base/android/jni_android.h"
10#include "base/android/jni_array.h"
11#include "base/android/jni_string.h"
12#include "base/logging.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/values.h"
15#include "jni/PrintingContext_jni.h"
16#include "printing/metafile.h"
17#include "printing/print_job_constants.h"
18#include "printing/units.h"
19#include "third_party/icu/source/i18n/unicode/ulocdata.h"
20
21namespace {
22
23// 1 inch in mils.
24const int kInchToMil = 1000;
25
26inline int Round(double x) {
27  return static_cast<int>(x + 0.5);
28}
29
30// Sets the page sizes for a |PrintSettings| object.  |width| and |height|
31// arguments should be in device units.
32void SetSizes(
33    printing::PrintSettings* settings, int dpi, int width, int height) {
34  gfx::Size physical_size_device_units(width, height);
35  // Assume full page is printable for now.
36  gfx::Rect printable_area_device_units(0, 0, width, height);
37
38  settings->set_dpi(dpi);
39  settings->SetPrinterPrintableArea(physical_size_device_units,
40                                    printable_area_device_units,
41                                    false);
42}
43
44void GetPageRanges(JNIEnv* env,
45                   jintArray int_arr,
46                   printing::PageRanges& range_vector) {
47  std::vector<int> pages;
48  base::android::JavaIntArrayToIntVector(env, int_arr, &pages);
49  for (std::vector<int>::const_iterator it = pages.begin();
50      it != pages.end();
51      ++it) {
52    printing::PageRange range;
53    range.from = *it;
54    range.to = *it;
55    range_vector.push_back(range);
56  }
57}
58
59}  // namespace
60
61namespace printing {
62
63// static
64PrintingContext* PrintingContext::Create(const std::string& app_locale) {
65  return new PrintingContextAndroid(app_locale);
66}
67
68// static
69void PrintingContextAndroid::PdfWritingDone(int fd, bool success) {
70  JNIEnv* env = base::android::AttachCurrentThread();
71  Java_PrintingContext_pdfWritingDone(env, fd, success);
72}
73
74PrintingContextAndroid::PrintingContextAndroid(const std::string& app_locale)
75    : PrintingContext(app_locale) {
76  // The constructor is run in the IO thread.
77}
78
79PrintingContextAndroid::~PrintingContextAndroid() {
80}
81
82void PrintingContextAndroid::AskUserForSettings(
83    gfx::NativeView parent_view,
84    int max_pages,
85    bool has_selection,
86    const PrintSettingsCallback& callback) {
87  // This method is always run in the UI thread.
88  callback_ = callback;
89
90  JNIEnv* env = base::android::AttachCurrentThread();
91  if (j_printing_context_.is_null()) {
92    j_printing_context_.Reset(Java_PrintingContext_create(
93        env,
94        reinterpret_cast<intptr_t>(this)));
95  }
96
97  Java_PrintingContext_pageCountEstimationDone(env,
98                                               j_printing_context_.obj(),
99                                               max_pages);
100}
101
102void PrintingContextAndroid::AskUserForSettingsReply(JNIEnv* env,
103                                                     jobject obj,
104                                                     jboolean success) {
105  if (!success) {
106    // TODO(cimamoglu): Differentiate between FAILED And CANCEL.
107    callback_.Run(FAILED);
108    return;
109  }
110
111  // We use device name variable to store the file descriptor.  This is hacky
112  // but necessary. Since device name is not necessary for the upstream
113  // printing code for Android, this is harmless.
114  int fd = Java_PrintingContext_getFileDescriptor(env,
115                                                  j_printing_context_.obj());
116  settings_.set_device_name(base::IntToString16(fd));
117
118  ScopedJavaLocalRef<jintArray> intArr =
119      Java_PrintingContext_getPages(env, j_printing_context_.obj());
120  if (intArr.obj() != NULL) {
121    PageRanges range_vector;
122    GetPageRanges(env, intArr.obj(), range_vector);
123    settings_.set_ranges(range_vector);
124  }
125
126  int dpi = Java_PrintingContext_getDpi(env, j_printing_context_.obj());
127  int width = Java_PrintingContext_getWidth(env, j_printing_context_.obj());
128  int height = Java_PrintingContext_getHeight(env, j_printing_context_.obj());
129  width = Round(ConvertUnitDouble(width, kInchToMil, 1.0) * dpi);
130  height = Round(ConvertUnitDouble(height, kInchToMil, 1.0) * dpi);
131  SetSizes(&settings_, dpi, width, height);
132
133  callback_.Run(OK);
134}
135
136PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() {
137  DCHECK(!in_print_job_);
138
139  ResetSettings();
140  settings_.set_dpi(kDefaultPdfDpi);
141  gfx::Size physical_size = GetPdfPaperSizeDeviceUnits();
142  SetSizes(&settings_, kDefaultPdfDpi, physical_size.width(),
143           physical_size.height());
144  return OK;
145}
146
147gfx::Size PrintingContextAndroid::GetPdfPaperSizeDeviceUnits() {
148  // NOTE: This implementation is the same as in PrintingContextNoSystemDialog.
149  int32_t width = 0;
150  int32_t height = 0;
151  UErrorCode error = U_ZERO_ERROR;
152  ulocdata_getPaperSize(app_locale_.c_str(), &height, &width, &error);
153  if (error > U_ZERO_ERROR) {
154    // If the call failed, assume a paper size of 8.5 x 11 inches.
155    LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
156                 << error;
157    width = static_cast<int>(
158        kLetterWidthInch * settings_.device_units_per_inch());
159    height = static_cast<int>(
160        kLetterHeightInch  * settings_.device_units_per_inch());
161  } else {
162    // ulocdata_getPaperSize returns the width and height in mm.
163    // Convert this to pixels based on the dpi.
164    float multiplier = 100 * settings_.device_units_per_inch();
165    multiplier /= kHundrethsMMPerInch;
166    width *= multiplier;
167    height *= multiplier;
168  }
169  return gfx::Size(width, height);
170}
171
172PrintingContext::Result PrintingContextAndroid::UpdatePrinterSettings(
173    bool external_preview) {
174  DCHECK(!in_print_job_);
175
176  // Intentional No-op.
177
178  return OK;
179}
180
181PrintingContext::Result PrintingContextAndroid::InitWithSettings(
182    const PrintSettings& settings) {
183  DCHECK(!in_print_job_);
184
185  settings_ = settings;
186
187  return OK;
188}
189
190PrintingContext::Result PrintingContextAndroid::NewDocument(
191    const string16& document_name) {
192  DCHECK(!in_print_job_);
193  in_print_job_ = true;
194
195  return OK;
196}
197
198PrintingContext::Result PrintingContextAndroid::NewPage() {
199  if (abort_printing_)
200    return CANCEL;
201  DCHECK(in_print_job_);
202
203  // Intentional No-op.
204
205  return OK;
206}
207
208PrintingContext::Result PrintingContextAndroid::PageDone() {
209  if (abort_printing_)
210    return CANCEL;
211  DCHECK(in_print_job_);
212
213  // Intentional No-op.
214
215  return OK;
216}
217
218PrintingContext::Result PrintingContextAndroid::DocumentDone() {
219  if (abort_printing_)
220    return CANCEL;
221  DCHECK(in_print_job_);
222
223  ResetSettings();
224  return OK;
225}
226
227void PrintingContextAndroid::Cancel() {
228  abort_printing_ = true;
229  in_print_job_ = false;
230}
231
232void PrintingContextAndroid::ReleaseContext() {
233  // Intentional No-op.
234}
235
236gfx::NativeDrawingContext PrintingContextAndroid::context() const {
237  // Intentional No-op.
238  return NULL;
239}
240
241// static
242bool PrintingContextAndroid::RegisterPrintingContext(JNIEnv* env) {
243   return RegisterNativesImpl(env);
244}
245
246}  // namespace printing
247