Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef PRINTING_EMF_WIN_H_ |
| 6 | #define PRINTING_EMF_WIN_H_ |
| 7 | |
| 8 | #include <windows.h> |
| 9 | |
| 10 | #include <vector> |
| 11 | |
| 12 | #include "base/basictypes.h" |
| 13 | #include "base/compiler_specific.h" |
| 14 | #include "base/gtest_prod_util.h" |
| 15 | #include "printing/metafile.h" |
| 16 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 17 | namespace base { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 18 | class FilePath; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 19 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 20 | |
| 21 | namespace gfx { |
| 22 | class Rect; |
| 23 | class Size; |
| 24 | } |
| 25 | |
| 26 | namespace printing { |
| 27 | |
| 28 | // http://msdn2.microsoft.com/en-us/library/ms535522.aspx |
| 29 | // Windows 2000/XP: When a page in a spooled file exceeds approximately 350 |
| 30 | // MB, it can fail to print and not send an error message. |
| 31 | const size_t kMetafileMaxSize = 350*1024*1024; |
| 32 | |
| 33 | // Simple wrapper class that manage an EMF data stream and its virtual HDC. |
| 34 | class PRINTING_EXPORT Emf : public Metafile { |
| 35 | public: |
| 36 | class Record; |
| 37 | class Enumerator; |
| 38 | struct EnumerationContext; |
| 39 | |
| 40 | // Generates a virtual HDC that will record every GDI commands and compile |
| 41 | // it in a EMF data stream. |
| 42 | Emf(); |
| 43 | virtual ~Emf(); |
| 44 | |
| 45 | // Generates a new metafile that will record every GDI command, and will |
| 46 | // be saved to |metafile_path|. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 47 | virtual bool InitToFile(const base::FilePath& metafile_path); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 48 | |
| 49 | // Initializes the Emf with the data in |metafile_path|. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 50 | virtual bool InitFromFile(const base::FilePath& metafile_path); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 51 | |
| 52 | // Metafile methods. |
| 53 | virtual bool Init() OVERRIDE; |
| 54 | virtual bool InitFromData(const void* src_buffer, |
| 55 | uint32 src_buffer_size) OVERRIDE; |
| 56 | |
Torne (Richard Coles) | 424c4d7 | 2013-08-30 15:14:49 +0100 | [diff] [blame] | 57 | virtual SkBaseDevice* StartPageForVectorCanvas( |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 58 | const gfx::Size& page_size, const gfx::Rect& content_area, |
| 59 | const float& scale_factor) OVERRIDE; |
| 60 | // Inserts a custom GDICOMMENT records indicating StartPage/EndPage calls |
| 61 | // (since StartPage and EndPage do not work in a metafile DC). Only valid |
| 62 | // when hdc_ is non-NULL. |page_size|, |content_area|, and |scale_factor| are |
| 63 | // ignored. |
| 64 | virtual bool StartPage(const gfx::Size& page_size, |
| 65 | const gfx::Rect& content_area, |
| 66 | const float& scale_factor) OVERRIDE; |
| 67 | virtual bool FinishPage() OVERRIDE; |
| 68 | virtual bool FinishDocument() OVERRIDE; |
| 69 | |
| 70 | virtual uint32 GetDataSize() const OVERRIDE; |
| 71 | virtual bool GetData(void* buffer, uint32 size) const OVERRIDE; |
| 72 | |
| 73 | // Saves the EMF data to a file as-is. It is recommended to use the .emf file |
| 74 | // extension but it is not enforced. This function synchronously writes to the |
| 75 | // file. For testing only. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 76 | virtual bool SaveTo(const base::FilePath& file_path) const OVERRIDE; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 77 | |
| 78 | // Should be passed to Playback to keep the exact same size. |
| 79 | virtual gfx::Rect GetPageBounds(unsigned int page_number) const OVERRIDE; |
| 80 | |
| 81 | virtual unsigned int GetPageCount() const OVERRIDE { |
| 82 | return page_count_; |
| 83 | } |
| 84 | |
| 85 | virtual HDC context() const OVERRIDE { |
| 86 | return hdc_; |
| 87 | } |
| 88 | |
| 89 | virtual bool Playback(HDC hdc, const RECT* rect) const OVERRIDE; |
| 90 | virtual bool SafePlayback(HDC hdc) const OVERRIDE; |
| 91 | |
| 92 | virtual HENHMETAFILE emf() const OVERRIDE { |
| 93 | return emf_; |
| 94 | } |
| 95 | |
| 96 | // Returns true if metafile contains alpha blend. |
| 97 | bool IsAlphaBlendUsed() const; |
| 98 | |
| 99 | // Returns new metafile with only bitmap created by playback of the current |
| 100 | // metafile. Returns NULL if fails. |
| 101 | Emf* RasterizeMetafile(int raster_area_in_pixels) const; |
| 102 | |
| 103 | // Returns new metafile where AlphaBlend replaced by bitmaps. Returns NULL |
| 104 | // if fails. |
| 105 | Emf* RasterizeAlphaBlend() const; |
| 106 | |
| 107 | private: |
| 108 | FRIEND_TEST_ALL_PREFIXES(EmfTest, DC); |
| 109 | FRIEND_TEST_ALL_PREFIXES(EmfPrintingTest, PageBreak); |
| 110 | FRIEND_TEST_ALL_PREFIXES(EmfTest, FileBackedEmf); |
| 111 | |
| 112 | // Retrieves the underlying data stream. It is a helper function. |
| 113 | bool GetDataAsVector(std::vector<uint8>* buffer) const; |
| 114 | |
| 115 | // Playbacks safely one EMF record. |
| 116 | static int CALLBACK SafePlaybackProc(HDC hdc, |
| 117 | HANDLETABLE* handle_table, |
| 118 | const ENHMETARECORD* record, |
| 119 | int objects_count, |
| 120 | LPARAM param); |
| 121 | |
| 122 | // Compiled EMF data handle. |
| 123 | HENHMETAFILE emf_; |
| 124 | |
| 125 | // Valid when generating EMF data through a virtual HDC. |
| 126 | HDC hdc_; |
| 127 | |
| 128 | int page_count_; |
| 129 | |
| 130 | DISALLOW_COPY_AND_ASSIGN(Emf); |
| 131 | }; |
| 132 | |
| 133 | struct Emf::EnumerationContext { |
| 134 | EnumerationContext(); |
| 135 | |
| 136 | HANDLETABLE* handle_table; |
| 137 | int objects_count; |
| 138 | HDC hdc; |
| 139 | const XFORM* base_matrix; |
| 140 | int dc_on_page_start; |
| 141 | }; |
| 142 | |
| 143 | // One EMF record. It keeps pointers to the EMF buffer held by Emf::emf_. |
| 144 | // The entries become invalid once Emf::CloseEmf() is called. |
| 145 | class PRINTING_EXPORT Emf::Record { |
| 146 | public: |
| 147 | // Plays the record. |
| 148 | bool Play(EnumerationContext* context) const; |
| 149 | |
| 150 | // Plays the record working around quirks with SetLayout, |
| 151 | // SetWorldTransform and ModifyWorldTransform. See implementation for details. |
| 152 | bool SafePlayback(EnumerationContext* context) const; |
| 153 | |
| 154 | // Access the underlying EMF record. |
| 155 | const ENHMETARECORD* record() const { return record_; } |
| 156 | |
| 157 | protected: |
| 158 | explicit Record(const ENHMETARECORD* record); |
| 159 | |
| 160 | private: |
| 161 | friend class Emf; |
| 162 | friend class Enumerator; |
| 163 | const ENHMETARECORD* record_; |
| 164 | }; |
| 165 | |
| 166 | // Retrieves individual records out of a Emf buffer. The main use is to skip |
| 167 | // over records that are unsupported on a specific printer or to play back |
| 168 | // only a part of an EMF buffer. |
| 169 | class PRINTING_EXPORT Emf::Enumerator { |
| 170 | public: |
| 171 | // Iterator type used for iterating the records. |
| 172 | typedef std::vector<Record>::const_iterator const_iterator; |
| 173 | |
| 174 | // Enumerates the records at construction time. |hdc| and |rect| are |
| 175 | // both optional at the same time or must both be valid. |
| 176 | // Warning: |emf| must be kept valid for the time this object is alive. |
| 177 | Enumerator(const Emf& emf, HDC hdc, const RECT* rect); |
| 178 | |
| 179 | // Retrieves the first Record. |
| 180 | const_iterator begin() const; |
| 181 | |
| 182 | // Retrieves the end of the array. |
| 183 | const_iterator end() const; |
| 184 | |
| 185 | private: |
| 186 | FRIEND_TEST_ALL_PREFIXES(EmfPrintingTest, Enumerate); |
| 187 | |
| 188 | // Processes one EMF record and saves it in the items_ array. |
| 189 | static int CALLBACK EnhMetaFileProc(HDC hdc, |
| 190 | HANDLETABLE* handle_table, |
| 191 | const ENHMETARECORD* record, |
| 192 | int objects_count, |
| 193 | LPARAM param); |
| 194 | |
| 195 | // The collection of every EMF records in the currently loaded EMF buffer. |
| 196 | // Initialized by Enumerate(). It keeps pointers to the EMF buffer held by |
| 197 | // Emf::emf_. The entries become invalid once Emf::CloseEmf() is called. |
| 198 | std::vector<Record> items_; |
| 199 | |
| 200 | EnumerationContext context_; |
| 201 | |
| 202 | DISALLOW_COPY_AND_ASSIGN(Enumerator); |
| 203 | }; |
| 204 | |
| 205 | } // namespace printing |
| 206 | |
| 207 | #endif // PRINTING_EMF_WIN_H_ |