Home | History | Annotate | Download | only in printing
      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/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"
     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 #if defined(OS_WIN)
     52   page->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
     53       filename, FILE_PATH_LITERAL(".emf")));
     54 #else   // OS_WIN
     55   page->metafile()->SaveTo(PrintedDocument::CreateDebugDumpPath(
     56       filename, FILE_PATH_LITERAL(".pdf")));
     57 #endif  // OS_WIN
     58 }
     59 
     60 void DebugDumpDataTask(const base::string16& doc_name,
     61                        const base::FilePath::StringType& extension,
     62                        const base::RefCountedMemory* data) {
     63   base::FilePath path =
     64       PrintedDocument::CreateDebugDumpPath(doc_name, extension);
     65   if (path.empty())
     66     return;
     67   base::WriteFile(path,
     68                   reinterpret_cast<const char*>(data->front()),
     69                   base::checked_cast<int>(data->size()));
     70 }
     71 
     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(
     83       FROM_HERE,
     84       base::Bind(
     85           &DebugDumpDataTask, doc_name, FILE_PATH_LITERAL(".json"), data));
     86 }
     87 
     88 }  // namespace
     89 
     90 PrintedDocument::PrintedDocument(const PrintSettings& settings,
     91                                  PrintedPagesSource* source,
     92                                  int cookie,
     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;
    101     }
    102   }
    103 
    104   if (!g_debug_dump_info.Get().empty())
    105     DebugDumpSettings(name(), settings, blocking_runner);
    106 }
    107 
    108 PrintedDocument::~PrintedDocument() {
    109 }
    110 
    111 void PrintedDocument::SetPage(int page_number,
    112                               Metafile* metafile,
    113 #if defined(OS_WIN)
    114                               double shrink,
    115 #endif  // OS_WIN
    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));
    122 #if defined(OS_WIN)
    123   page->set_shrink_factor(shrink);
    124 #endif  // OS_WIN
    125   {
    126     base::AutoLock lock(lock_);
    127     mutable_.pages_[page_number] = page;
    128 
    129 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    130     if (page_number < mutable_.first_page)
    131       mutable_.first_page = page_number;
    132 #endif
    133   }
    134 
    135   if (!g_debug_dump_info.Get().empty()) {
    136     immutable_.blocking_runner_->PostTask(
    137         FROM_HERE, base::Bind(&DebugDumpPageTask, name(), page));
    138   }
    139 }
    140 
    141 scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) {
    142   scoped_refptr<PrintedPage> page;
    143   {
    144     base::AutoLock lock(lock_);
    145     PrintedPages::const_iterator itr = mutable_.pages_.find(page_number);
    146     if (itr != mutable_.pages_.end())
    147       page = itr->second;
    148   }
    149   return page;
    150 }
    151 
    152 bool PrintedDocument::IsComplete() const {
    153   base::AutoLock lock(lock_);
    154   if (!mutable_.page_count_)
    155     return false;
    156   PageNumber page(immutable_.settings_, mutable_.page_count_);
    157   if (page == PageNumber::npos())
    158     return false;
    159 
    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);
    165 #endif
    166     PrintedPages::const_iterator itr = mutable_.pages_.find(page.ToInt());
    167     if (itr == mutable_.pages_.end() || !itr->second.get())
    168       return false;
    169     if (metafile_must_be_valid && !itr->second->metafile())
    170       return false;
    171   }
    172   return true;
    173 }
    174 
    175 void PrintedDocument::DisconnectSource() {
    176   base::AutoLock lock(lock_);
    177   mutable_.source_ = NULL;
    178 }
    179 
    180 uint32 PrintedDocument::MemoryUsage() const {
    181   std::vector< scoped_refptr<PrintedPage> > pages_copy;
    182   {
    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();
    187          itr != end; ++itr) {
    188       if (itr->second.get()) {
    189         pages_copy.push_back(itr->second);
    190       }
    191     }
    192   }
    193   uint32 total = 0;
    194   for (size_t i = 0; i < pages_copy.size(); ++i) {
    195     total += pages_copy[i]->metafile()->GetDataSize();
    196   }
    197   return total;
    198 }
    199 
    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;
    206   } else {
    207     // If there is a range, don't bother since expected_page_count_ is already
    208     // initialized.
    209     DCHECK_NE(mutable_.expected_page_count_, 0);
    210   }
    211 }
    212 
    213 int PrintedDocument::page_count() const {
    214   base::AutoLock lock(lock_);
    215   return mutable_.page_count_;
    216 }
    217 
    218 int PrintedDocument::expected_page_count() const {
    219   base::AutoLock lock(lock_);
    220   return mutable_.expected_page_count_;
    221 }
    222 
    223 void PrintedDocument::set_debug_dump_path(
    224     const base::FilePath& debug_dump_path) {
    225   g_debug_dump_info.Get() = debug_dump_path;
    226 }
    227 
    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;
    240 #if defined(OS_WIN)
    241   system_filename = filename;
    242 #else   // OS_WIN
    243   system_filename = base::UTF16ToUTF8(filename);
    244 #endif  // OS_WIN
    245   file_util::ReplaceIllegalCharactersInPath(&system_filename, '_');
    246   return g_debug_dump_info.Get().Append(system_filename).AddExtension(
    247       extension);
    248 }
    249 
    250 void PrintedDocument::DebugDumpData(
    251     const base::RefCountedMemory* data,
    252     const base::FilePath::StringType& extension) {
    253   if (g_debug_dump_info.Get().empty())
    254     return;
    255   immutable_.blocking_runner_->PostTask(
    256       FROM_HERE, base::Bind(&DebugDumpDataTask, name(), extension, data));
    257 }
    258 
    259 PrintedDocument::Mutable::Mutable(PrintedPagesSource* source)
    260     : source_(source),
    261       expected_page_count_(0),
    262       page_count_(0) {
    263 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    264   first_page = INT_MAX;
    265 #endif
    266 }
    267 
    268 PrintedDocument::Mutable::~Mutable() {
    269 }
    270 
    271 PrintedDocument::Immutable::Immutable(const PrintSettings& settings,
    272                                       PrintedPagesSource* source,
    273                                       int cookie,
    274                                       base::TaskRunner* blocking_runner)
    275     : settings_(settings),
    276       name_(source->RenderSourceName()),
    277       cookie_(cookie),
    278       blocking_runner_(blocking_runner) {
    279 }
    280 
    281 PrintedDocument::Immutable::~Immutable() {
    282 }
    283 
    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 {
    288 }
    289 #endif
    290 
    291 }  // namespace printing
    292