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/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" 35 36 namespace printing { 37 38 namespace { 39 40 base::LazyInstance<base::FilePath> g_debug_dump_info = 41 LAZY_INSTANCE_INITIALIZER; 42 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 base::FilePath file_path = 52 #if defined(OS_WIN) 53 PrintedDocument::CreateDebugDumpPath(filename, FILE_PATH_LITERAL(".emf")); 54 #else // OS_WIN 55 PrintedDocument::CreateDebugDumpPath(filename, FILE_PATH_LITERAL(".pdf")); 56 #endif // OS_WIN 57 base::File file(file_path, 58 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 59 page->metafile()->SaveTo(&file); 60 } 61 62 void DebugDumpDataTask(const base::string16& doc_name, 63 const base::FilePath::StringType& extension, 64 const base::RefCountedMemory* data) { 65 base::FilePath path = 66 PrintedDocument::CreateDebugDumpPath(doc_name, extension); 67 if (path.empty()) 68 return; 69 base::WriteFile(path, 70 reinterpret_cast<const char*>(data->front()), 71 base::checked_cast<int>(data->size())); 72 } 73 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( 85 FROM_HERE, 86 base::Bind( 87 &DebugDumpDataTask, doc_name, FILE_PATH_LITERAL(".json"), data)); 88 } 89 90 } // namespace 91 92 PrintedDocument::PrintedDocument(const PrintSettings& settings, 93 PrintedPagesSource* source, 94 int cookie, 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; 103 } 104 } 105 106 if (!g_debug_dump_info.Get().empty()) 107 DebugDumpSettings(name(), settings, blocking_runner); 108 } 109 110 PrintedDocument::~PrintedDocument() { 111 } 112 113 void PrintedDocument::SetPage(int page_number, 114 scoped_ptr<MetafilePlayer> metafile, 115 #if defined(OS_WIN) 116 double shrink, 117 #endif // OS_WIN 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)); 124 #if defined(OS_WIN) 125 page->set_shrink_factor(shrink); 126 #endif // OS_WIN 127 { 128 base::AutoLock lock(lock_); 129 mutable_.pages_[page_number] = page; 130 131 #if defined(OS_POSIX) && !defined(OS_MACOSX) 132 if (page_number < mutable_.first_page) 133 mutable_.first_page = page_number; 134 #endif 135 } 136 137 if (!g_debug_dump_info.Get().empty()) { 138 immutable_.blocking_runner_->PostTask( 139 FROM_HERE, base::Bind(&DebugDumpPageTask, name(), page)); 140 } 141 } 142 143 scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) { 144 scoped_refptr<PrintedPage> page; 145 { 146 base::AutoLock lock(lock_); 147 PrintedPages::const_iterator itr = mutable_.pages_.find(page_number); 148 if (itr != mutable_.pages_.end()) 149 page = itr->second; 150 } 151 return page; 152 } 153 154 bool PrintedDocument::IsComplete() const { 155 base::AutoLock lock(lock_); 156 if (!mutable_.page_count_) 157 return false; 158 PageNumber page(immutable_.settings_, mutable_.page_count_); 159 if (page == PageNumber::npos()) 160 return false; 161 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); 167 #endif 168 PrintedPages::const_iterator itr = mutable_.pages_.find(page.ToInt()); 169 if (itr == mutable_.pages_.end() || !itr->second.get()) 170 return false; 171 if (metafile_must_be_valid && !itr->second->metafile()) 172 return false; 173 } 174 return true; 175 } 176 177 void PrintedDocument::DisconnectSource() { 178 base::AutoLock lock(lock_); 179 mutable_.source_ = NULL; 180 } 181 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; 188 } else { 189 // If there is a range, don't bother since expected_page_count_ is already 190 // initialized. 191 DCHECK_NE(mutable_.expected_page_count_, 0); 192 } 193 } 194 195 int PrintedDocument::page_count() const { 196 base::AutoLock lock(lock_); 197 return mutable_.page_count_; 198 } 199 200 int PrintedDocument::expected_page_count() const { 201 base::AutoLock lock(lock_); 202 return mutable_.expected_page_count_; 203 } 204 205 void PrintedDocument::set_debug_dump_path( 206 const base::FilePath& debug_dump_path) { 207 g_debug_dump_info.Get() = debug_dump_path; 208 } 209 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; 222 #if defined(OS_WIN) 223 system_filename = filename; 224 #else // OS_WIN 225 system_filename = base::UTF16ToUTF8(filename); 226 #endif // OS_WIN 227 base::i18n::ReplaceIllegalCharactersInPath(&system_filename, '_'); 228 return g_debug_dump_info.Get().Append(system_filename).AddExtension( 229 extension); 230 } 231 232 void PrintedDocument::DebugDumpData( 233 const base::RefCountedMemory* data, 234 const base::FilePath::StringType& extension) { 235 if (g_debug_dump_info.Get().empty()) 236 return; 237 immutable_.blocking_runner_->PostTask( 238 FROM_HERE, base::Bind(&DebugDumpDataTask, name(), extension, data)); 239 } 240 241 PrintedDocument::Mutable::Mutable(PrintedPagesSource* source) 242 : source_(source), 243 expected_page_count_(0), 244 page_count_(0) { 245 #if defined(OS_POSIX) && !defined(OS_MACOSX) 246 first_page = INT_MAX; 247 #endif 248 } 249 250 PrintedDocument::Mutable::~Mutable() { 251 } 252 253 PrintedDocument::Immutable::Immutable(const PrintSettings& settings, 254 PrintedPagesSource* source, 255 int cookie, 256 base::TaskRunner* blocking_runner) 257 : settings_(settings), 258 name_(source->RenderSourceName()), 259 cookie_(cookie), 260 blocking_runner_(blocking_runner) { 261 } 262 263 PrintedDocument::Immutable::~Immutable() { 264 } 265 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 { 270 } 271 #endif 272 273 } // namespace printing 274