| Index: chrome/browser/printing/printed_document.cc
|
| ===================================================================
|
| --- chrome/browser/printing/printed_document.cc (revision 20026)
|
| +++ chrome/browser/printing/printed_document.cc (working copy)
|
| @@ -1,366 +0,0 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/printing/printed_document.h"
|
| -
|
| -#include <set>
|
| -
|
| -#include "app/gfx/font.h"
|
| -#include "app/gfx/text_elider.h"
|
| -#include "app/win_util.h"
|
| -#include "base/file_util.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/singleton.h"
|
| -#include "base/string_util.h"
|
| -#include "base/time.h"
|
| -#include "chrome/browser/printing/page_number.h"
|
| -#include "chrome/browser/printing/page_overlays.h"
|
| -#include "chrome/browser/printing/printed_pages_source.h"
|
| -#include "chrome/browser/printing/printed_page.h"
|
| -#include "printing/units.h"
|
| -#include "skia/ext/platform_device.h"
|
| -
|
| -using base::Time;
|
| -
|
| -namespace {
|
| -
|
| -struct PrintDebugDumpPath {
|
| - PrintDebugDumpPath()
|
| - : enabled(false) {
|
| - }
|
| -
|
| - bool enabled;
|
| - std::wstring debug_dump_path;
|
| -};
|
| -
|
| -Singleton<PrintDebugDumpPath> g_debug_dump_info;
|
| -
|
| -} // namespace
|
| -
|
| -namespace printing {
|
| -
|
| -PrintedDocument::PrintedDocument(const PrintSettings& settings,
|
| - PrintedPagesSource* source,
|
| - int cookie)
|
| - : mutable_(source),
|
| - immutable_(settings, source, cookie) {
|
| -
|
| - // Records the expected page count if a range is setup.
|
| - if (!settings.ranges.empty()) {
|
| - // If there is a range, set the number of page
|
| - for (unsigned i = 0; i < settings.ranges.size(); ++i) {
|
| - const PageRange& range = settings.ranges[i];
|
| - mutable_.expected_page_count_ += range.to - range.from + 1;
|
| - }
|
| - }
|
| -}
|
| -
|
| -PrintedDocument::~PrintedDocument() {
|
| -}
|
| -
|
| -void PrintedDocument::SetPage(int page_number,
|
| - NativeMetafile* metafile,
|
| - double shrink) {
|
| - // Notice the page_number + 1, the reason is that this is the value that will
|
| - // be shown. Users dislike 0-based counting.
|
| - scoped_refptr<PrintedPage> page(
|
| - new PrintedPage(page_number + 1,
|
| - metafile, immutable_.settings_.page_setup_pixels().physical_size()));
|
| - {
|
| - AutoLock lock(lock_);
|
| - mutable_.pages_[page_number] = page;
|
| - if (mutable_.shrink_factor == 0) {
|
| - mutable_.shrink_factor = shrink;
|
| - } else {
|
| - DCHECK_EQ(mutable_.shrink_factor, shrink);
|
| - }
|
| - }
|
| - DebugDump(*page);
|
| -}
|
| -
|
| -bool PrintedDocument::GetPage(int page_number,
|
| - scoped_refptr<PrintedPage>* page) {
|
| - AutoLock lock(lock_);
|
| - PrintedPages::const_iterator itr = mutable_.pages_.find(page_number);
|
| - if (itr != mutable_.pages_.end()) {
|
| - if (itr->second.get()) {
|
| - *page = itr->second;
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void PrintedDocument::RenderPrintedPage(const PrintedPage& page,
|
| - HDC context) const {
|
| -#ifndef NDEBUG
|
| - {
|
| - // Make sure the page is from our list.
|
| - AutoLock lock(lock_);
|
| - DCHECK(&page == mutable_.pages_.find(page.page_number() - 1)->second.get());
|
| - }
|
| -#endif
|
| -
|
| - // Save the state to make sure the context this function call does not modify
|
| - // the device context.
|
| - int saved_state = SaveDC(context);
|
| - DCHECK_NE(saved_state, 0);
|
| - skia::PlatformDevice::InitializeDC(context);
|
| - {
|
| - // Save the state (again) to apply the necessary world transformation.
|
| - int saved_state = SaveDC(context);
|
| - DCHECK_NE(saved_state, 0);
|
| -
|
| - // Setup the matrix to translate and scale to the right place. Take in
|
| - // account the actual shrinking factor.
|
| - XFORM xform = { 0 };
|
| - xform.eDx = static_cast<float>(
|
| - immutable_.settings_.page_setup_pixels().content_area().x());
|
| - xform.eDy = static_cast<float>(
|
| - immutable_.settings_.page_setup_pixels().content_area().y());
|
| - xform.eM11 = static_cast<float>(1. / mutable_.shrink_factor);
|
| - xform.eM22 = static_cast<float>(1. / mutable_.shrink_factor);
|
| - BOOL res = ModifyWorldTransform(context, &xform, MWT_LEFTMULTIPLY);
|
| - DCHECK_NE(res, 0);
|
| -
|
| - if (!page.native_metafile()->SafePlayback(context)) {
|
| - NOTREACHED();
|
| - }
|
| -
|
| - res = RestoreDC(context, saved_state);
|
| - DCHECK_NE(res, 0);
|
| - }
|
| -
|
| - // Print the header and footer.
|
| - int base_font_size = gfx::Font().height();
|
| - int new_font_size = ConvertUnit(10,
|
| - immutable_.settings_.desired_dpi,
|
| - immutable_.settings_.dpi());
|
| - DCHECK_GT(new_font_size, base_font_size);
|
| - gfx::Font font(gfx::Font().DeriveFont(new_font_size - base_font_size));
|
| - HGDIOBJ old_font = SelectObject(context, font.hfont());
|
| - DCHECK(old_font != NULL);
|
| - // We don't want a white square around the text ever if overflowing.
|
| - SetBkMode(context, TRANSPARENT);
|
| - PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::TOP,
|
| - font);
|
| - PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::TOP,
|
| - font);
|
| - PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::TOP,
|
| - font);
|
| - PrintHeaderFooter(context, page, PageOverlays::LEFT, PageOverlays::BOTTOM,
|
| - font);
|
| - PrintHeaderFooter(context, page, PageOverlays::CENTER, PageOverlays::BOTTOM,
|
| - font);
|
| - PrintHeaderFooter(context, page, PageOverlays::RIGHT, PageOverlays::BOTTOM,
|
| - font);
|
| - int res = RestoreDC(context, saved_state);
|
| - DCHECK_NE(res, 0);
|
| -}
|
| -
|
| -bool PrintedDocument::RenderPrintedPageNumber(int page_number, HDC context) {
|
| - scoped_refptr<PrintedPage> page;
|
| - if (!GetPage(page_number, &page))
|
| - return false;
|
| - RenderPrintedPage(*page.get(), context);
|
| - return true;
|
| -}
|
| -
|
| -bool PrintedDocument::IsComplete() const {
|
| - AutoLock lock(lock_);
|
| - if (!mutable_.page_count_)
|
| - return false;
|
| - PageNumber page(immutable_.settings_, mutable_.page_count_);
|
| - if (page == PageNumber::npos())
|
| - return false;
|
| - for (; page != PageNumber::npos(); ++page) {
|
| - PrintedPages::const_iterator itr = mutable_.pages_.find(page.ToInt());
|
| - if (itr == mutable_.pages_.end() || !itr->second.get() ||
|
| - !itr->second->native_metafile())
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void PrintedDocument::DisconnectSource() {
|
| - AutoLock lock(lock_);
|
| - mutable_.source_ = NULL;
|
| -}
|
| -
|
| -size_t PrintedDocument::MemoryUsage() const {
|
| - std::vector<scoped_refptr<PrintedPage>> pages_copy;
|
| - {
|
| - AutoLock lock(lock_);
|
| - pages_copy.reserve(mutable_.pages_.size());
|
| - PrintedPages::const_iterator end = mutable_.pages_.end();
|
| - for (PrintedPages::const_iterator itr = mutable_.pages_.begin();
|
| - itr != end; ++itr) {
|
| - if (itr->second.get()) {
|
| - pages_copy.push_back(itr->second);
|
| - }
|
| - }
|
| - }
|
| - size_t total = 0;
|
| - for (size_t i = 0; i < pages_copy.size(); ++i) {
|
| - total += pages_copy[i]->native_metafile()->GetDataSize();
|
| - }
|
| - return total;
|
| -}
|
| -
|
| -void PrintedDocument::set_page_count(int max_page) {
|
| - AutoLock lock(lock_);
|
| - DCHECK_EQ(0, mutable_.page_count_);
|
| - mutable_.page_count_ = max_page;
|
| - if (immutable_.settings_.ranges.empty()) {
|
| - mutable_.expected_page_count_ = max_page;
|
| - } else {
|
| - // If there is a range, don't bother since expected_page_count_ is already
|
| - // initialized.
|
| - DCHECK_NE(mutable_.expected_page_count_, 0);
|
| - }
|
| -}
|
| -
|
| -int PrintedDocument::page_count() const {
|
| - AutoLock lock(lock_);
|
| - return mutable_.page_count_;
|
| -}
|
| -
|
| -int PrintedDocument::expected_page_count() const {
|
| - AutoLock lock(lock_);
|
| - return mutable_.expected_page_count_;
|
| -}
|
| -
|
| -void PrintedDocument::PrintHeaderFooter(HDC context,
|
| - const PrintedPage& page,
|
| - PageOverlays::HorizontalPosition x,
|
| - PageOverlays::VerticalPosition y,
|
| - const gfx::Font& font) const {
|
| - const PrintSettings& settings = immutable_.settings_;
|
| - const std::wstring& line = settings.overlays.GetOverlay(x, y);
|
| - if (line.empty()) {
|
| - return;
|
| - }
|
| - std::wstring output(PageOverlays::ReplaceVariables(line, *this, page));
|
| - if (output.empty()) {
|
| - // May happens if document name or url is empty.
|
| - return;
|
| - }
|
| - const gfx::Size string_size(font.GetStringWidth(output), font.height());
|
| - gfx::Rect bounding;
|
| - bounding.set_height(string_size.height());
|
| - const gfx::Rect& overlay_area(settings.page_setup_pixels().overlay_area());
|
| - // Hard code .25 cm interstice between overlays. Make sure that some space is
|
| - // kept between each headers.
|
| - const int interstice = ConvertUnit(250, kHundrethsMMPerInch, settings.dpi());
|
| - const int max_width = overlay_area.width() / 3 - interstice;
|
| - const int actual_width = std::min(string_size.width(), max_width);
|
| - switch (x) {
|
| - case PageOverlays::LEFT:
|
| - bounding.set_x(overlay_area.x());
|
| - bounding.set_width(max_width);
|
| - break;
|
| - case PageOverlays::CENTER:
|
| - bounding.set_x(overlay_area.x() +
|
| - (overlay_area.width() - actual_width) / 2);
|
| - bounding.set_width(actual_width);
|
| - break;
|
| - case PageOverlays::RIGHT:
|
| - bounding.set_x(overlay_area.right() - actual_width);
|
| - bounding.set_width(actual_width);
|
| - break;
|
| - }
|
| -
|
| - DCHECK_LE(bounding.right(), overlay_area.right());
|
| -
|
| - switch (y) {
|
| - case PageOverlays::BOTTOM:
|
| - bounding.set_y(overlay_area.bottom() - string_size.height());
|
| - break;
|
| - case PageOverlays::TOP:
|
| - bounding.set_y(overlay_area.y());
|
| - break;
|
| - }
|
| -
|
| - if (string_size.width() > bounding.width()) {
|
| - if (line == PageOverlays::kUrl) {
|
| - output = gfx::ElideUrl(url(), font, bounding.width(), std::wstring());
|
| - } else {
|
| - output = gfx::ElideText(output, font, bounding.width());
|
| - }
|
| - }
|
| -
|
| - // Save the state (again) for the clipping region.
|
| - int saved_state = SaveDC(context);
|
| - DCHECK_NE(saved_state, 0);
|
| -
|
| - int result = IntersectClipRect(context, bounding.x(), bounding.y(),
|
| - bounding.right() + 1, bounding.bottom() + 1);
|
| - DCHECK(result == SIMPLEREGION || result == COMPLEXREGION);
|
| - TextOut(context,
|
| - bounding.x(), bounding.y(),
|
| - output.c_str(),
|
| - static_cast<int>(output.size()));
|
| - int res = RestoreDC(context, saved_state);
|
| - DCHECK_NE(res, 0);
|
| -}
|
| -
|
| -void PrintedDocument::DebugDump(const PrintedPage& page)
|
| -{
|
| - if (!g_debug_dump_info->enabled)
|
| - return;
|
| -
|
| - std::wstring filename;
|
| - filename += date();
|
| - filename += L"_";
|
| - filename += time();
|
| - filename += L"_";
|
| - filename += name();
|
| - filename += L"_";
|
| - filename += StringPrintf(L"%02d", page.page_number());
|
| - filename += L"_.emf";
|
| - file_util::ReplaceIllegalCharacters(&filename, '_');
|
| - std::wstring path(g_debug_dump_info->debug_dump_path);
|
| - file_util::AppendToPath(&path, filename);
|
| - page.native_metafile()->SaveTo(path);
|
| -}
|
| -
|
| -void PrintedDocument::set_debug_dump_path(const std::wstring& debug_dump_path) {
|
| - g_debug_dump_info->enabled = !debug_dump_path.empty();
|
| - g_debug_dump_info->debug_dump_path = debug_dump_path;
|
| -}
|
| -
|
| -const std::wstring& PrintedDocument::debug_dump_path() {
|
| - return g_debug_dump_info->debug_dump_path;
|
| -}
|
| -
|
| -PrintedDocument::Mutable::Mutable(PrintedPagesSource* source)
|
| - : source_(source),
|
| - expected_page_count_(0),
|
| - page_count_(0),
|
| - shrink_factor(0) {
|
| -}
|
| -
|
| -PrintedDocument::Immutable::Immutable(const PrintSettings& settings,
|
| - PrintedPagesSource* source,
|
| - int cookie)
|
| - : settings_(settings),
|
| - source_message_loop_(MessageLoop::current()),
|
| - name_(source->RenderSourceName()),
|
| - url_(source->RenderSourceUrl()),
|
| - cookie_(cookie) {
|
| - // Setup the document's date.
|
| -#ifdef WIN32
|
| - // On Windows, use the native time formatting for printing.
|
| - SYSTEMTIME systemtime;
|
| - GetLocalTime(&systemtime);
|
| - date_ = win_util::FormatSystemDate(systemtime, std::wstring());
|
| - time_ = win_util::FormatSystemTime(systemtime, std::wstring());
|
| -#else
|
| - Time now = Time::Now();
|
| - date_ = TimeFormat::ShortDateNumeric(now);
|
| - time_ = TimeFormat::TimeOfDay(now);
|
| -#endif // WIN32
|
| -}
|
| -
|
| -} // namespace printing
|
|
|