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 36namespace printing { 37 38namespace { 39 40base::LazyInstance<base::FilePath> g_debug_dump_info = 41 LAZY_INSTANCE_INITIALIZER; 42 43void 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 62void 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 74void 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 92PrintedDocument::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 110PrintedDocument::~PrintedDocument() { 111} 112 113void 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 143scoped_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 154bool 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 177void PrintedDocument::DisconnectSource() { 178 base::AutoLock lock(lock_); 179 mutable_.source_ = NULL; 180} 181 182void 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 195int PrintedDocument::page_count() const { 196 base::AutoLock lock(lock_); 197 return mutable_.page_count_; 198} 199 200int PrintedDocument::expected_page_count() const { 201 base::AutoLock lock(lock_); 202 return mutable_.expected_page_count_; 203} 204 205void PrintedDocument::set_debug_dump_path( 206 const base::FilePath& debug_dump_path) { 207 g_debug_dump_info.Get() = debug_dump_path; 208} 209 210base::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 232void 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 241PrintedDocument::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 250PrintedDocument::Mutable::~Mutable() { 251} 252 253PrintedDocument::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 263PrintedDocument::Immutable::~Immutable() { 264} 265 266#if defined(OS_CHROMEOS) || defined(OS_ANDROID) 267// This function is not used on aura linux/chromeos or android. 268void PrintedDocument::RenderPrintedPage(const PrintedPage& page, 269 PrintingContext* context) const { 270} 271#endif 272 273} // namespace printing 274