• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <vector>
11 
12 #include "base/bind.h"
13 #include "base/file_util.h"
14 #include "base/files/file_path.h"
15 #include "base/i18n/file_util_icu.h"
16 #include "base/i18n/time_formatting.h"
17 #include "base/json/json_writer.h"
18 #include "base/lazy_instance.h"
19 #include "base/memory/ref_counted_memory.h"
20 #include "base/message_loop/message_loop.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/time/time.h"
26 #include "base/values.h"
27 #include "printing/page_number.h"
28 #include "printing/print_settings_conversion.h"
29 #include "printing/printed_page.h"
30 #include "printing/printed_pages_source.h"
31 #include "printing/units.h"
32 #include "skia/ext/platform_device.h"
33 #include "ui/gfx/font.h"
34 #include "ui/gfx/text_elider.h"
35 
36 namespace printing {
37 
38 namespace {
39 
40 base::LazyInstance<base::FilePath> g_debug_dump_info =
41     LAZY_INSTANCE_INITIALIZER;
42 
DebugDumpPageTask(const base::string16 & doc_name,const PrintedPage * page)43 void DebugDumpPageTask(const base::string16& doc_name,
44                        const PrintedPage* page) {
45   if (g_debug_dump_info.Get().empty())
46     return;
47 
48   base::string16 filename = doc_name;
49   filename +=
50       base::ASCIIToUTF16(base::StringPrintf("_%04d", page->page_number()));
51 #if defined(OS_WIN)
52   page->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
53       filename, FILE_PATH_LITERAL(".emf")));
54 #else   // OS_WIN
55   page->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
56       filename, FILE_PATH_LITERAL(".pdf")));
57 #endif  // OS_WIN
58 }
59 
DebugDumpDataTask(const base::string16 & doc_name,const base::FilePath::StringType & extension,const base::RefCountedMemory * data)60 void DebugDumpDataTask(const base::string16& doc_name,
61                        const base::FilePath::StringType& extension,
62                        const base::RefCountedMemory* data) {
63   base::FilePath path =
64       PrintedDocument::CreateDebugDumpPath(doc_name, extension);
65   if (path.empty())
66     return;
67   base::WriteFile(path,
68                   reinterpret_cast<const char*>(data->front()),
69                   base::checked_cast<int>(data->size()));
70 }
71 
DebugDumpSettings(const base::string16 & doc_name,const PrintSettings & settings,base::TaskRunner * blocking_runner)72 void DebugDumpSettings(const base::string16& doc_name,
73                        const PrintSettings& settings,
74                        base::TaskRunner* blocking_runner) {
75   base::DictionaryValue job_settings;
76   PrintSettingsToJobSettingsDebug(settings, &job_settings);
77   std::string settings_str;
78   base::JSONWriter::WriteWithOptions(
79       &job_settings, base::JSONWriter::OPTIONS_PRETTY_PRINT, &settings_str);
80   scoped_refptr<base::RefCountedMemory> data =
81       base::RefCountedString::TakeString(&settings_str);
82   blocking_runner->PostTask(
83       FROM_HERE,
84       base::Bind(
85           &DebugDumpDataTask, doc_name, FILE_PATH_LITERAL(".json"), data));
86 }
87 
88 }  // namespace
89 
PrintedDocument(const PrintSettings & settings,PrintedPagesSource * source,int cookie,base::TaskRunner * blocking_runner)90 PrintedDocument::PrintedDocument(const PrintSettings& settings,
91                                  PrintedPagesSource* source,
92                                  int cookie,
93                                  base::TaskRunner* blocking_runner)
94     : mutable_(source), immutable_(settings, source, cookie, blocking_runner) {
95   // Records the expected page count if a range is setup.
96   if (!settings.ranges().empty()) {
97     // If there is a range, set the number of page
98     for (unsigned i = 0; i < settings.ranges().size(); ++i) {
99       const PageRange& range = settings.ranges()[i];
100       mutable_.expected_page_count_ += range.to - range.from + 1;
101     }
102   }
103 
104   if (!g_debug_dump_info.Get().empty())
105     DebugDumpSettings(name(), settings, blocking_runner);
106 }
107 
~PrintedDocument()108 PrintedDocument::~PrintedDocument() {
109 }
110 
SetPage(int page_number,Metafile * metafile,double shrink,const gfx::Size & paper_size,const gfx::Rect & page_rect)111 void PrintedDocument::SetPage(int page_number,
112                               Metafile* metafile,
113 #if defined(OS_WIN)
114                               double shrink,
115 #endif  // OS_WIN
116                               const gfx::Size& paper_size,
117                               const gfx::Rect& page_rect) {
118   // Notice the page_number + 1, the reason is that this is the value that will
119   // be shown. Users dislike 0-based counting.
120   scoped_refptr<PrintedPage> page(
121       new PrintedPage(page_number + 1, metafile, paper_size, page_rect));
122 #if defined(OS_WIN)
123   page->set_shrink_factor(shrink);
124 #endif  // OS_WIN
125   {
126     base::AutoLock lock(lock_);
127     mutable_.pages_[page_number] = page;
128 
129 #if defined(OS_POSIX) && !defined(OS_MACOSX)
130     if (page_number < mutable_.first_page)
131       mutable_.first_page = page_number;
132 #endif
133   }
134 
135   if (!g_debug_dump_info.Get().empty()) {
136     immutable_.blocking_runner_->PostTask(
137         FROM_HERE, base::Bind(&DebugDumpPageTask, name(), page));
138   }
139 }
140 
GetPage(int page_number)141 scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) {
142   scoped_refptr<PrintedPage> page;
143   {
144     base::AutoLock lock(lock_);
145     PrintedPages::const_iterator itr = mutable_.pages_.find(page_number);
146     if (itr != mutable_.pages_.end())
147       page = itr->second;
148   }
149   return page;
150 }
151 
IsComplete() const152 bool PrintedDocument::IsComplete() const {
153   base::AutoLock lock(lock_);
154   if (!mutable_.page_count_)
155     return false;
156   PageNumber page(immutable_.settings_, mutable_.page_count_);
157   if (page == PageNumber::npos())
158     return false;
159 
160   for (; page != PageNumber::npos(); ++page) {
161 #if defined(OS_WIN) || defined(OS_MACOSX)
162     const bool metafile_must_be_valid = true;
163 #elif defined(OS_POSIX)
164     const bool metafile_must_be_valid = (page.ToInt() == mutable_.first_page);
165 #endif
166     PrintedPages::const_iterator itr = mutable_.pages_.find(page.ToInt());
167     if (itr == mutable_.pages_.end() || !itr->second.get())
168       return false;
169     if (metafile_must_be_valid && !itr->second->metafile())
170       return false;
171   }
172   return true;
173 }
174 
DisconnectSource()175 void PrintedDocument::DisconnectSource() {
176   base::AutoLock lock(lock_);
177   mutable_.source_ = NULL;
178 }
179 
MemoryUsage() const180 uint32 PrintedDocument::MemoryUsage() const {
181   std::vector< scoped_refptr<PrintedPage> > pages_copy;
182   {
183     base::AutoLock lock(lock_);
184     pages_copy.reserve(mutable_.pages_.size());
185     PrintedPages::const_iterator end = mutable_.pages_.end();
186     for (PrintedPages::const_iterator itr = mutable_.pages_.begin();
187          itr != end; ++itr) {
188       if (itr->second.get()) {
189         pages_copy.push_back(itr->second);
190       }
191     }
192   }
193   uint32 total = 0;
194   for (size_t i = 0; i < pages_copy.size(); ++i) {
195     total += pages_copy[i]->metafile()->GetDataSize();
196   }
197   return total;
198 }
199 
set_page_count(int max_page)200 void PrintedDocument::set_page_count(int max_page) {
201   base::AutoLock lock(lock_);
202   DCHECK_EQ(0, mutable_.page_count_);
203   mutable_.page_count_ = max_page;
204   if (immutable_.settings_.ranges().empty()) {
205     mutable_.expected_page_count_ = max_page;
206   } else {
207     // If there is a range, don't bother since expected_page_count_ is already
208     // initialized.
209     DCHECK_NE(mutable_.expected_page_count_, 0);
210   }
211 }
212 
page_count() const213 int PrintedDocument::page_count() const {
214   base::AutoLock lock(lock_);
215   return mutable_.page_count_;
216 }
217 
expected_page_count() const218 int PrintedDocument::expected_page_count() const {
219   base::AutoLock lock(lock_);
220   return mutable_.expected_page_count_;
221 }
222 
set_debug_dump_path(const base::FilePath & debug_dump_path)223 void PrintedDocument::set_debug_dump_path(
224     const base::FilePath& debug_dump_path) {
225   g_debug_dump_info.Get() = debug_dump_path;
226 }
227 
CreateDebugDumpPath(const base::string16 & document_name,const base::FilePath::StringType & extension)228 base::FilePath PrintedDocument::CreateDebugDumpPath(
229     const base::string16& document_name,
230     const base::FilePath::StringType& extension) {
231   if (g_debug_dump_info.Get().empty())
232     return base::FilePath();
233   // Create a filename.
234   base::string16 filename;
235   base::Time now(base::Time::Now());
236   filename = base::TimeFormatShortDateAndTime(now);
237   filename += base::ASCIIToUTF16("_");
238   filename += document_name;
239   base::FilePath::StringType system_filename;
240 #if defined(OS_WIN)
241   system_filename = filename;
242 #else   // OS_WIN
243   system_filename = base::UTF16ToUTF8(filename);
244 #endif  // OS_WIN
245   file_util::ReplaceIllegalCharactersInPath(&system_filename, '_');
246   return g_debug_dump_info.Get().Append(system_filename).AddExtension(
247       extension);
248 }
249 
DebugDumpData(const base::RefCountedMemory * data,const base::FilePath::StringType & extension)250 void PrintedDocument::DebugDumpData(
251     const base::RefCountedMemory* data,
252     const base::FilePath::StringType& extension) {
253   if (g_debug_dump_info.Get().empty())
254     return;
255   immutable_.blocking_runner_->PostTask(
256       FROM_HERE, base::Bind(&DebugDumpDataTask, name(), extension, data));
257 }
258 
Mutable(PrintedPagesSource * source)259 PrintedDocument::Mutable::Mutable(PrintedPagesSource* source)
260     : source_(source),
261       expected_page_count_(0),
262       page_count_(0) {
263 #if defined(OS_POSIX) && !defined(OS_MACOSX)
264   first_page = INT_MAX;
265 #endif
266 }
267 
~Mutable()268 PrintedDocument::Mutable::~Mutable() {
269 }
270 
Immutable(const PrintSettings & settings,PrintedPagesSource * source,int cookie,base::TaskRunner * blocking_runner)271 PrintedDocument::Immutable::Immutable(const PrintSettings& settings,
272                                       PrintedPagesSource* source,
273                                       int cookie,
274                                       base::TaskRunner* blocking_runner)
275     : settings_(settings),
276       name_(source->RenderSourceName()),
277       cookie_(cookie),
278       blocking_runner_(blocking_runner) {
279 }
280 
~Immutable()281 PrintedDocument::Immutable::~Immutable() {
282 }
283 
284 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
285 // This function is not used on aura linux/chromeos or android.
RenderPrintedPage(const PrintedPage & page,PrintingContext * context) const286 void PrintedDocument::RenderPrintedPage(const PrintedPage& page,
287                                         PrintingContext* context) const {
288 }
289 #endif
290 
291 }  // namespace printing
292