blob: 64139c8bfb837c708d0002bf4f85ff707a28e44e [file] [log] [blame]
[email protected]b6f76a12013-11-14 17:29:241// 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
Vitaly Bukabd7c9812014-08-26 08:57:5464scoped_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
65 return make_scoped_ptr<PrintingContext>(new PrintingContextAndroid(delegate));
[email protected]b6f76a12013-11-14 17:29:2466}
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
Vitaly Bukabd7c9812014-08-26 08:57:5474PrintingContextAndroid::PrintingContextAndroid(Delegate* delegate)
75 : PrintingContext(delegate) {
[email protected]b6f76a12013-11-14 17:29:2476 // The constructor is run in the IO thread.
77}
78
79PrintingContextAndroid::~PrintingContextAndroid() {
80}
81
82void PrintingContextAndroid::AskUserForSettings(
[email protected]b6f76a12013-11-14 17:29:2483 int max_pages,
84 bool has_selection,
85 const PrintSettingsCallback& callback) {
86 // This method is always run in the UI thread.
87 callback_ = callback;
88
89 JNIEnv* env = base::android::AttachCurrentThread();
90 if (j_printing_context_.is_null()) {
91 j_printing_context_.Reset(Java_PrintingContext_create(
92 env,
[email protected]879517bd2013-11-22 20:36:3193 reinterpret_cast<intptr_t>(this)));
[email protected]b6f76a12013-11-14 17:29:2494 }
95
96 Java_PrintingContext_pageCountEstimationDone(env,
97 j_printing_context_.obj(),
98 max_pages);
99}
100
101void PrintingContextAndroid::AskUserForSettingsReply(JNIEnv* env,
102 jobject obj,
103 jboolean success) {
104 if (!success) {
105 // TODO(cimamoglu): Differentiate between FAILED And CANCEL.
106 callback_.Run(FAILED);
107 return;
108 }
109
110 // We use device name variable to store the file descriptor. This is hacky
111 // but necessary. Since device name is not necessary for the upstream
112 // printing code for Android, this is harmless.
113 int fd = Java_PrintingContext_getFileDescriptor(env,
114 j_printing_context_.obj());
115 settings_.set_device_name(base::IntToString16(fd));
116
117 ScopedJavaLocalRef<jintArray> intArr =
118 Java_PrintingContext_getPages(env, j_printing_context_.obj());
119 if (intArr.obj() != NULL) {
120 PageRanges range_vector;
121 GetPageRanges(env, intArr.obj(), range_vector);
122 settings_.set_ranges(range_vector);
123 }
124
125 int dpi = Java_PrintingContext_getDpi(env, j_printing_context_.obj());
126 int width = Java_PrintingContext_getWidth(env, j_printing_context_.obj());
127 int height = Java_PrintingContext_getHeight(env, j_printing_context_.obj());
128 width = Round(ConvertUnitDouble(width, kInchToMil, 1.0) * dpi);
129 height = Round(ConvertUnitDouble(height, kInchToMil, 1.0) * dpi);
130 SetSizes(&settings_, dpi, width, height);
131
132 callback_.Run(OK);
133}
134
135PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() {
136 DCHECK(!in_print_job_);
137
138 ResetSettings();
[email protected]c19b6a62013-11-18 21:53:11139 settings_.set_dpi(kDefaultPdfDpi);
[email protected]b6f76a12013-11-14 17:29:24140 gfx::Size physical_size = GetPdfPaperSizeDeviceUnits();
141 SetSizes(&settings_, kDefaultPdfDpi, physical_size.width(),
142 physical_size.height());
143 return OK;
144}
145
146gfx::Size PrintingContextAndroid::GetPdfPaperSizeDeviceUnits() {
147 // NOTE: This implementation is the same as in PrintingContextNoSystemDialog.
148 int32_t width = 0;
149 int32_t height = 0;
150 UErrorCode error = U_ZERO_ERROR;
Vitaly Bukabd7c9812014-08-26 08:57:54151 ulocdata_getPaperSize(
152 delegate_->GetAppLocale().c_str(), &height, &width, &error);
[email protected]b6f76a12013-11-14 17:29:24153 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(
vitalybuka92ab8ce2014-08-26 23:41:45173 bool external_preview,
174 bool show_system_dialog) {
175 DCHECK(!show_system_dialog);
[email protected]b6f76a12013-11-14 17:29:24176 DCHECK(!in_print_job_);
177
178 // Intentional No-op.
179
180 return OK;
181}
182
183PrintingContext::Result PrintingContextAndroid::InitWithSettings(
184 const PrintSettings& settings) {
185 DCHECK(!in_print_job_);
186
187 settings_ = settings;
188
189 return OK;
190}
191
192PrintingContext::Result PrintingContextAndroid::NewDocument(
[email protected]90007a52013-12-19 23:28:07193 const base::string16& document_name) {
[email protected]b6f76a12013-11-14 17:29:24194 DCHECK(!in_print_job_);
195 in_print_job_ = true;
196
197 return OK;
198}
199
200PrintingContext::Result PrintingContextAndroid::NewPage() {
201 if (abort_printing_)
202 return CANCEL;
203 DCHECK(in_print_job_);
204
205 // Intentional No-op.
206
207 return OK;
208}
209
210PrintingContext::Result PrintingContextAndroid::PageDone() {
211 if (abort_printing_)
212 return CANCEL;
213 DCHECK(in_print_job_);
214
215 // Intentional No-op.
216
217 return OK;
218}
219
220PrintingContext::Result PrintingContextAndroid::DocumentDone() {
221 if (abort_printing_)
222 return CANCEL;
223 DCHECK(in_print_job_);
224
225 ResetSettings();
226 return OK;
227}
228
229void PrintingContextAndroid::Cancel() {
230 abort_printing_ = true;
231 in_print_job_ = false;
232}
233
234void PrintingContextAndroid::ReleaseContext() {
235 // Intentional No-op.
236}
237
238gfx::NativeDrawingContext PrintingContextAndroid::context() const {
239 // Intentional No-op.
240 return NULL;
241}
242
243// static
244bool PrintingContextAndroid::RegisterPrintingContext(JNIEnv* env) {
245 return RegisterNativesImpl(env);
246}
247
248} // namespace printing