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/file_util.h" 13 #include "base/files/file_path.h" 14 #include "base/i18n/file_util_icu.h" 15 #include "base/i18n/time_formatting.h" 16 #include "base/lazy_instance.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/stringprintf.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "printing/page_number.h" 22 #include "printing/printed_page.h" 23 #include "printing/printed_pages_source.h" 24 #include "printing/units.h" 25 #include "skia/ext/platform_device.h" 26 #include "ui/gfx/font.h" 27 #include "ui/gfx/text_elider.h" 28 29 namespace { 30 31 struct PrintDebugDumpPath { 32 PrintDebugDumpPath() 33 : enabled(false) { 34 } 35 36 bool enabled; 37 base::FilePath debug_dump_path; 38 }; 39 40 base::LazyInstance<PrintDebugDumpPath> g_debug_dump_info = 41 LAZY_INSTANCE_INITIALIZER; 42 43 } // namespace 44 45 namespace printing { 46 47 PrintedDocument::PrintedDocument(const PrintSettings& settings, 48 PrintedPagesSource* source, 49 int cookie) 50 : mutable_(source), 51 immutable_(settings, source, cookie) { 52 53 // Records the expected page count if a range is setup. 54 if (!settings.ranges().empty()) { 55 // If there is a range, set the number of page 56 for (unsigned i = 0; i < settings.ranges().size(); ++i) { 57 const PageRange& range = settings.ranges()[i]; 58 mutable_.expected_page_count_ += range.to - range.from + 1; 59 } 60 } 61 } 62 63 PrintedDocument::~PrintedDocument() { 64 } 65 66 void PrintedDocument::SetPage(int page_number, 67 Metafile* metafile, 68 double shrink, 69 const gfx::Size& paper_size, 70 const gfx::Rect& page_rect) { 71 // Notice the page_number + 1, the reason is that this is the value that will 72 // be shown. Users dislike 0-based counting. 73 scoped_refptr<PrintedPage> page( 74 new PrintedPage(page_number + 1, 75 metafile, 76 paper_size, 77 page_rect, 78 shrink)); 79 { 80 base::AutoLock lock(lock_); 81 mutable_.pages_[page_number] = page; 82 83 #if defined(OS_POSIX) && !defined(OS_MACOSX) 84 if (page_number < mutable_.first_page) 85 mutable_.first_page = page_number; 86 #endif 87 } 88 DebugDump(*page.get()); 89 } 90 91 bool PrintedDocument::GetPage(int page_number, 92 scoped_refptr<PrintedPage>* page) { 93 base::AutoLock lock(lock_); 94 PrintedPages::const_iterator itr = mutable_.pages_.find(page_number); 95 if (itr != mutable_.pages_.end()) { 96 if (itr->second.get()) { 97 *page = itr->second; 98 return true; 99 } 100 } 101 return false; 102 } 103 104 bool PrintedDocument::IsComplete() const { 105 base::AutoLock lock(lock_); 106 if (!mutable_.page_count_) 107 return false; 108 PageNumber page(immutable_.settings_, mutable_.page_count_); 109 if (page == PageNumber::npos()) 110 return false; 111 112 for (; page != PageNumber::npos(); ++page) { 113 #if defined(OS_WIN) || defined(OS_MACOSX) 114 const bool metafile_must_be_valid = true; 115 #elif defined(OS_POSIX) 116 const bool metafile_must_be_valid = (page.ToInt() == mutable_.first_page); 117 #endif 118 PrintedPages::const_iterator itr = mutable_.pages_.find(page.ToInt()); 119 if (itr == mutable_.pages_.end() || !itr->second.get()) 120 return false; 121 if (metafile_must_be_valid && !itr->second->metafile()) 122 return false; 123 } 124 return true; 125 } 126 127 void PrintedDocument::DisconnectSource() { 128 base::AutoLock lock(lock_); 129 mutable_.source_ = NULL; 130 } 131 132 uint32 PrintedDocument::MemoryUsage() const { 133 std::vector< scoped_refptr<PrintedPage> > pages_copy; 134 { 135 base::AutoLock lock(lock_); 136 pages_copy.reserve(mutable_.pages_.size()); 137 PrintedPages::const_iterator end = mutable_.pages_.end(); 138 for (PrintedPages::const_iterator itr = mutable_.pages_.begin(); 139 itr != end; ++itr) { 140 if (itr->second.get()) { 141 pages_copy.push_back(itr->second); 142 } 143 } 144 } 145 uint32 total = 0; 146 for (size_t i = 0; i < pages_copy.size(); ++i) { 147 total += pages_copy[i]->metafile()->GetDataSize(); 148 } 149 return total; 150 } 151 152 void PrintedDocument::set_page_count(int max_page) { 153 base::AutoLock lock(lock_); 154 DCHECK_EQ(0, mutable_.page_count_); 155 mutable_.page_count_ = max_page; 156 if (immutable_.settings_.ranges().empty()) { 157 mutable_.expected_page_count_ = max_page; 158 } else { 159 // If there is a range, don't bother since expected_page_count_ is already 160 // initialized. 161 DCHECK_NE(mutable_.expected_page_count_, 0); 162 } 163 } 164 165 int PrintedDocument::page_count() const { 166 base::AutoLock lock(lock_); 167 return mutable_.page_count_; 168 } 169 170 int PrintedDocument::expected_page_count() const { 171 base::AutoLock lock(lock_); 172 return mutable_.expected_page_count_; 173 } 174 175 void PrintedDocument::DebugDump(const PrintedPage& page) { 176 if (!g_debug_dump_info.Get().enabled) 177 return; 178 179 base::string16 filename; 180 filename += name(); 181 filename += base::ASCIIToUTF16("_"); 182 filename += base::ASCIIToUTF16( 183 base::StringPrintf("%02d", page.page_number())); 184 #if defined(OS_WIN) 185 filename += base::ASCIIToUTF16("_.emf"); 186 page.metafile()->SaveTo( 187 g_debug_dump_info.Get().debug_dump_path.Append(filename)); 188 #else // OS_WIN 189 filename += base::ASCIIToUTF16("_.pdf"); 190 page.metafile()->SaveTo( 191 g_debug_dump_info.Get().debug_dump_path.Append( 192 base::UTF16ToUTF8(filename))); 193 #endif // OS_WIN 194 } 195 196 void PrintedDocument::set_debug_dump_path( 197 const base::FilePath& debug_dump_path) { 198 g_debug_dump_info.Get().enabled = !debug_dump_path.empty(); 199 g_debug_dump_info.Get().debug_dump_path = debug_dump_path; 200 } 201 202 const base::FilePath& PrintedDocument::debug_dump_path() { 203 return g_debug_dump_info.Get().debug_dump_path; 204 } 205 206 PrintedDocument::Mutable::Mutable(PrintedPagesSource* source) 207 : source_(source), 208 expected_page_count_(0), 209 page_count_(0) { 210 #if defined(OS_POSIX) && !defined(OS_MACOSX) 211 first_page = INT_MAX; 212 #endif 213 } 214 215 PrintedDocument::Mutable::~Mutable() { 216 } 217 218 PrintedDocument::Immutable::Immutable(const PrintSettings& settings, 219 PrintedPagesSource* source, 220 int cookie) 221 : settings_(settings), 222 source_message_loop_(base::MessageLoop::current()), 223 name_(source->RenderSourceName()), 224 cookie_(cookie) { 225 } 226 227 PrintedDocument::Immutable::~Immutable() { 228 } 229 230 #if (defined(OS_POSIX) && defined(USE_AURA)) || defined(OS_ANDROID) 231 // This function is not used on aura linux/chromeos or android. 232 void PrintedDocument::RenderPrintedPage(const PrintedPage& page, 233 PrintingContext* context) const { 234 } 235 #endif 236 237 } // namespace printing 238