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 scoped_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) { 65 return make_scoped_ptr<PrintingContext>(new PrintingContextAndroid(delegate)); 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(Delegate* delegate) 75 : PrintingContext(delegate) { 76 // The constructor is run in the IO thread. 77 } 78 79 PrintingContextAndroid::~PrintingContextAndroid() { 80 } 81 82 void PrintingContextAndroid::AskUserForSettings( 83 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, 93 reinterpret_cast<intptr_t>(this))); 94 } 95 96 Java_PrintingContext_pageCountEstimationDone(env, 97 j_printing_context_.obj(), 98 max_pages); 99 } 100 101 void 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 135 PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() { 136 DCHECK(!in_print_job_); 137 138 ResetSettings(); 139 settings_.set_dpi(kDefaultPdfDpi); 140 gfx::Size physical_size = GetPdfPaperSizeDeviceUnits(); 141 SetSizes(&settings_, kDefaultPdfDpi, physical_size.width(), 142 physical_size.height()); 143 return OK; 144 } 145 146 gfx::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; 151 ulocdata_getPaperSize( 152 delegate_->GetAppLocale().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 bool show_system_dialog) { 175 DCHECK(!show_system_dialog); 176 DCHECK(!in_print_job_); 177 178 // Intentional No-op. 179 180 return OK; 181 } 182 183 PrintingContext::Result PrintingContextAndroid::InitWithSettings( 184 const PrintSettings& settings) { 185 DCHECK(!in_print_job_); 186 187 settings_ = settings; 188 189 return OK; 190 } 191 192 PrintingContext::Result PrintingContextAndroid::NewDocument( 193 const base::string16& document_name) { 194 DCHECK(!in_print_job_); 195 in_print_job_ = true; 196 197 return OK; 198 } 199 200 PrintingContext::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 210 PrintingContext::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 220 PrintingContext::Result PrintingContextAndroid::DocumentDone() { 221 if (abort_printing_) 222 return CANCEL; 223 DCHECK(in_print_job_); 224 225 ResetSettings(); 226 return OK; 227 } 228 229 void PrintingContextAndroid::Cancel() { 230 abort_printing_ = true; 231 in_print_job_ = false; 232 } 233 234 void PrintingContextAndroid::ReleaseContext() { 235 // Intentional No-op. 236 } 237 238 gfx::NativeDrawingContext PrintingContextAndroid::context() const { 239 // Intentional No-op. 240 return NULL; 241 } 242 243 // static 244 bool PrintingContextAndroid::RegisterPrintingContext(JNIEnv* env) { 245 return RegisterNativesImpl(env); 246 } 247 248 } // namespace printing 249