blob: 2558a8453a95f34229ee906e3bb17470a90b130e [file] [log] [blame]
[email protected]8f879292011-04-08 00:21:201// 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/pdf_metafile_skia.h"
6
7#include "base/eintr_wrapper.h"
8#include "base/file_descriptor_posix.h"
9#include "base/file_util.h"
[email protected]67e16b392011-05-30 20:58:0910#include "base/hash_tables.h"
11#include "base/metrics/histogram.h"
[email protected]8f879292011-04-08 00:21:2012#include "skia/ext/vector_platform_device_skia.h"
13#include "third_party/skia/include/core/SkRefCnt.h"
[email protected]a34f0122011-04-12 17:36:3914#include "third_party/skia/include/core/SkScalar.h"
[email protected]8f879292011-04-08 00:21:2015#include "third_party/skia/include/core/SkStream.h"
[email protected]67e16b392011-05-30 20:58:0916#include "third_party/skia/include/core/SkTypeface.h"
[email protected]8f879292011-04-08 00:21:2017#include "third_party/skia/include/pdf/SkPDFDevice.h"
18#include "third_party/skia/include/pdf/SkPDFDocument.h"
[email protected]67e16b392011-05-30 20:58:0919#include "third_party/skia/include/pdf/SkPDFFont.h"
[email protected]8f879292011-04-08 00:21:2020#include "third_party/skia/include/pdf/SkPDFPage.h"
21#include "ui/gfx/point.h"
22#include "ui/gfx/rect.h"
23#include "ui/gfx/size.h"
24
[email protected]67e16b392011-05-30 20:58:0925namespace {
26 typedef base::hash_map<SkFontID, SkAdvancedTypefaceMetrics::FontType>
27 FontTypeMap;
28};
29
[email protected]8f879292011-04-08 00:21:2030namespace printing {
31
32struct PdfMetafileSkiaData {
33 SkRefPtr<SkPDFDevice> current_page_;
34 SkPDFDocument pdf_doc_;
35 SkDynamicMemoryWStream pdf_stream_;
[email protected]67e16b392011-05-30 20:58:0936 FontTypeMap font_type_stats_;
[email protected]8f879292011-04-08 00:21:2037};
38
39PdfMetafileSkia::~PdfMetafileSkia() {}
40
41bool PdfMetafileSkia::Init() {
42 return true;
43}
44bool PdfMetafileSkia::InitFromData(const void* src_buffer,
45 uint32 src_buffer_size) {
46 return data_->pdf_stream_.write(src_buffer, src_buffer_size);
47}
48
[email protected]62f2e802011-05-26 14:28:3549SkDevice* PdfMetafileSkia::StartPageForVectorCanvas(
[email protected]39892b92011-04-30 02:24:4450 const gfx::Size& page_size, const gfx::Rect& content_area,
[email protected]8f879292011-04-08 00:21:2051 const float& scale_factor) {
52 DCHECK(data_->current_page_.get() == NULL);
53
[email protected]a34f0122011-04-12 17:36:3954 // Adjust for the margins and apply the scale factor.
55 SkMatrix transform;
[email protected]39892b92011-04-30 02:24:4456 transform.setTranslate(SkIntToScalar(content_area.x()),
57 SkIntToScalar(content_area.y()));
[email protected]a34f0122011-04-12 17:36:3958 transform.preScale(SkFloatToScalar(scale_factor),
59 SkFloatToScalar(scale_factor));
60
[email protected]39892b92011-04-30 02:24:4461 // TODO(ctguil): Refactor: don't create the PDF device explicitly here.
62 SkISize pdf_page_size = SkISize::Make(page_size.width(), page_size.height());
63 SkISize pdf_content_size =
64 SkISize::Make(content_area.width(), content_area.height());
65 SkRefPtr<SkPDFDevice> pdf_device =
66 new SkPDFDevice(pdf_page_size, pdf_content_size, transform);
67 pdf_device->unref(); // SkRefPtr and new both took a reference.
[email protected]8f879292011-04-08 00:21:2068 skia::VectorPlatformDeviceSkia* device =
[email protected]39892b92011-04-30 02:24:4469 new skia::VectorPlatformDeviceSkia(pdf_device.get());
[email protected]8f879292011-04-08 00:21:2070 data_->current_page_ = device->PdfDevice();
71 return device;
72}
73
74bool PdfMetafileSkia::StartPage(const gfx::Size& page_size,
[email protected]39892b92011-04-30 02:24:4475 const gfx::Rect& content_area,
[email protected]8f879292011-04-08 00:21:2076 const float& scale_factor) {
77 NOTREACHED();
78 return NULL;
79}
80
81bool PdfMetafileSkia::FinishPage() {
82 DCHECK(data_->current_page_.get());
83
[email protected]67e16b392011-05-30 20:58:0984 const SkTDArray<SkPDFFont*>& font_resources =
85 data_->current_page_->getFontResources();
86 for (int i = 0; i < font_resources.count(); i++) {
87 SkFontID key = font_resources[i]->typeface()->uniqueID();
88 data_->font_type_stats_[key] = font_resources[i]->getType();
89 }
90
[email protected]8f879292011-04-08 00:21:2091 data_->pdf_doc_.appendPage(data_->current_page_);
92 data_->current_page_ = NULL;
93 return true;
94}
95
96bool PdfMetafileSkia::FinishDocument() {
97 // Don't do anything if we've already set the data in InitFromData.
98 if (data_->pdf_stream_.getOffset())
99 return true;
100
101 if (data_->current_page_.get())
102 FinishPage();
[email protected]67e16b392011-05-30 20:58:09103
104 for (FontTypeMap::const_iterator it = data_->font_type_stats_.begin();
105 it != data_->font_type_stats_.end();
106 it++) {
107 UMA_HISTOGRAM_ENUMERATION(
108 "PrintPreview.FontType",
109 it->second,
110 SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1);
111 }
112
[email protected]8f879292011-04-08 00:21:20113 return data_->pdf_doc_.emitPDF(&data_->pdf_stream_);
114}
115
116uint32 PdfMetafileSkia::GetDataSize() const {
117 return data_->pdf_stream_.getOffset();
118}
119
120bool PdfMetafileSkia::GetData(void* dst_buffer,
121 uint32 dst_buffer_size) const {
122 if (dst_buffer_size < GetDataSize())
123 return false;
124
125 memcpy(dst_buffer, data_->pdf_stream_.getStream(), dst_buffer_size);
126 return true;
127}
128
129bool PdfMetafileSkia::SaveTo(const FilePath& file_path) const {
130 DCHECK_GT(data_->pdf_stream_.getOffset(), 0U);
131 if (file_util::WriteFile(file_path, data_->pdf_stream_.getStream(),
132 GetDataSize()) != static_cast<int>(GetDataSize())) {
133 DLOG(ERROR) << "Failed to save file " << file_path.value().c_str();
134 return false;
135 }
136 return true;
137}
138
139gfx::Rect PdfMetafileSkia::GetPageBounds(unsigned int page_number) const {
140 // TODO(vandebo) add a method to get the page size for a given page to
141 // SkPDFDocument.
142 NOTIMPLEMENTED();
143 return gfx::Rect();
144}
145
146unsigned int PdfMetafileSkia::GetPageCount() const {
147 // TODO(vandebo) add a method to get the number of pages to SkPDFDocument.
148 NOTIMPLEMENTED();
149 return 0;
150}
151
152gfx::NativeDrawingContext PdfMetafileSkia::context() const {
153 NOTREACHED();
154 return NULL;
155}
156
157#if defined(OS_WIN)
158bool PdfMetafileSkia::Playback(gfx::NativeDrawingContext hdc,
159 const RECT* rect) const {
160 NOTREACHED();
161 return false;
162}
163
164bool PdfMetafileSkia::SafePlayback(gfx::NativeDrawingContext hdc) const {
165 NOTREACHED();
166 return false;
167}
168
169HENHMETAFILE PdfMetafileSkia::emf() const {
170 NOTREACHED();
171 return NULL;
172}
173#endif // if defined(OS_WIN)
174
175#if defined(OS_CHROMEOS)
176bool PdfMetafileSkia::SaveToFD(const base::FileDescriptor& fd) const {
177 DCHECK_GT(data_->pdf_stream_.getOffset(), 0U);
178
179 if (fd.fd < 0) {
180 DLOG(ERROR) << "Invalid file descriptor!";
181 return false;
182 }
183
184 bool result = true;
185 if (file_util::WriteFileDescriptor(fd.fd, data_->pdf_stream_.getStream(),
186 GetDataSize()) !=
187 static_cast<int>(GetDataSize())) {
188 DLOG(ERROR) << "Failed to save file with fd " << fd.fd;
189 result = false;
190 }
191
192 if (fd.auto_close) {
193 if (HANDLE_EINTR(close(fd.fd)) < 0) {
194 DPLOG(WARNING) << "close";
195 result = false;
196 }
197 }
198 return result;
199}
200#endif
201
202PdfMetafileSkia::PdfMetafileSkia() : data_(new PdfMetafileSkiaData) {}
203
204} // namespace printing