Home | History | Annotate | Download | only in printing
      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