Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: printing/pdf_ps_metafile_linux.cc

Issue 174405: Implement native metafile for printing on Linux. (Closed)
Patch Set: Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « printing/pdf_ps_metafile_linux.h ('k') | printing/pdf_ps_metafile_linux_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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_ps_metafile_linux.h"
6
7 #include <stdio.h>
8
9 #include <cairo-pdf.h>
10 #include <cairo-ps.h>
11
12 #include "base/file_util.h"
13 #include "base/logging.h"
14
15 namespace printing {
16
17 PdfPsMetafile::PdfPsMetafile(const FileFormat& format)
18 : format_(format),
19 surface_(NULL), context_(NULL),
20 page_surface_(NULL), page_context_(NULL) {
21
22 // Create an 1 by 1 Cairo surface for entire PDF/PS file.
23 // The size for each page will be overwritten later in StartPage().
24 switch (format_) {
25 case PDF: {
26 surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream,
27 &all_pages_, 1, 1);
28 }
29 break;
30
31 case PS: {
32 surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream,
33 &all_pages_, 1, 1);
34 }
35 break;
36
37 default:
38 NOTREACHED();
39 return;
40 }
41
42 // Cairo always returns a valid pointer.
43 // Hence, we have to check if it points to a "nil" object.
44 if (!IsSurfaceValid(surface_)) {
45 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!";
46 cairo_surface_destroy(surface_);
47 return;
48 }
49
50 // Create a context.
51 context_ = cairo_create(surface_);
52 if (!IsContextValid(context_)) {
53 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!";
54 cairo_destroy(context_);
55 cairo_surface_destroy(surface_);
56 return;
57 }
58
59 // Since |context_| will keep a reference of |surface_|, we can decreace
60 // surface's reference count by one safely.
61 cairo_surface_destroy(surface_);
62 }
63
64 PdfPsMetafile::PdfPsMetafile(const FileFormat& format,
65 const void* src_buffer,
66 size_t src_buffer_size)
67 : format_(format),
68 surface_(NULL), context_(NULL),
69 page_surface_(NULL), page_context_(NULL) {
70
71 all_pages_ = std::string(reinterpret_cast<const char*>(src_buffer),
72 src_buffer_size);
73 }
74
75 PdfPsMetafile::~PdfPsMetafile() {
76 // Releases resources if we forgot to do so.
77 Close();
78 }
79
80 bool PdfPsMetafile::StartPage(double width_in_points, double height_in_points) {
81 DCHECK(IsSurfaceValid(surface_));
82 DCHECK(IsContextValid(context_));
83 DCHECK(!page_surface_ && !page_context_);
84 DCHECK_GT(width_in_points, 0.);
85 DCHECK_GT(height_in_points, 0.);
86
87 // Create a target surface for the new page.
88 // Cairo 1.6.0 does NOT allow the first argument be NULL,
89 // but some newer versions do support NULL pointer.
90 switch (format_) {
91 case PDF: {
92 page_surface_ = cairo_pdf_surface_create_for_stream(WriteCairoStream,
93 &current_page_,
94 width_in_points,
95 height_in_points);
96 }
97 break;
98
99 case PS: {
100 page_surface_ = cairo_ps_surface_create_for_stream(WriteCairoStream,
101 &current_page_,
102 width_in_points,
103 height_in_points);
104 }
105 break;
106
107 default:
108 NOTREACHED();
109 return false;
110 }
111
112 // Cairo always returns a valid pointer.
113 // Hence, we have to check if it points to a "nil" object.
114 if (!IsSurfaceValid(page_surface_)) {
115 DLOG(ERROR) << "Cannot create Cairo surface for PdfPsMetafile!";
116 cairo_surface_destroy(page_surface_);
117 return false;
118 }
119
120 // Create a context.
121 page_context_ = cairo_create(page_surface_);
122 if (!IsContextValid(page_context_)) {
123 DLOG(ERROR) << "Cannot create Cairo context for PdfPsMetafile!";
124 cairo_destroy(page_context_);
125 cairo_surface_destroy(page_surface_);
126 return false;
127 }
128
129 // Since |page_context_| will keep a reference of |page_surface_|, we can
130 // decreace surface's reference count by one safely.
131 cairo_surface_destroy(page_surface_);
132
133 return true;
134 }
135
136 void PdfPsMetafile::FinishPage(float shrink) {
137 DCHECK(IsSurfaceValid(surface_));
138 DCHECK(IsContextValid(context_));
139 DCHECK(IsSurfaceValid(page_surface_));
140 DCHECK(IsContextValid(page_context_));
141
142 // Flush all rendering for current page.
143 cairo_surface_flush(page_surface_);
144
145 // TODO(myhuang): Use real page settings.
146 // We hard-coded page settings here for testing purpose.
147 // The paper size is US Letter (8.5 in. by 11 in.).
148 // The default margins are:
149 // Left = 0.25 in.
150 // Right = 0.25 in.
151 // Top = 0.25 in.
152 // Bottom = 0.56 in.
153 const double kDPI = 72.0; // Dots (points) per inch.
154 const double kWidthInInch = 8.5;
155 const double kHeightInInch = 11.0;
156 const double kWidthInPoint = kWidthInInch * kDPI;
157 const double kHeightInPoint = kHeightInInch * kDPI;
158 switch (format_) {
159 case PDF: {
160 cairo_pdf_surface_set_size(surface_, kWidthInPoint, kHeightInPoint);
161 }
162 break;
163
164 case PS: {
165 cairo_ps_surface_set_size(surface_, kWidthInPoint, kHeightInPoint);
166 }
167 break;
168
169 default:
170 NOTREACHED();
171 return;
172 }
173
174 // Save context's states.
175 cairo_save(context_);
176 // Copy current page onto the surface of final result.
177 // Margins are done by coordinates transformation.
178 // Please NOTE that we have to call cairo_scale() before we call
179 // cairo_set_source_surface().
180 const double scale_factor = 1. / shrink;
181 cairo_scale(context_, scale_factor, scale_factor);
182 const double kLeftMarginInInch = 0.25;
183 const double kTopMarginInInch = 0.25;
184 const double kLeftMarginInPoint = kLeftMarginInInch * kDPI;
185 const double kTopMarginInPoint = kTopMarginInInch * kDPI;
186 const double kScaledLeftMarginInPoint = kLeftMarginInPoint * shrink;
187 const double kScaledTopMarginInPoint = kTopMarginInPoint * shrink;
188 cairo_set_source_surface(context_,
189 page_surface_,
190 kScaledLeftMarginInPoint,
191 kScaledTopMarginInPoint);
192 // In Cairo 1.6.0, if we use the following API, either the renderer will
193 // crash, or we will get an empty page. This might be a bug in Cairo.
194 // cairo_set_operator(context_, CAIRO_OPERATOR_SOURCE);
195 const double kRightMarginInInch = 0.25;
196 const double kBottomMarginInInch = 0.56;
197 const double kPrintableWidthInInch =
198 kWidthInInch - kLeftMarginInInch - kRightMarginInInch;
199 const double kPrintableHeightInInch =
200 kHeightInInch - kTopMarginInInch - kBottomMarginInInch;
201 const double kScaledPrintableWidthInPoint =
202 kPrintableWidthInInch * kDPI * shrink;
203 const double kScaledPrintableHeightInPoint =
204 kPrintableHeightInInch * kDPI * shrink;
205 cairo_rectangle(context_,
206 kScaledLeftMarginInPoint,
207 kScaledTopMarginInPoint,
208 kScaledPrintableWidthInPoint,
209 kScaledPrintableHeightInPoint);
210 cairo_fill(context_);
211
212 // Finishing the duplication of current page.
213 cairo_show_page(context_);
214 cairo_surface_flush(surface_);
215
216 // Destroy resoreces for current page.
217 cairo_destroy(page_context_);
218 page_context_ = NULL;
219 page_surface_ = NULL;
220 current_page_.clear();
221
222 // Restore context's states.
223 cairo_restore(context_);
224 }
225
226 void PdfPsMetafile::Close() {
227 if (surface_ != NULL && IsSurfaceValid(surface_)) {
228 cairo_surface_finish(surface_);
229 surface_ = NULL;
230 }
231 if (context_ != NULL && IsContextValid(context_)) {
232 cairo_destroy(context_);
233 context_ = NULL;
234 }
235 }
236
237 unsigned int PdfPsMetafile::GetDataSize() const {
238 DCHECK(!surface_ && !context_);
239
240 return all_pages_.size();
241 }
242
243 void PdfPsMetafile::GetData(void* dst_buffer, size_t dst_buffer_size) const {
244 DCHECK(!surface_ && !context_);
245 DCHECK(dst_buffer);
246
247 size_t data_size = GetDataSize();
248 if (data_size < dst_buffer_size)
249 dst_buffer_size = data_size;
250 memcpy(dst_buffer, all_pages_.data(), dst_buffer_size);
251 }
252
253 bool PdfPsMetafile::SaveTo(const FilePath& filename) const {
254 DCHECK(!surface_ && !context_);
255
256 const unsigned int data_size = GetDataSize();
257 const unsigned int bytes_written =
258 file_util::WriteFile(filename, all_pages_.data(), data_size);
259 if (bytes_written != data_size) {
260 DLOG(ERROR) << "Failed to save file: " << filename.value();
261 return false;
262 }
263
264 return true;
265 }
266
267 cairo_status_t PdfPsMetafile::WriteCairoStream(void* dst_buffer,
268 const unsigned char* src_data,
269 unsigned int src_data_length) {
270 DCHECK(dst_buffer);
271 DCHECK(src_data);
272
273 std::string* buffer = reinterpret_cast<std::string* >(dst_buffer);
274 buffer->append(reinterpret_cast<const char*>(src_data), src_data_length);
275
276 return CAIRO_STATUS_SUCCESS;
277 }
278
279 bool PdfPsMetafile::IsSurfaceValid(cairo_surface_t* surface) const {
280 return cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS;
281 }
282
283 bool PdfPsMetafile::IsContextValid(cairo_t* context) const {
284 return cairo_status(context) == CAIRO_STATUS_SUCCESS;
285 }
286
287 } // namespace printing
288
OLDNEW
« no previous file with comments | « printing/pdf_ps_metafile_linux.h ('k') | printing/pdf_ps_metafile_linux_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698