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 21 namespace { 22 23 // 1 inch in mils. 24 const int kInchToMil = 1000; 25 26 inline 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. 32 void 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 44 void 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 61 namespace printing { 62 63 // static 64 PrintingContext* PrintingContext::Create(const std::string& app_locale) { 65 return new PrintingContextAndroid(app_locale); 66 } 67 68 // static 69 void PrintingContextAndroid::PdfWritingDone(int fd, bool success) { 70 JNIEnv* env = base::android::AttachCurrentThread(); 71 Java_PrintingContext_pdfWritingDone(env, fd, success); 72 } 73 74 PrintingContextAndroid::PrintingContextAndroid(const std::string& app_locale) 75 : PrintingContext(app_locale) { 76 // The constructor is run in the IO thread. 77 } 78 79 PrintingContextAndroid::~PrintingContextAndroid() { 80 } 81 82 void 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 102 void 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 136 PrintingContext::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 147 gfx::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 172 PrintingContext::Result PrintingContextAndroid::UpdatePrinterSettings( 173 bool external_preview) { 174 DCHECK(!in_print_job_); 175 176 // Intentional No-op. 177 178 return OK; 179 } 180 181 PrintingContext::Result PrintingContextAndroid::InitWithSettings( 182 const PrintSettings& settings) { 183 DCHECK(!in_print_job_); 184 185 settings_ = settings; 186 187 return OK; 188 } 189 190 PrintingContext::Result PrintingContextAndroid::NewDocument( 191 const string16& document_name) { 192 DCHECK(!in_print_job_); 193 in_print_job_ = true; 194 195 return OK; 196 } 197 198 PrintingContext::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 208 PrintingContext::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 218 PrintingContext::Result PrintingContextAndroid::DocumentDone() { 219 if (abort_printing_) 220 return CANCEL; 221 DCHECK(in_print_job_); 222 223 ResetSettings(); 224 return OK; 225 } 226 227 void PrintingContextAndroid::Cancel() { 228 abort_printing_ = true; 229 in_print_job_ = false; 230 } 231 232 void PrintingContextAndroid::ReleaseContext() { 233 // Intentional No-op. 234 } 235 236 gfx::NativeDrawingContext PrintingContextAndroid::context() const { 237 // Intentional No-op. 238 return NULL; 239 } 240 241 // static 242 bool PrintingContextAndroid::RegisterPrintingContext(JNIEnv* env) { 243 return RegisterNativesImpl(env); 244 } 245 246 } // namespace printing 247