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.
5 #include "printing/printed_document.h"
12 #include "base/bind.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.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"
40 base::LazyInstance
<base::FilePath
> g_debug_dump_info
=
41 LAZY_INSTANCE_INITIALIZER
;
43 void DebugDumpPageTask(const base::string16
& doc_name
,
44 const PrintedPage
* page
) {
45 if (g_debug_dump_info
.Get().empty())
48 base::string16 filename
= doc_name
;
50 base::ASCIIToUTF16(base::StringPrintf("_%04d", page
->page_number()));
51 base::FilePath file_path
=
53 PrintedDocument::CreateDebugDumpPath(filename
, FILE_PATH_LITERAL(".emf"));
55 PrintedDocument::CreateDebugDumpPath(filename
, FILE_PATH_LITERAL(".pdf"));
57 base::File
file(file_path
,
58 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
);
59 page
->metafile()->SaveTo(&file
);
62 void DebugDumpDataTask(const base::string16
& doc_name
,
63 const base::FilePath::StringType
& extension
,
64 const base::RefCountedMemory
* data
) {
66 PrintedDocument::CreateDebugDumpPath(doc_name
, extension
);
70 reinterpret_cast<const char*>(data
->front()),
71 base::checked_cast
<int>(data
->size()));
74 void DebugDumpSettings(const base::string16
& doc_name
,
75 const PrintSettings
& settings
,
76 base::TaskRunner
* blocking_runner
) {
77 base::DictionaryValue job_settings
;
78 PrintSettingsToJobSettingsDebug(settings
, &job_settings
);
79 std::string settings_str
;
80 base::JSONWriter::WriteWithOptions(
81 &job_settings
, base::JSONWriter::OPTIONS_PRETTY_PRINT
, &settings_str
);
82 scoped_refptr
<base::RefCountedMemory
> data
=
83 base::RefCountedString::TakeString(&settings_str
);
84 blocking_runner
->PostTask(
87 &DebugDumpDataTask
, doc_name
, FILE_PATH_LITERAL(".json"), data
));
92 PrintedDocument::PrintedDocument(const PrintSettings
& settings
,
93 PrintedPagesSource
* source
,
95 base::TaskRunner
* blocking_runner
)
96 : mutable_(source
), immutable_(settings
, source
, cookie
, blocking_runner
) {
97 // Records the expected page count if a range is setup.
98 if (!settings
.ranges().empty()) {
99 // If there is a range, set the number of page
100 for (unsigned i
= 0; i
< settings
.ranges().size(); ++i
) {
101 const PageRange
& range
= settings
.ranges()[i
];
102 mutable_
.expected_page_count_
+= range
.to
- range
.from
+ 1;
106 if (!g_debug_dump_info
.Get().empty())
107 DebugDumpSettings(name(), settings
, blocking_runner
);
110 PrintedDocument::~PrintedDocument() {
113 void PrintedDocument::SetPage(int page_number
,
114 scoped_ptr
<MetafilePlayer
> metafile
,
118 const gfx::Size
& paper_size
,
119 const gfx::Rect
& page_rect
) {
120 // Notice the page_number + 1, the reason is that this is the value that will
121 // be shown. Users dislike 0-based counting.
122 scoped_refptr
<PrintedPage
> page(
123 new PrintedPage(page_number
+ 1, metafile
.Pass(), paper_size
, page_rect
));
125 page
->set_shrink_factor(shrink
);
128 base::AutoLock
lock(lock_
);
129 mutable_
.pages_
[page_number
] = page
;
131 #if defined(OS_POSIX) && !defined(OS_MACOSX)
132 if (page_number
< mutable_
.first_page
)
133 mutable_
.first_page
= page_number
;
137 if (!g_debug_dump_info
.Get().empty()) {
138 immutable_
.blocking_runner_
->PostTask(
139 FROM_HERE
, base::Bind(&DebugDumpPageTask
, name(), page
));
143 scoped_refptr
<PrintedPage
> PrintedDocument::GetPage(int page_number
) {
144 scoped_refptr
<PrintedPage
> page
;
146 base::AutoLock
lock(lock_
);
147 PrintedPages::const_iterator itr
= mutable_
.pages_
.find(page_number
);
148 if (itr
!= mutable_
.pages_
.end())
154 bool PrintedDocument::IsComplete() const {
155 base::AutoLock
lock(lock_
);
156 if (!mutable_
.page_count_
)
158 PageNumber
page(immutable_
.settings_
, mutable_
.page_count_
);
159 if (page
== PageNumber::npos())
162 for (; page
!= PageNumber::npos(); ++page
) {
163 #if defined(OS_WIN) || defined(OS_MACOSX)
164 const bool metafile_must_be_valid
= true;
165 #elif defined(OS_POSIX)
166 const bool metafile_must_be_valid
= (page
.ToInt() == mutable_
.first_page
);
168 PrintedPages::const_iterator itr
= mutable_
.pages_
.find(page
.ToInt());
169 if (itr
== mutable_
.pages_
.end() || !itr
->second
.get())
171 if (metafile_must_be_valid
&& !itr
->second
->metafile())
177 void PrintedDocument::DisconnectSource() {
178 base::AutoLock
lock(lock_
);
179 mutable_
.source_
= NULL
;
182 void PrintedDocument::set_page_count(int max_page
) {
183 base::AutoLock
lock(lock_
);
184 DCHECK_EQ(0, mutable_
.page_count_
);
185 mutable_
.page_count_
= max_page
;
186 if (immutable_
.settings_
.ranges().empty()) {
187 mutable_
.expected_page_count_
= max_page
;
189 // If there is a range, don't bother since expected_page_count_ is already
191 DCHECK_NE(mutable_
.expected_page_count_
, 0);
195 int PrintedDocument::page_count() const {
196 base::AutoLock
lock(lock_
);
197 return mutable_
.page_count_
;
200 int PrintedDocument::expected_page_count() const {
201 base::AutoLock
lock(lock_
);
202 return mutable_
.expected_page_count_
;
205 void PrintedDocument::set_debug_dump_path(
206 const base::FilePath
& debug_dump_path
) {
207 g_debug_dump_info
.Get() = debug_dump_path
;
210 base::FilePath
PrintedDocument::CreateDebugDumpPath(
211 const base::string16
& document_name
,
212 const base::FilePath::StringType
& extension
) {
213 if (g_debug_dump_info
.Get().empty())
214 return base::FilePath();
215 // Create a filename.
216 base::string16 filename
;
217 base::Time
now(base::Time::Now());
218 filename
= base::TimeFormatShortDateAndTime(now
);
219 filename
+= base::ASCIIToUTF16("_");
220 filename
+= document_name
;
221 base::FilePath::StringType system_filename
;
223 system_filename
= filename
;
225 system_filename
= base::UTF16ToUTF8(filename
);
227 base::i18n::ReplaceIllegalCharactersInPath(&system_filename
, '_');
228 return g_debug_dump_info
.Get().Append(system_filename
).AddExtension(
232 void PrintedDocument::DebugDumpData(
233 const base::RefCountedMemory
* data
,
234 const base::FilePath::StringType
& extension
) {
235 if (g_debug_dump_info
.Get().empty())
237 immutable_
.blocking_runner_
->PostTask(
238 FROM_HERE
, base::Bind(&DebugDumpDataTask
, name(), extension
, data
));
241 PrintedDocument::Mutable::Mutable(PrintedPagesSource
* source
)
243 expected_page_count_(0),
245 #if defined(OS_POSIX) && !defined(OS_MACOSX)
246 first_page
= INT_MAX
;
250 PrintedDocument::Mutable::~Mutable() {
253 PrintedDocument::Immutable::Immutable(const PrintSettings
& settings
,
254 PrintedPagesSource
* source
,
256 base::TaskRunner
* blocking_runner
)
257 : settings_(settings
),
258 name_(source
->RenderSourceName()),
260 blocking_runner_(blocking_runner
) {
263 PrintedDocument::Immutable::~Immutable() {
266 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
267 // This function is not used on aura linux/chromeos or android.
268 void PrintedDocument::RenderPrintedPage(const PrintedPage
& page
,
269 PrintingContext
* context
) const {
273 } // namespace printing