printed_document.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright (c) 2011 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/printed_document.h"
  5. #include <algorithm>
  6. #include <set>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/bind.h"
  11. #include "base/files/file_path.h"
  12. #include "base/files/file_util.h"
  13. #include "base/i18n/file_util_icu.h"
  14. #include "base/i18n/time_formatting.h"
  15. #include "base/json/json_writer.h"
  16. #include "base/lazy_instance.h"
  17. #include "base/memory/ref_counted_memory.h"
  18. #include "base/numerics/safe_conversions.h"
  19. #include "base/strings/string_util.h"
  20. #include "base/strings/stringprintf.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "base/task/thread_pool.h"
  23. #include "base/time/time.h"
  24. #include "base/values.h"
  25. #include "build/build_config.h"
  26. #include "printing/metafile.h"
  27. #include "printing/page_number.h"
  28. #include "printing/print_settings_conversion.h"
  29. #include "printing/printing_context.h"
  30. #include "printing/units.h"
  31. #include "ui/gfx/font.h"
  32. #include "ui/gfx/text_elider.h"
  33. #if BUILDFLAG(IS_WIN)
  34. #include "printing/printed_page_win.h"
  35. #endif
  36. namespace printing {
  37. namespace {
  38. base::LazyInstance<base::FilePath>::Leaky g_debug_dump_info =
  39. LAZY_INSTANCE_INITIALIZER;
  40. #if BUILDFLAG(IS_WIN)
  41. void DebugDumpPageTask(const std::u16string& doc_name,
  42. const PrintedPage* page) {
  43. DCHECK(PrintedDocument::HasDebugDumpPath());
  44. static constexpr base::FilePath::CharType kExtension[] =
  45. FILE_PATH_LITERAL(".emf");
  46. std::u16string name = doc_name;
  47. name += base::ASCIIToUTF16(base::StringPrintf("_%04d", page->page_number()));
  48. base::FilePath path = PrintedDocument::CreateDebugDumpPath(name, kExtension);
  49. base::File file(path,
  50. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  51. page->metafile()->SaveTo(&file);
  52. }
  53. #endif // BUILDFLAG(IS_WIN)
  54. void DebugDumpTask(const std::u16string& doc_name,
  55. const MetafilePlayer* metafile) {
  56. DCHECK(PrintedDocument::HasDebugDumpPath());
  57. static constexpr base::FilePath::CharType kExtension[] =
  58. FILE_PATH_LITERAL(".pdf");
  59. std::u16string name = doc_name;
  60. base::FilePath path = PrintedDocument::CreateDebugDumpPath(name, kExtension);
  61. base::File file(path,
  62. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  63. #if BUILDFLAG(IS_ANDROID)
  64. metafile->SaveToFileDescriptor(file.GetPlatformFile());
  65. #else
  66. metafile->SaveTo(&file);
  67. #endif // BUILDFLAG(IS_ANDROID)
  68. }
  69. void DebugDumpDataTask(const std::u16string& doc_name,
  70. const base::FilePath::StringType& extension,
  71. const base::RefCountedMemory* data) {
  72. base::FilePath path =
  73. PrintedDocument::CreateDebugDumpPath(doc_name, extension);
  74. if (path.empty())
  75. return;
  76. base::WriteFile(path, *data);
  77. }
  78. void DebugDumpSettings(const std::u16string& doc_name,
  79. const PrintSettings& settings) {
  80. base::Value job_settings(PrintSettingsToJobSettingsDebug(settings));
  81. std::string settings_str;
  82. base::JSONWriter::WriteWithOptions(
  83. job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str);
  84. scoped_refptr<base::RefCountedMemory> data =
  85. base::RefCountedString::TakeString(&settings_str);
  86. base::ThreadPool::PostTask(
  87. FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
  88. base::BindOnce(&DebugDumpDataTask, doc_name, FILE_PATH_LITERAL(".json"),
  89. base::RetainedRef(data)));
  90. }
  91. } // namespace
  92. PrintedDocument::PrintedDocument(std::unique_ptr<PrintSettings> settings,
  93. const std::u16string& name,
  94. int cookie)
  95. : immutable_(std::move(settings), name, cookie) {
  96. // If there is a range, set the number of page
  97. for (const PageRange& range : immutable_.settings_->ranges())
  98. mutable_.expected_page_count_ += range.to - range.from + 1;
  99. if (HasDebugDumpPath())
  100. DebugDumpSettings(name, *immutable_.settings_);
  101. }
  102. PrintedDocument::~PrintedDocument() = default;
  103. #if BUILDFLAG(IS_WIN)
  104. void PrintedDocument::SetConvertingPdf() {
  105. base::AutoLock lock(lock_);
  106. mutable_.converting_pdf_ = true;
  107. }
  108. void PrintedDocument::SetPage(uint32_t page_number,
  109. std::unique_ptr<MetafilePlayer> metafile,
  110. float shrink,
  111. const gfx::Size& page_size,
  112. const gfx::Rect& page_content_rect) {
  113. // Notice the page_number + 1, the reason is that this is the value that will
  114. // be shown. Users dislike 0-based counting.
  115. auto page = base::MakeRefCounted<PrintedPage>(
  116. page_number + 1, std::move(metafile), page_size, page_content_rect);
  117. page->set_shrink_factor(shrink);
  118. {
  119. base::AutoLock lock(lock_);
  120. mutable_.pages_[page_number] = page;
  121. }
  122. if (HasDebugDumpPath()) {
  123. base::ThreadPool::PostTask(
  124. FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
  125. base::BindOnce(&DebugDumpPageTask, name(), base::RetainedRef(page)));
  126. }
  127. }
  128. scoped_refptr<PrintedPage> PrintedDocument::GetPage(uint32_t page_number) {
  129. scoped_refptr<PrintedPage> page;
  130. {
  131. base::AutoLock lock(lock_);
  132. PrintedPages::const_iterator it = mutable_.pages_.find(page_number);
  133. if (it != mutable_.pages_.end())
  134. page = it->second;
  135. }
  136. return page;
  137. }
  138. void PrintedDocument::RemovePage(const PrintedPage* page) {
  139. base::AutoLock lock(lock_);
  140. PrintedPages::const_iterator it =
  141. mutable_.pages_.find(page->page_number() - 1);
  142. DCHECK_EQ(page, it->second.get());
  143. mutable_.pages_.erase(it);
  144. }
  145. #endif // BUILDFLAG(IS_WIN)
  146. void PrintedDocument::SetDocument(std::unique_ptr<MetafilePlayer> metafile) {
  147. {
  148. base::AutoLock lock(lock_);
  149. mutable_.metafile_ = std::move(metafile);
  150. }
  151. if (HasDebugDumpPath()) {
  152. base::ThreadPool::PostTask(
  153. FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
  154. base::BindOnce(&DebugDumpTask, name(), mutable_.metafile_.get()));
  155. }
  156. }
  157. const MetafilePlayer* PrintedDocument::GetMetafile() {
  158. return mutable_.metafile_.get();
  159. }
  160. mojom::ResultCode PrintedDocument::RenderPrintedDocument(
  161. PrintingContext* context) {
  162. base::AutoLock lock(lock_);
  163. mojom::ResultCode result = context->PrintDocument(
  164. *GetMetafile(), *immutable_.settings_, mutable_.expected_page_count_);
  165. if (result != mojom::ResultCode::kSuccess)
  166. return result;
  167. // Beware of any asynchronous aborts of the print job that happened during
  168. // printing.
  169. if (context->PrintingAborted())
  170. return mojom::ResultCode::kCanceled;
  171. return mojom::ResultCode::kSuccess;
  172. }
  173. bool PrintedDocument::IsComplete() const {
  174. base::AutoLock lock(lock_);
  175. if (!mutable_.page_count_)
  176. return false;
  177. #if BUILDFLAG(IS_WIN)
  178. if (mutable_.converting_pdf_)
  179. return true;
  180. PageNumber page(immutable_.settings_->ranges(), mutable_.page_count_);
  181. if (page == PageNumber::npos())
  182. return false;
  183. for (; page != PageNumber::npos(); ++page) {
  184. PrintedPages::const_iterator it = mutable_.pages_.find(page.ToUint());
  185. if (it == mutable_.pages_.end() || !it->second.get() ||
  186. !it->second->metafile()) {
  187. return false;
  188. }
  189. }
  190. return true;
  191. #else
  192. return !!mutable_.metafile_;
  193. #endif
  194. }
  195. void PrintedDocument::set_page_count(uint32_t max_page) {
  196. base::AutoLock lock(lock_);
  197. DCHECK_EQ(0u, mutable_.page_count_);
  198. mutable_.page_count_ = max_page;
  199. if (immutable_.settings_->ranges().empty()) {
  200. mutable_.expected_page_count_ = max_page;
  201. } else {
  202. // If there is a range, don't bother since expected_page_count_ is already
  203. // initialized.
  204. DCHECK_NE(mutable_.expected_page_count_, 0u);
  205. }
  206. }
  207. uint32_t PrintedDocument::page_count() const {
  208. base::AutoLock lock(lock_);
  209. return mutable_.page_count_;
  210. }
  211. uint32_t PrintedDocument::expected_page_count() const {
  212. base::AutoLock lock(lock_);
  213. return mutable_.expected_page_count_;
  214. }
  215. // static
  216. void PrintedDocument::SetDebugDumpPath(const base::FilePath& debug_dump_path) {
  217. DCHECK(!debug_dump_path.empty());
  218. g_debug_dump_info.Get() = debug_dump_path;
  219. }
  220. // static
  221. bool PrintedDocument::HasDebugDumpPath() {
  222. return g_debug_dump_info.IsCreated();
  223. }
  224. // static
  225. base::FilePath PrintedDocument::CreateDebugDumpPath(
  226. const std::u16string& document_name,
  227. const base::FilePath::StringType& extension) {
  228. DCHECK(HasDebugDumpPath());
  229. // Create a filename.
  230. std::u16string filename;
  231. base::Time now(base::Time::Now());
  232. filename = base::TimeFormatShortDateAndTime(now);
  233. filename += u"_";
  234. filename += document_name;
  235. base::FilePath::StringType system_filename;
  236. #if BUILDFLAG(IS_WIN)
  237. system_filename = base::UTF16ToWide(filename);
  238. #else // BUILDFLAG(IS_WIN)
  239. system_filename = base::UTF16ToUTF8(filename);
  240. #endif // BUILDFLAG(IS_WIN)
  241. base::i18n::ReplaceIllegalCharactersInPath(&system_filename, '_');
  242. const auto& dump_path = g_debug_dump_info.Get();
  243. DCHECK(!dump_path.empty());
  244. return dump_path.Append(system_filename).AddExtension(extension);
  245. }
  246. void PrintedDocument::DebugDumpData(
  247. const base::RefCountedMemory* data,
  248. const base::FilePath::StringType& extension) {
  249. DCHECK(HasDebugDumpPath());
  250. base::ThreadPool::PostTask(
  251. FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
  252. base::BindOnce(&DebugDumpDataTask, name(), extension,
  253. base::RetainedRef(data)));
  254. }
  255. PrintedDocument::Mutable::Mutable() = default;
  256. PrintedDocument::Mutable::~Mutable() = default;
  257. PrintedDocument::Immutable::Immutable(std::unique_ptr<PrintSettings> settings,
  258. const std::u16string& name,
  259. int cookie)
  260. : settings_(std::move(settings)), name_(name), cookie_(cookie) {}
  261. PrintedDocument::Immutable::~Immutable() = default;
  262. } // namespace printing