[email protected] | 89eff96a | 2011-03-17 23:22:06 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
[email protected] | 0e0fca3 | 2009-07-06 15:25:50 | [diff] [blame] | 5 | #include "printing/emf_win.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 6 | |
[email protected] | e6cddc57 | 2010-09-29 21:39:45 | [diff] [blame] | 7 | #include "base/file_path.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 8 | #include "base/logging.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 9 | #include "base/memory/scoped_ptr.h" |
[email protected] | 835d7c8 | 2010-10-14 04:38:38 | [diff] [blame] | 10 | #include "base/metrics/histogram.h" |
[email protected] | 38bba4f | 2010-03-12 05:29:07 | [diff] [blame] | 11 | #include "base/time.h" |
[email protected] | d2fdcf0 | 2011-03-21 22:16:43 | [diff] [blame] | 12 | #include "skia/ext/vector_platform_device_win.h" |
[email protected] | 38bba4f | 2010-03-12 05:29:07 | [diff] [blame] | 13 | #include "third_party/skia/include/core/SkBitmap.h" |
[email protected] | 08397d5 | 2011-02-05 01:53:38 | [diff] [blame] | 14 | #include "ui/gfx/codec/jpeg_codec.h" |
| 15 | #include "ui/gfx/codec/png_codec.h" |
| 16 | #include "ui/gfx/gdi_util.h" |
[email protected] | edc531f9 | 2011-03-18 17:52:23 | [diff] [blame] | 17 | #include "ui/gfx/point.h" |
[email protected] | 08397d5 | 2011-02-05 01:53:38 | [diff] [blame] | 18 | #include "ui/gfx/rect.h" |
[email protected] | edc531f9 | 2011-03-18 17:52:23 | [diff] [blame] | 19 | #include "ui/gfx/size.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 20 | |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 21 | namespace { |
| 22 | const int kCustomGdiCommentSignature = 0xdeadbabe; |
| 23 | struct PageBreakRecord { |
| 24 | int signature; |
| 25 | enum PageBreakType { |
| 26 | START_PAGE, |
| 27 | END_PAGE, |
| 28 | } type; |
| 29 | explicit PageBreakRecord(PageBreakType type_in) |
| 30 | : signature(kCustomGdiCommentSignature), type(type_in) { |
| 31 | } |
| 32 | bool IsValid() const { |
| 33 | return (signature == kCustomGdiCommentSignature) && |
| 34 | (type >= START_PAGE) && (type <= END_PAGE); |
| 35 | } |
| 36 | }; |
| 37 | } |
| 38 | |
[email protected] | 0e0fca3 | 2009-07-06 15:25:50 | [diff] [blame] | 39 | namespace printing { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 40 | |
[email protected] | 38bba4f | 2010-03-12 05:29:07 | [diff] [blame] | 41 | bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits, |
| 42 | int size) { |
| 43 | BOOL supported = FALSE; |
| 44 | if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape), |
| 45 | reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) { |
| 46 | ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits), |
| 47 | sizeof(supported), reinterpret_cast<LPSTR>(&supported)); |
| 48 | } |
| 49 | return !!supported; |
| 50 | } |
| 51 | |
[email protected] | 830cf74 | 2011-04-01 16:06:25 | [diff] [blame^] | 52 | Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | Emf::~Emf() { |
[email protected] | 481edc5 | 2011-03-22 06:36:58 | [diff] [blame] | 56 | DCHECK(!hdc_); |
| 57 | if (emf_) |
| 58 | DeleteEnhMetaFile(emf_); |
| 59 | } |
| 60 | |
| 61 | bool Emf::InitToFile(const FilePath& metafile_path) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 62 | DCHECK(!emf_ && !hdc_); |
[email protected] | 481edc5 | 2011-03-22 06:36:58 | [diff] [blame] | 63 | hdc_ = CreateEnhMetaFile(NULL, metafile_path.value().c_str(), NULL, NULL); |
| 64 | DCHECK(hdc_); |
| 65 | return hdc_ != NULL; |
| 66 | } |
| 67 | |
| 68 | bool Emf::InitFromFile(const FilePath& metafile_path) { |
| 69 | DCHECK(!emf_ && !hdc_); |
| 70 | emf_ = GetEnhMetaFile(metafile_path.value().c_str()); |
| 71 | DCHECK(emf_); |
| 72 | return emf_ != NULL; |
| 73 | } |
| 74 | |
| 75 | bool Emf::Init() { |
| 76 | DCHECK(!emf_ && !hdc_); |
| 77 | hdc_ = CreateEnhMetaFile(NULL, NULL, NULL, NULL); |
| 78 | DCHECK(hdc_); |
| 79 | return hdc_ != NULL; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 80 | } |
| 81 | |
[email protected] | 89eff96a | 2011-03-17 23:22:06 | [diff] [blame] | 82 | bool Emf::InitFromData(const void* src_buffer, uint32 src_buffer_size) { |
[email protected] | e8980a5 | 2010-10-07 20:11:24 | [diff] [blame] | 83 | DCHECK(!emf_ && !hdc_); |
| 84 | emf_ = SetEnhMetaFileBits(src_buffer_size, |
| 85 | reinterpret_cast<const BYTE*>(src_buffer)); |
[email protected] | e8980a5 | 2010-10-07 20:11:24 | [diff] [blame] | 86 | return emf_ != NULL; |
| 87 | } |
| 88 | |
[email protected] | cdd19f5 | 2011-03-19 01:04:57 | [diff] [blame] | 89 | bool Emf::FinishDocument() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 90 | DCHECK(!emf_ && hdc_); |
| 91 | emf_ = CloseEnhMetaFile(hdc_); |
| 92 | DCHECK(emf_); |
| 93 | hdc_ = NULL; |
| 94 | return emf_ != NULL; |
| 95 | } |
| 96 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 97 | bool Emf::Playback(HDC hdc, const RECT* rect) const { |
| 98 | DCHECK(emf_ && !hdc_); |
| 99 | RECT bounds; |
| 100 | if (!rect) { |
| 101 | // Get the natural bounds of the EMF buffer. |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 102 | bounds = GetPageBounds(1).ToRECT(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 103 | rect = &bounds; |
| 104 | } |
| 105 | return PlayEnhMetaFile(hdc, emf_, rect) != 0; |
| 106 | } |
| 107 | |
| 108 | bool Emf::SafePlayback(HDC context) const { |
| 109 | DCHECK(emf_ && !hdc_); |
| 110 | XFORM base_matrix; |
| 111 | if (!GetWorldTransform(context, &base_matrix)) { |
| 112 | NOTREACHED(); |
| 113 | return false; |
| 114 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 115 | return EnumEnhMetaFile(context, |
| 116 | emf_, |
| 117 | &Emf::SafePlaybackProc, |
| 118 | reinterpret_cast<void*>(&base_matrix), |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 119 | &GetPageBounds(1).ToRECT()) != 0; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 120 | } |
| 121 | |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 122 | gfx::Rect Emf::GetPageBounds(unsigned int page_number) const { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 123 | DCHECK(emf_ && !hdc_); |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 124 | DCHECK_EQ(1U, page_number); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 125 | ENHMETAHEADER header; |
| 126 | if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) { |
| 127 | NOTREACHED(); |
| 128 | return gfx::Rect(); |
| 129 | } |
| 130 | if (header.rclBounds.left == 0 && |
| 131 | header.rclBounds.top == 0 && |
| 132 | header.rclBounds.right == -1 && |
| 133 | header.rclBounds.bottom == -1) { |
| 134 | // A freshly created EMF buffer that has no drawing operation has invalid |
| 135 | // bounds. Instead of having an (0,0) size, it has a (-1,-1) size. Detect |
| 136 | // this special case and returns an empty Rect instead of an invalid one. |
| 137 | return gfx::Rect(); |
| 138 | } |
| 139 | return gfx::Rect(header.rclBounds.left, |
| 140 | header.rclBounds.top, |
| 141 | header.rclBounds.right - header.rclBounds.left, |
| 142 | header.rclBounds.bottom - header.rclBounds.top); |
| 143 | } |
| 144 | |
[email protected] | b5ab398 | 2010-02-16 23:58:27 | [diff] [blame] | 145 | uint32 Emf::GetDataSize() const { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 146 | DCHECK(emf_ && !hdc_); |
| 147 | return GetEnhMetaFileBits(emf_, 0, NULL); |
| 148 | } |
| 149 | |
[email protected] | b5ab398 | 2010-02-16 23:58:27 | [diff] [blame] | 150 | bool Emf::GetData(void* buffer, uint32 size) const { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 151 | DCHECK(emf_ && !hdc_); |
| 152 | DCHECK(buffer && size); |
[email protected] | b5ab398 | 2010-02-16 23:58:27 | [diff] [blame] | 153 | uint32 size2 = |
| 154 | GetEnhMetaFileBits(emf_, size, reinterpret_cast<BYTE*>(buffer)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 155 | DCHECK(size2 == size); |
| 156 | return size2 == size && size2 != 0; |
| 157 | } |
| 158 | |
[email protected] | 96fddd8 | 2011-03-24 23:37:45 | [diff] [blame] | 159 | bool Emf::GetDataAsVector(std::vector<uint8>* buffer) const { |
[email protected] | b5ab398 | 2010-02-16 23:58:27 | [diff] [blame] | 160 | uint32 size = GetDataSize(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 161 | if (!size) |
| 162 | return false; |
| 163 | |
| 164 | buffer->resize(size); |
| 165 | if (!GetData(&buffer->front(), size)) |
| 166 | return false; |
| 167 | return true; |
| 168 | } |
| 169 | |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 170 | bool Emf::SaveTo(const FilePath& file_path) const { |
| 171 | HANDLE file = CreateFile(file_path.value().c_str(), GENERIC_WRITE, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 172 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
| 173 | CREATE_ALWAYS, 0, NULL); |
| 174 | if (file == INVALID_HANDLE_VALUE) |
| 175 | return false; |
| 176 | |
| 177 | bool success = false; |
| 178 | std::vector<uint8> buffer; |
[email protected] | 96fddd8 | 2011-03-24 23:37:45 | [diff] [blame] | 179 | if (GetDataAsVector(&buffer)) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 180 | DWORD written = 0; |
| 181 | if (WriteFile(file, &*buffer.begin(), static_cast<DWORD>(buffer.size()), |
| 182 | &written, NULL) && |
| 183 | written == buffer.size()) { |
| 184 | success = true; |
| 185 | } |
| 186 | } |
| 187 | CloseHandle(file); |
| 188 | return success; |
| 189 | } |
| 190 | |
| 191 | int CALLBACK Emf::SafePlaybackProc(HDC hdc, |
| 192 | HANDLETABLE* handle_table, |
| 193 | const ENHMETARECORD* record, |
| 194 | int objects_count, |
| 195 | LPARAM param) { |
| 196 | const XFORM* base_matrix = reinterpret_cast<const XFORM*>(param); |
| 197 | EnumerationContext context; |
| 198 | context.handle_table = handle_table; |
| 199 | context.objects_count = objects_count; |
| 200 | context.hdc = hdc; |
| 201 | Record record_instance(&context, record); |
| 202 | bool success = record_instance.SafePlayback(base_matrix); |
| 203 | DCHECK(success); |
| 204 | return 1; |
| 205 | } |
| 206 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 207 | Emf::Record::Record(const EnumerationContext* context, |
| 208 | const ENHMETARECORD* record) |
| 209 | : record_(record), |
| 210 | context_(context) { |
| 211 | DCHECK(record_); |
| 212 | } |
| 213 | |
| 214 | bool Emf::Record::Play() const { |
| 215 | return 0 != PlayEnhMetaFileRecord(context_->hdc, |
| 216 | context_->handle_table, |
| 217 | record_, |
| 218 | context_->objects_count); |
| 219 | } |
| 220 | |
| 221 | bool Emf::Record::SafePlayback(const XFORM* base_matrix) const { |
| 222 | // For EMF field description, see [MS-EMF] Enhanced Metafile Format |
| 223 | // Specification. |
| 224 | // |
| 225 | // This is the second major EMF breakage I get; the first one being |
| 226 | // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored. |
| 227 | // |
| 228 | // This function is the guts of the fix for bug 1186598. Some printer drivers |
| 229 | // somehow choke on certain EMF records, but calling the corresponding |
| 230 | // function directly on the printer HDC is fine. Still, playing the EMF record |
| 231 | // fails. Go figure. |
| 232 | // |
| 233 | // The main issue is that SetLayout is totally unsupported on these printers |
| 234 | // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is |
| 235 | // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!) |
| 236 | // Damn. |
| 237 | // |
| 238 | // So I resorted to manually parse the EMF records and play them one by one. |
| 239 | // The issue with this method compared to using PlayEnhMetaFile to play back |
| 240 | // an EMF buffer is that the later silently fixes the matrix to take in |
| 241 | // account the matrix currently loaded at the time of the call. |
| 242 | // The matrix magic is done transparently when using PlayEnhMetaFile but since |
| 243 | // I'm processing one field at a time, I need to do the fixup myself. Note |
| 244 | // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when |
| 245 | // called inside an EnumEnhMetaFile loop. Go figure (bis). |
| 246 | // |
| 247 | // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need |
| 248 | // to fix the matrix according to the matrix previously loaded before playing |
| 249 | // back the buffer. Otherwise, the previously loaded matrix would be ignored |
| 250 | // and the EMF buffer would always be played back at its native resolution. |
| 251 | // Duh. |
| 252 | // |
| 253 | // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that |
| 254 | // could remain. |
| 255 | // |
[email protected] | 38bba4f | 2010-03-12 05:29:07 | [diff] [blame] | 256 | // Another tweak we make is for JPEGs/PNGs in calls to StretchDIBits. |
| 257 | // (Our Pepper plugin code uses a JPEG). If the printer does not support |
| 258 | // JPEGs/PNGs natively we decompress the JPEG/PNG and then set it to the |
| 259 | // device. |
| 260 | // TODO(sanjeevr): We should also add JPEG/PNG support for SetSIBitsToDevice |
| 261 | // |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 262 | // We also process any custom EMR_GDICOMMENT records which are our |
| 263 | // placeholders for StartPage and EndPage. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 264 | // Note: I should probably care about view ports and clipping, eventually. |
| 265 | bool res; |
| 266 | switch (record()->iType) { |
[email protected] | 38bba4f | 2010-03-12 05:29:07 | [diff] [blame] | 267 | case EMR_STRETCHDIBITS: { |
| 268 | const EMRSTRETCHDIBITS * sdib_record = |
| 269 | reinterpret_cast<const EMRSTRETCHDIBITS*>(record()); |
| 270 | const BYTE* record_start = reinterpret_cast<const BYTE *>(record()); |
| 271 | const BITMAPINFOHEADER *bmih = |
| 272 | reinterpret_cast<const BITMAPINFOHEADER *>(record_start + |
| 273 | sdib_record->offBmiSrc); |
| 274 | const BYTE* bits = record_start + sdib_record->offBitsSrc; |
| 275 | bool play_normally = true; |
| 276 | res = false; |
| 277 | HDC hdc = context_->hdc; |
| 278 | scoped_ptr<SkBitmap> bitmap; |
| 279 | if (bmih->biCompression == BI_JPEG) { |
| 280 | if (!DIBFormatNativelySupported(hdc, CHECKJPEGFORMAT, bits, |
| 281 | bmih->biSizeImage)) { |
| 282 | play_normally = false; |
| 283 | base::TimeTicks start_time = base::TimeTicks::Now(); |
| 284 | bitmap.reset(gfx::JPEGCodec::Decode(bits, bmih->biSizeImage)); |
| 285 | UMA_HISTOGRAM_TIMES("Printing.JPEGDecompressTime", |
| 286 | base::TimeTicks::Now() - start_time); |
| 287 | } |
| 288 | } else if (bmih->biCompression == BI_PNG) { |
| 289 | if (!DIBFormatNativelySupported(hdc, CHECKPNGFORMAT, bits, |
| 290 | bmih->biSizeImage)) { |
| 291 | play_normally = false; |
| 292 | bitmap.reset(new SkBitmap()); |
| 293 | base::TimeTicks start_time = base::TimeTicks::Now(); |
| 294 | gfx::PNGCodec::Decode(bits, bmih->biSizeImage, bitmap.get()); |
| 295 | UMA_HISTOGRAM_TIMES("Printing.PNGDecompressTime", |
| 296 | base::TimeTicks::Now() - start_time); |
| 297 | } |
| 298 | } |
| 299 | if (!play_normally) { |
| 300 | DCHECK(bitmap.get()); |
| 301 | if (bitmap.get()) { |
| 302 | SkAutoLockPixels lock(*bitmap.get()); |
| 303 | DCHECK_EQ(bitmap->getConfig(), SkBitmap::kARGB_8888_Config); |
| 304 | const uint32_t* pixels = |
| 305 | static_cast<const uint32_t*>(bitmap->getPixels()); |
| 306 | if (pixels == NULL) { |
| 307 | NOTREACHED(); |
| 308 | return false; |
| 309 | } |
| 310 | BITMAPINFOHEADER bmi = {0}; |
| 311 | gfx::CreateBitmapHeader(bitmap->width(), bitmap->height(), &bmi); |
| 312 | res = (0 != StretchDIBits(hdc, sdib_record->xDest, sdib_record->yDest, |
| 313 | sdib_record->cxDest, |
| 314 | sdib_record->cyDest, sdib_record->xSrc, |
| 315 | sdib_record->ySrc, |
| 316 | sdib_record->cxSrc, sdib_record->cySrc, |
| 317 | pixels, |
| 318 | reinterpret_cast<const BITMAPINFO *>(&bmi), |
| 319 | sdib_record->iUsageSrc, |
| 320 | sdib_record->dwRop)); |
| 321 | } |
| 322 | } else { |
| 323 | res = Play(); |
| 324 | } |
| 325 | break; |
| 326 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 327 | case EMR_SETWORLDTRANSFORM: { |
| 328 | DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM)); |
| 329 | const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm); |
| 330 | HDC hdc = context_->hdc; |
| 331 | if (base_matrix) { |
| 332 | res = 0 != SetWorldTransform(hdc, base_matrix) && |
| 333 | ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY); |
| 334 | } else { |
| 335 | res = 0 != SetWorldTransform(hdc, xform); |
| 336 | } |
| 337 | break; |
| 338 | } |
| 339 | case EMR_MODIFYWORLDTRANSFORM: { |
| 340 | DCHECK_EQ(record()->nSize, |
| 341 | sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD)); |
| 342 | const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm); |
| 343 | const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1); |
| 344 | HDC hdc = context_->hdc; |
| 345 | switch (*option) { |
| 346 | case MWT_IDENTITY: |
| 347 | if (base_matrix) { |
| 348 | res = 0 != SetWorldTransform(hdc, base_matrix); |
| 349 | } else { |
| 350 | res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY); |
| 351 | } |
| 352 | break; |
| 353 | case MWT_LEFTMULTIPLY: |
| 354 | case MWT_RIGHTMULTIPLY: |
| 355 | res = 0 != ModifyWorldTransform(hdc, xform, *option); |
| 356 | break; |
| 357 | case 4: // MWT_SET |
| 358 | if (base_matrix) { |
| 359 | res = 0 != SetWorldTransform(hdc, base_matrix) && |
| 360 | ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY); |
| 361 | } else { |
| 362 | res = 0 != SetWorldTransform(hdc, xform); |
| 363 | } |
| 364 | break; |
| 365 | default: |
| 366 | res = false; |
| 367 | break; |
| 368 | } |
| 369 | break; |
| 370 | } |
| 371 | case EMR_SETLAYOUT: |
| 372 | // Ignore it. |
| 373 | res = true; |
| 374 | break; |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 375 | case EMR_GDICOMMENT: { |
| 376 | const EMRGDICOMMENT* comment_record = |
| 377 | reinterpret_cast<const EMRGDICOMMENT*>(record()); |
| 378 | if (comment_record->cbData == sizeof(PageBreakRecord)) { |
| 379 | const PageBreakRecord* page_break_record = |
| 380 | reinterpret_cast<const PageBreakRecord*>(comment_record->Data); |
| 381 | if (page_break_record && page_break_record->IsValid()) { |
| 382 | if (page_break_record->type == PageBreakRecord::START_PAGE) { |
| 383 | res = !!::StartPage(context_->hdc); |
| 384 | } else if (page_break_record->type == PageBreakRecord::END_PAGE) { |
| 385 | res = !!::EndPage(context_->hdc); |
| 386 | } else { |
| 387 | res = false; |
| 388 | NOTREACHED(); |
| 389 | } |
| 390 | } else { |
| 391 | res = Play(); |
| 392 | } |
[email protected] | b2b0fce | 2011-01-12 16:34:40 | [diff] [blame] | 393 | } else { |
| 394 | res = true; |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 395 | } |
| 396 | break; |
| 397 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 398 | default: { |
| 399 | res = Play(); |
| 400 | break; |
| 401 | } |
| 402 | } |
| 403 | return res; |
| 404 | } |
| 405 | |
[email protected] | d2fdcf0 | 2011-03-21 22:16:43 | [diff] [blame] | 406 | skia::PlatformDevice* Emf::StartPageForVectorCanvas( |
| 407 | const gfx::Size& page_size, const gfx::Point& content_origin, |
| 408 | const float& scale_factor) { |
| 409 | if (!StartPage(page_size, content_origin, scale_factor)) |
| 410 | return NULL; |
| 411 | |
| 412 | return skia::VectorPlatformDeviceFactory::CreateDevice(page_size.width(), |
| 413 | page_size.height(), |
| 414 | true, hdc_); |
| 415 | } |
| 416 | |
[email protected] | edc531f9 | 2011-03-18 17:52:23 | [diff] [blame] | 417 | bool Emf::StartPage(const gfx::Size& /*page_size*/, |
| 418 | const gfx::Point& /*content_origin*/, |
| 419 | const float& scale_factor) { |
[email protected] | d2fdcf0 | 2011-03-21 22:16:43 | [diff] [blame] | 420 | DCHECK_EQ(1.0f, scale_factor); // We don't support scaling here. |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 421 | DCHECK(hdc_); |
| 422 | if (!hdc_) |
| 423 | return false; |
[email protected] | 830cf74 | 2011-04-01 16:06:25 | [diff] [blame^] | 424 | page_count_++; |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 425 | PageBreakRecord record(PageBreakRecord::START_PAGE); |
| 426 | return !!GdiComment(hdc_, sizeof(record), |
| 427 | reinterpret_cast<const BYTE *>(&record)); |
| 428 | } |
| 429 | |
[email protected] | 8f17cd3e | 2011-03-16 01:39:42 | [diff] [blame] | 430 | bool Emf::FinishPage() { |
[email protected] | 2aa8e18 | 2010-07-12 16:25:04 | [diff] [blame] | 431 | DCHECK(hdc_); |
| 432 | if (!hdc_) |
| 433 | return false; |
| 434 | PageBreakRecord record(PageBreakRecord::END_PAGE); |
| 435 | return !!GdiComment(hdc_, sizeof(record), |
| 436 | reinterpret_cast<const BYTE *>(&record)); |
| 437 | } |
| 438 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 439 | Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) { |
| 440 | context_.handle_table = NULL; |
| 441 | context_.objects_count = 0; |
| 442 | context_.hdc = NULL; |
| 443 | items_.clear(); |
| 444 | if (!EnumEnhMetaFile(context, |
| 445 | emf.emf(), |
| 446 | &Emf::Enumerator::EnhMetaFileProc, |
| 447 | reinterpret_cast<void*>(this), |
| 448 | rect)) { |
| 449 | NOTREACHED(); |
| 450 | items_.clear(); |
| 451 | } |
| 452 | DCHECK_EQ(context_.hdc, context); |
| 453 | } |
| 454 | |
| 455 | Emf::Enumerator::const_iterator Emf::Enumerator::begin() const { |
| 456 | return items_.begin(); |
| 457 | } |
| 458 | |
| 459 | Emf::Enumerator::const_iterator Emf::Enumerator::end() const { |
| 460 | return items_.end(); |
| 461 | } |
| 462 | |
| 463 | int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc, |
| 464 | HANDLETABLE* handle_table, |
| 465 | const ENHMETARECORD* record, |
| 466 | int objects_count, |
| 467 | LPARAM param) { |
| 468 | Enumerator& emf = *reinterpret_cast<Enumerator*>(param); |
| 469 | if (!emf.context_.handle_table) { |
| 470 | DCHECK(!emf.context_.handle_table); |
| 471 | DCHECK(!emf.context_.objects_count); |
| 472 | emf.context_.handle_table = handle_table; |
| 473 | emf.context_.objects_count = objects_count; |
| 474 | emf.context_.hdc = hdc; |
| 475 | } else { |
| 476 | DCHECK_EQ(emf.context_.handle_table, handle_table); |
| 477 | DCHECK_EQ(emf.context_.objects_count, objects_count); |
| 478 | DCHECK_EQ(emf.context_.hdc, hdc); |
| 479 | } |
| 480 | emf.items_.push_back(Record(&emf.context_, record)); |
| 481 | return 1; |
| 482 | } |
| 483 | |
[email protected] | 0e0fca3 | 2009-07-06 15:25:50 | [diff] [blame] | 484 | } // namespace printing |