OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "printing/pdf_metafile_cg_mac.h" | 5 #include "printing/pdf_metafile_cg_mac.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 // the destination PDF context will crash. So the outermost instantiation of | 33 // the destination PDF context will crash. So the outermost instantiation of |
34 // PdfMetafileCg creates a pool for deeper instantiations to dump their used | 34 // PdfMetafileCg creates a pool for deeper instantiations to dump their used |
35 // PDFs into rather than releasing them. When the top-level PDF is closed, then | 35 // PDFs into rather than releasing them. When the top-level PDF is closed, then |
36 // it's safe to clear the pool. A thread local is used to allow this to work in | 36 // it's safe to clear the pool. A thread local is used to allow this to work in |
37 // single-process mode. TODO(avi): This Apple bug appears fixed in 10.7; when | 37 // single-process mode. TODO(avi): This Apple bug appears fixed in 10.7; when |
38 // 10.7 is the minimum required version for Chromium, remove this hack. | 38 // 10.7 is the minimum required version for Chromium, remove this hack. |
39 | 39 |
40 base::LazyInstance<base::ThreadLocalPointer<struct __CFSet> >::Leaky | 40 base::LazyInstance<base::ThreadLocalPointer<struct __CFSet> >::Leaky |
41 thread_pdf_docs = LAZY_INSTANCE_INITIALIZER; | 41 thread_pdf_docs = LAZY_INSTANCE_INITIALIZER; |
42 | 42 |
| 43 // Rotate a page by |num_rotations| * 90 degrees, counter-clockwise. |
| 44 void RotatePage(CGContextRef context, const CGRect rect, int num_rotations) { |
| 45 switch (num_rotations) { |
| 46 case 0: |
| 47 break; |
| 48 case 1: |
| 49 // After rotating by 90 degrees with the axis at the origin, the page |
| 50 // content is now "off screen". Shift it right to move it back on screen. |
| 51 CGContextTranslateCTM(context, rect.size.width, 0); |
| 52 // Rotates counter-clockwise by 90 degrees. |
| 53 CGContextRotateCTM(context, M_PI_2); |
| 54 break; |
| 55 case 2: |
| 56 // After rotating by 180 degrees with the axis at the origin, the page |
| 57 // content is now "off screen". Shift it right and up to move it back on |
| 58 // screen. |
| 59 CGContextTranslateCTM(context, rect.size.width, rect.size.height); |
| 60 // Rotates counter-clockwise by 90 degrees. |
| 61 CGContextRotateCTM(context, M_PI); |
| 62 break; |
| 63 case 3: |
| 64 // After rotating by 270 degrees with the axis at the origin, the page |
| 65 // content is now "off screen". Shift it right to move it back on screen. |
| 66 CGContextTranslateCTM(context, 0, rect.size.height); |
| 67 // Rotates counter-clockwise by 90 degrees. |
| 68 CGContextRotateCTM(context, -M_PI_2); |
| 69 break; |
| 70 default: |
| 71 NOTREACHED(); |
| 72 break; |
| 73 }; |
| 74 } |
| 75 |
43 } // namespace | 76 } // namespace |
44 | 77 |
45 namespace printing { | 78 namespace printing { |
46 | 79 |
47 PdfMetafileCg::PdfMetafileCg() | 80 PdfMetafileCg::PdfMetafileCg() |
48 : page_is_open_(false), | 81 : page_is_open_(false), |
49 thread_pdf_docs_owned_(false) { | 82 thread_pdf_docs_owned_(false) { |
50 if (!thread_pdf_docs.Pointer()->Get() && | 83 if (!thread_pdf_docs.Pointer()->Get() && |
51 base::mac::IsOSSnowLeopard()) { | 84 base::mac::IsOSSnowLeopard()) { |
52 thread_pdf_docs_owned_ = true; | 85 thread_pdf_docs_owned_ = true; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 CGContextRef context, | 208 CGContextRef context, |
176 const CGRect rect, | 209 const CGRect rect, |
177 const MacRenderPageParams& params) const { | 210 const MacRenderPageParams& params) const { |
178 CGPDFDocumentRef pdf_doc = GetPDFDocument(); | 211 CGPDFDocumentRef pdf_doc = GetPDFDocument(); |
179 if (!pdf_doc) { | 212 if (!pdf_doc) { |
180 LOG(ERROR) << "Unable to create PDF document from data"; | 213 LOG(ERROR) << "Unable to create PDF document from data"; |
181 return false; | 214 return false; |
182 } | 215 } |
183 CGPDFPageRef pdf_page = CGPDFDocumentGetPage(pdf_doc, page_number); | 216 CGPDFPageRef pdf_page = CGPDFDocumentGetPage(pdf_doc, page_number); |
184 CGRect source_rect = CGPDFPageGetBoxRect(pdf_page, kCGPDFCropBox); | 217 CGRect source_rect = CGPDFPageGetBoxRect(pdf_page, kCGPDFCropBox); |
| 218 int pdf_src_rotation = CGPDFPageGetRotationAngle(pdf_page); |
185 float scaling_factor = 1.0; | 219 float scaling_factor = 1.0; |
186 const bool source_is_landscape = | 220 const bool source_is_landscape = |
187 (source_rect.size.width > source_rect.size.height); | 221 (source_rect.size.width > source_rect.size.height); |
188 const bool dest_is_landscape = (rect.size.width > rect.size.height); | 222 const bool dest_is_landscape = (rect.size.width > rect.size.height); |
189 const bool rotate = | 223 const bool rotate = |
190 params.autorotate ? (source_is_landscape != dest_is_landscape) : false; | 224 params.autorotate ? (source_is_landscape != dest_is_landscape) : false; |
191 const float source_width = | 225 const float source_width = |
192 rotate ? source_rect.size.height : source_rect.size.width; | 226 rotate ? source_rect.size.height : source_rect.size.width; |
193 const float source_height = | 227 const float source_height = |
194 rotate ? source_rect.size.width : source_rect.size.height; | 228 rotate ? source_rect.size.width : source_rect.size.height; |
(...skipping 22 matching lines...) Expand all Loading... |
217 | 251 |
218 float y_offset = params.center_vertically ? | 252 float y_offset = params.center_vertically ? |
219 ((rect.size.height - (source_height * scaling_factor)) / 2) : 0; | 253 ((rect.size.height - (source_height * scaling_factor)) / 2) : 0; |
220 | 254 |
221 CGContextSaveGState(context); | 255 CGContextSaveGState(context); |
222 | 256 |
223 // The transform operations specified here gets applied in reverse order. | 257 // The transform operations specified here gets applied in reverse order. |
224 // i.e. the origin offset translation happens first. | 258 // i.e. the origin offset translation happens first. |
225 // Origin is at bottom-left. | 259 // Origin is at bottom-left. |
226 CGContextTranslateCTM(context, x_offset, y_offset); | 260 CGContextTranslateCTM(context, x_offset, y_offset); |
| 261 |
| 262 int num_rotations = 0; |
227 if (rotate) { | 263 if (rotate) { |
228 // After rotating by 90 degrees with the axis at the origin, the page | 264 if (pdf_src_rotation == 0 || pdf_src_rotation == 270) { |
229 // content is now "off screen". Shift it right to move it back on screen. | 265 num_rotations = 1; |
230 CGContextTranslateCTM(context, rect.size.width, 0); | 266 } else { |
231 // Rotates counter-clockwise by 90 degrees. | 267 num_rotations = 3; |
232 CGContextRotateCTM(context, M_PI_2); | 268 } |
| 269 } else { |
| 270 if (pdf_src_rotation == 180 || pdf_src_rotation == 270) { |
| 271 num_rotations = 2; |
| 272 } |
233 } | 273 } |
| 274 RotatePage(context, rect, num_rotations); |
| 275 |
234 CGContextScaleCTM(context, scaling_factor, scaling_factor); | 276 CGContextScaleCTM(context, scaling_factor, scaling_factor); |
235 CGContextTranslateCTM(context, x_origin_offset, y_origin_offset); | 277 CGContextTranslateCTM(context, x_origin_offset, y_origin_offset); |
236 | 278 |
237 CGContextDrawPDFPage(context, pdf_page); | 279 CGContextDrawPDFPage(context, pdf_page); |
238 CGContextRestoreGState(context); | 280 CGContextRestoreGState(context); |
239 | 281 |
240 return true; | 282 return true; |
241 } | 283 } |
242 | 284 |
243 unsigned int PdfMetafileCg::GetPageCount() const { | 285 unsigned int PdfMetafileCg::GetPageCount() const { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 | 339 |
298 if (!pdf_doc_.get()) { | 340 if (!pdf_doc_.get()) { |
299 ScopedCFTypeRef<CGDataProviderRef> pdf_data_provider( | 341 ScopedCFTypeRef<CGDataProviderRef> pdf_data_provider( |
300 CGDataProviderCreateWithCFData(pdf_data_)); | 342 CGDataProviderCreateWithCFData(pdf_data_)); |
301 pdf_doc_.reset(CGPDFDocumentCreateWithProvider(pdf_data_provider)); | 343 pdf_doc_.reset(CGPDFDocumentCreateWithProvider(pdf_data_provider)); |
302 } | 344 } |
303 return pdf_doc_.get(); | 345 return pdf_doc_.get(); |
304 } | 346 } |
305 | 347 |
306 } // namespace printing | 348 } // namespace printing |
OLD | NEW |