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/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"
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()));
52 page
->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
53 filename
, FILE_PATH_LITERAL(".emf")));
55 page
->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
56 filename
, FILE_PATH_LITERAL(".pdf")));
60 void DebugDumpDataTask(const base::string16
& doc_name
,
61 const base::FilePath::StringType
& extension
,
62 const base::RefCountedMemory
* data
) {
64 PrintedDocument::CreateDebugDumpPath(doc_name
, extension
);
68 reinterpret_cast<const char*>(data
->front()),
69 base::checked_cast
<int>(data
->size()));
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(
85 &DebugDumpDataTask
, doc_name
, FILE_PATH_LITERAL(".json"), data
));
90 PrintedDocument::PrintedDocument(const PrintSettings
& settings
,
91 PrintedPagesSource
* source
,
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;
104 if (!g_debug_dump_info
.Get().empty())
105 DebugDumpSettings(name(), settings
, blocking_runner
);
108 PrintedDocument::~PrintedDocument() {
111 void PrintedDocument::SetPage(int page_number
,
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
));
123 page
->set_shrink_factor(shrink
);
126 base::AutoLock
lock(lock_
);
127 mutable_
.pages_
[page_number
] = page
;
129 #if defined(OS_POSIX) && !defined(OS_MACOSX)
130 if (page_number
< mutable_
.first_page
)
131 mutable_
.first_page
= page_number
;
135 if (!g_debug_dump_info
.Get().empty()) {
136 immutable_
.blocking_runner_
->PostTask(
137 FROM_HERE
, base::Bind(&DebugDumpPageTask
, name(), page
));
141 scoped_refptr
<PrintedPage
> PrintedDocument::GetPage(int page_number
) {
142 scoped_refptr
<PrintedPage
> page
;
144 base::AutoLock
lock(lock_
);
145 PrintedPages::const_iterator itr
= mutable_
.pages_
.find(page_number
);
146 if (itr
!= mutable_
.pages_
.end())
152 bool PrintedDocument::IsComplete() const {
153 base::AutoLock
lock(lock_
);
154 if (!mutable_
.page_count_
)
156 PageNumber
page(immutable_
.settings_
, mutable_
.page_count_
);
157 if (page
== PageNumber::npos())
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
);
166 PrintedPages::const_iterator itr
= mutable_
.pages_
.find(page
.ToInt());
167 if (itr
== mutable_
.pages_
.end() || !itr
->second
.get())
169 if (metafile_must_be_valid
&& !itr
->second
->metafile())
175 void PrintedDocument::DisconnectSource() {
176 base::AutoLock
lock(lock_
);
177 mutable_
.source_
= NULL
;
180 uint32
PrintedDocument::MemoryUsage() const {
181 std::vector
< scoped_refptr
<PrintedPage
> > pages_copy
;
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();
188 if (itr
->second
.get()) {
189 pages_copy
.push_back(itr
->second
);
194 for (size_t i
= 0; i
< pages_copy
.size(); ++i
) {
195 total
+= pages_copy
[i
]->metafile()->GetDataSize();
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
;
207 // If there is a range, don't bother since expected_page_count_ is already
209 DCHECK_NE(mutable_
.expected_page_count_
, 0);
213 int PrintedDocument::page_count() const {
214 base::AutoLock
lock(lock_
);
215 return mutable_
.page_count_
;
218 int PrintedDocument::expected_page_count() const {
219 base::AutoLock
lock(lock_
);
220 return mutable_
.expected_page_count_
;
223 void PrintedDocument::set_debug_dump_path(
224 const base::FilePath
& debug_dump_path
) {
225 g_debug_dump_info
.Get() = debug_dump_path
;
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
;
241 system_filename
= filename
;
243 system_filename
= base::UTF16ToUTF8(filename
);
245 base::i18n::ReplaceIllegalCharactersInPath(&system_filename
, '_');
246 return g_debug_dump_info
.Get().Append(system_filename
).AddExtension(
250 void PrintedDocument::DebugDumpData(
251 const base::RefCountedMemory
* data
,
252 const base::FilePath::StringType
& extension
) {
253 if (g_debug_dump_info
.Get().empty())
255 immutable_
.blocking_runner_
->PostTask(
256 FROM_HERE
, base::Bind(&DebugDumpDataTask
, name(), extension
, data
));
259 PrintedDocument::Mutable::Mutable(PrintedPagesSource
* source
)
261 expected_page_count_(0),
263 #if defined(OS_POSIX) && !defined(OS_MACOSX)
264 first_page
= INT_MAX
;
268 PrintedDocument::Mutable::~Mutable() {
271 PrintedDocument::Immutable::Immutable(const PrintSettings
& settings
,
272 PrintedPagesSource
* source
,
274 base::TaskRunner
* blocking_runner
)
275 : settings_(settings
),
276 name_(source
->RenderSourceName()),
278 blocking_runner_(blocking_runner
) {
281 PrintedDocument::Immutable::~Immutable() {
284 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
285 // This function is not used on aura linux/chromeos or android.
286 void PrintedDocument::RenderPrintedPage(const PrintedPage
& page
,
287 PrintingContext
* context
) const {
291 } // namespace printing