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/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