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