printing_context_android.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. #include "printing/printing_context_android.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/android/jni_android.h"
  10. #include "base/android/jni_array.h"
  11. #include "base/android/jni_string.h"
  12. #include "base/files/file.h"
  13. #include "base/logging.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/values.h"
  16. #include "printing/metafile.h"
  17. #include "printing/mojom/print.mojom.h"
  18. #include "printing/print_job_constants.h"
  19. #include "printing/printing_jni_headers/PrintingContext_jni.h"
  20. #include "printing/units.h"
  21. #include "third_party/icu/source/i18n/unicode/ulocdata.h"
  22. #include "ui/android/window_android.h"
  23. using base::android::JavaParamRef;
  24. using base::android::JavaRef;
  25. using base::android::ScopedJavaLocalRef;
  26. namespace printing {
  27. namespace {
  28. // Sets the page sizes for a `PrintSettings` object. `width` and `height`
  29. // arguments should be in device units.
  30. void SetSizes(PrintSettings* settings, int dpi, int width, int height) {
  31. gfx::Size physical_size_device_units(width, height);
  32. // Assume full page is printable for now.
  33. gfx::Rect printable_area_device_units(0, 0, width, height);
  34. settings->set_dpi(dpi);
  35. settings->SetPrinterPrintableArea(physical_size_device_units,
  36. printable_area_device_units, false);
  37. }
  38. void GetPageRanges(JNIEnv* env,
  39. const JavaRef<jintArray>& int_arr,
  40. PageRanges* range_vector) {
  41. std::vector<int> pages;
  42. base::android::JavaIntArrayToIntVector(env, int_arr, &pages);
  43. for (int page : pages) {
  44. PageRange range;
  45. range.from = page;
  46. range.to = page;
  47. range_vector->push_back(range);
  48. }
  49. }
  50. } // namespace
  51. // static
  52. std::unique_ptr<PrintingContext> PrintingContext::CreateImpl(
  53. Delegate* delegate,
  54. bool skip_system_calls) {
  55. DCHECK(!skip_system_calls);
  56. return std::make_unique<PrintingContextAndroid>(delegate);
  57. }
  58. // static
  59. void PrintingContextAndroid::PdfWritingDone(int page_count) {
  60. JNIEnv* env = base::android::AttachCurrentThread();
  61. Java_PrintingContext_pdfWritingDone(env, page_count);
  62. }
  63. // static
  64. void PrintingContextAndroid::SetPendingPrint(
  65. ui::WindowAndroid* window,
  66. const ScopedJavaLocalRef<jobject>& printable,
  67. int render_process_id,
  68. int render_frame_id) {
  69. JNIEnv* env = base::android::AttachCurrentThread();
  70. Java_PrintingContext_setPendingPrint(env, window->GetJavaObject(), printable,
  71. render_process_id, render_frame_id);
  72. }
  73. PrintingContextAndroid::PrintingContextAndroid(Delegate* delegate)
  74. : PrintingContext(delegate) {
  75. // The constructor is run in the IO thread.
  76. }
  77. PrintingContextAndroid::~PrintingContextAndroid() {}
  78. void PrintingContextAndroid::AskUserForSettings(
  79. int max_pages,
  80. bool has_selection,
  81. bool is_scripted,
  82. PrintSettingsCallback callback) {
  83. // This method is always run in the UI thread.
  84. callback_ = std::move(callback);
  85. JNIEnv* env = base::android::AttachCurrentThread();
  86. if (j_printing_context_.is_null()) {
  87. j_printing_context_.Reset(
  88. Java_PrintingContext_create(env, reinterpret_cast<intptr_t>(this)));
  89. }
  90. if (is_scripted) {
  91. Java_PrintingContext_showPrintDialog(env, j_printing_context_);
  92. } else {
  93. Java_PrintingContext_askUserForSettings(env, j_printing_context_,
  94. max_pages);
  95. }
  96. }
  97. void PrintingContextAndroid::AskUserForSettingsReply(
  98. JNIEnv* env,
  99. const JavaParamRef<jobject>& obj,
  100. jboolean success) {
  101. DCHECK(callback_);
  102. if (!success) {
  103. // TODO(cimamoglu): Differentiate between `kFailed` And `kCancel`.
  104. std::move(callback_).Run(mojom::ResultCode::kFailed);
  105. return;
  106. }
  107. // We use device name variable to store the file descriptor. This is hacky
  108. // but necessary. Since device name is not necessary for the upstream
  109. // printing code for Android, this is harmless.
  110. // TODO(thestig): See if the call to set_device_name() can be removed.
  111. fd_ = Java_PrintingContext_getFileDescriptor(env, j_printing_context_);
  112. DCHECK(is_file_descriptor_valid());
  113. settings_->set_device_name(base::NumberToString16(fd_));
  114. ScopedJavaLocalRef<jintArray> intArr =
  115. Java_PrintingContext_getPages(env, j_printing_context_);
  116. if (!intArr.is_null()) {
  117. PageRanges range_vector;
  118. GetPageRanges(env, intArr, &range_vector);
  119. settings_->set_ranges(range_vector);
  120. }
  121. int dpi = Java_PrintingContext_getDpi(env, j_printing_context_);
  122. int width = Java_PrintingContext_getWidth(env, j_printing_context_);
  123. int height = Java_PrintingContext_getHeight(env, j_printing_context_);
  124. width = ConvertUnit(width, kMilsPerInch, dpi);
  125. height = ConvertUnit(height, kMilsPerInch, dpi);
  126. SetSizes(settings_.get(), dpi, width, height);
  127. std::move(callback_).Run(mojom::ResultCode::kSuccess);
  128. }
  129. void PrintingContextAndroid::ShowSystemDialogDone(
  130. JNIEnv* env,
  131. const JavaParamRef<jobject>& obj) {
  132. DCHECK(callback_);
  133. // Settings are not updated, callback is called only to unblock javascript.
  134. std::move(callback_).Run(mojom::ResultCode::kCanceled);
  135. }
  136. mojom::ResultCode PrintingContextAndroid::UseDefaultSettings() {
  137. DCHECK(!in_print_job_);
  138. ResetSettings();
  139. settings_->set_dpi(kDefaultPdfDpi);
  140. gfx::Size physical_size = GetPdfPaperSizeDeviceUnits();
  141. SetSizes(settings_.get(), kDefaultPdfDpi, physical_size.width(),
  142. physical_size.height());
  143. return mojom::ResultCode::kSuccess;
  144. }
  145. gfx::Size PrintingContextAndroid::GetPdfPaperSizeDeviceUnits() {
  146. // NOTE: This implementation is the same as in PrintingContextNoSystemDialog.
  147. int32_t width = 0;
  148. int32_t height = 0;
  149. UErrorCode error = U_ZERO_ERROR;
  150. ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
  151. &error);
  152. if (error > U_ZERO_ERROR) {
  153. // If the call failed, assume a paper size of 8.5 x 11 inches.
  154. LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
  155. << error;
  156. width =
  157. static_cast<int>(kLetterWidthInch * settings_->device_units_per_inch());
  158. height = static_cast<int>(kLetterHeightInch *
  159. settings_->device_units_per_inch());
  160. } else {
  161. // ulocdata_getPaperSize returns the width and height in mm.
  162. // Convert this to pixels based on the dpi.
  163. float multiplier = settings_->device_units_per_inch() / kMicronsPerMil;
  164. width *= multiplier;
  165. height *= multiplier;
  166. }
  167. return gfx::Size(width, height);
  168. }
  169. mojom::ResultCode PrintingContextAndroid::UpdatePrinterSettings(
  170. const PrinterSettings& printer_settings) {
  171. DCHECK(!printer_settings.show_system_dialog);
  172. DCHECK(!in_print_job_);
  173. // Intentional No-op.
  174. return mojom::ResultCode::kSuccess;
  175. }
  176. mojom::ResultCode PrintingContextAndroid::NewDocument(
  177. const std::u16string& document_name) {
  178. DCHECK(!in_print_job_);
  179. in_print_job_ = true;
  180. return mojom::ResultCode::kSuccess;
  181. }
  182. mojom::ResultCode PrintingContextAndroid::PrintDocument(
  183. const MetafilePlayer& metafile,
  184. const PrintSettings& settings,
  185. uint32_t num_pages) {
  186. if (abort_printing_)
  187. return mojom::ResultCode::kCanceled;
  188. DCHECK(in_print_job_);
  189. DCHECK(is_file_descriptor_valid());
  190. return metafile.SaveToFileDescriptor(fd_) ? mojom::ResultCode::kSuccess
  191. : mojom::ResultCode::kFailed;
  192. }
  193. mojom::ResultCode PrintingContextAndroid::DocumentDone() {
  194. if (abort_printing_)
  195. return mojom::ResultCode::kCanceled;
  196. DCHECK(in_print_job_);
  197. ResetSettings();
  198. return mojom::ResultCode::kSuccess;
  199. }
  200. void PrintingContextAndroid::Cancel() {
  201. abort_printing_ = true;
  202. in_print_job_ = false;
  203. }
  204. void PrintingContextAndroid::ReleaseContext() {
  205. // Intentional No-op.
  206. }
  207. printing::NativeDrawingContext PrintingContextAndroid::context() const {
  208. // Intentional No-op.
  209. return nullptr;
  210. }
  211. } // namespace printing