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 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