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 #include "printing/emf_win.h" 6 7 // For quick access. 8 #include <wingdi.h> 9 #include <winspool.h> 10 11 #include <string> 12 13 #include "base/basictypes.h" 14 #include "base/files/file_path.h" 15 #include "base/files/file_util.h" 16 #include "base/files/scoped_temp_dir.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/path_service.h" 19 #include "base/win/scoped_hdc.h" 20 #include "printing/printing_context.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "ui/gfx/point.h" 23 #include "ui/gfx/size.h" 24 25 namespace printing { 26 27 namespace { 28 29 // This test is automatically disabled if no printer named "UnitTest Printer" is 30 // available. 31 class EmfPrintingTest : public testing::Test, public PrintingContext::Delegate { 32 public: 33 typedef testing::Test Parent; 34 static bool IsTestCaseDisabled() { 35 // It is assumed this printer is a HP Color LaserJet 4550 PCL or 4700. 36 HDC hdc = CreateDC(L"WINSPOOL", L"UnitTest Printer", NULL, NULL); 37 if (!hdc) 38 return true; 39 DeleteDC(hdc); 40 return false; 41 } 42 43 // PrintingContext::Delegate methods. 44 virtual gfx::NativeView GetParentView() OVERRIDE { return NULL; } 45 virtual std::string GetAppLocale() OVERRIDE { return std::string(); } 46 }; 47 48 const uint32 EMF_HEADER_SIZE = 128; 49 50 } // namespace 51 52 TEST(EmfTest, DC) { 53 // Simplest use case. 54 uint32 size; 55 std::vector<char> data; 56 { 57 Emf emf; 58 EXPECT_TRUE(emf.Init()); 59 EXPECT_TRUE(emf.context() != NULL); 60 // An empty EMF is invalid, so we put at least a rectangle in it. 61 ::Rectangle(emf.context(), 10, 10, 190, 190); 62 EXPECT_TRUE(emf.FinishDocument()); 63 size = emf.GetDataSize(); 64 EXPECT_GT(size, EMF_HEADER_SIZE); 65 EXPECT_TRUE(emf.GetDataAsVector(&data)); 66 EXPECT_EQ(data.size(), size); 67 } 68 69 // Playback the data. 70 Emf emf; 71 EXPECT_TRUE(emf.InitFromData(&data.front(), size)); 72 HDC hdc = CreateCompatibleDC(NULL); 73 EXPECT_TRUE(hdc); 74 RECT output_rect = {0, 0, 10, 10}; 75 EXPECT_TRUE(emf.Playback(hdc, &output_rect)); 76 EXPECT_TRUE(DeleteDC(hdc)); 77 } 78 79 // Disabled if no "UnitTest printer" exist. Useful to reproduce bug 1186598. 80 TEST_F(EmfPrintingTest, Enumerate) { 81 if (IsTestCaseDisabled()) 82 return; 83 84 PrintSettings settings; 85 86 // My test case is a HP Color LaserJet 4550 PCL. 87 settings.set_device_name(L"UnitTest Printer"); 88 89 // Initialize it. 90 scoped_ptr<PrintingContext> context(PrintingContext::Create(this)); 91 EXPECT_EQ(context->InitWithSettings(settings), PrintingContext::OK); 92 93 base::FilePath emf_file; 94 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &emf_file)); 95 emf_file = emf_file.Append(FILE_PATH_LITERAL("printing")) 96 .Append(FILE_PATH_LITERAL("test")) 97 .Append(FILE_PATH_LITERAL("data")) 98 .Append(FILE_PATH_LITERAL("test4.emf")); 99 // Load any EMF with an image. 100 Emf emf; 101 std::string emf_data; 102 base::ReadFileToString(emf_file, &emf_data); 103 ASSERT_TRUE(emf_data.size()); 104 EXPECT_TRUE(emf.InitFromData(&emf_data[0], emf_data.size())); 105 106 // This will print to file. The reason is that when running inside a 107 // unit_test, PrintingContext automatically dumps its files to the 108 // current directory. 109 // TODO(maruel): Clean the .PRN file generated in current directory. 110 context->NewDocument(L"EmfTest.Enumerate"); 111 context->NewPage(); 112 // Process one at a time. 113 RECT page_bounds = emf.GetPageBounds(1).ToRECT(); 114 Emf::Enumerator emf_enum(emf, context->context(), &page_bounds); 115 for (Emf::Enumerator::const_iterator itr = emf_enum.begin(); 116 itr != emf_enum.end(); 117 ++itr) { 118 // To help debugging. 119 ptrdiff_t index = itr - emf_enum.begin(); 120 // If you get this assert, you need to lookup iType in wingdi.h. It starts 121 // with EMR_HEADER. 122 EMR_HEADER; 123 EXPECT_TRUE(itr->SafePlayback(&emf_enum.context_)) << 124 " index: " << index << " type: " << itr->record()->iType; 125 } 126 context->PageDone(); 127 context->DocumentDone(); 128 } 129 130 // Disabled if no "UnitTest printer" exists. 131 TEST_F(EmfPrintingTest, PageBreak) { 132 base::win::ScopedCreateDC dc( 133 CreateDC(L"WINSPOOL", L"UnitTest Printer", NULL, NULL)); 134 if (!dc.Get()) 135 return; 136 uint32 size; 137 std::vector<char> data; 138 { 139 Emf emf; 140 EXPECT_TRUE(emf.Init()); 141 EXPECT_TRUE(emf.context() != NULL); 142 int pages = 3; 143 while (pages) { 144 EXPECT_TRUE(emf.StartPage(gfx::Size(), gfx::Rect(), 1)); 145 ::Rectangle(emf.context(), 10, 10, 190, 190); 146 EXPECT_TRUE(emf.FinishPage()); 147 --pages; 148 } 149 EXPECT_EQ(3U, emf.GetPageCount()); 150 EXPECT_TRUE(emf.FinishDocument()); 151 size = emf.GetDataSize(); 152 EXPECT_TRUE(emf.GetDataAsVector(&data)); 153 EXPECT_EQ(data.size(), size); 154 } 155 156 // Playback the data. 157 DOCINFO di = {0}; 158 di.cbSize = sizeof(DOCINFO); 159 di.lpszDocName = L"Test Job"; 160 int job_id = ::StartDoc(dc.Get(), &di); 161 Emf emf; 162 EXPECT_TRUE(emf.InitFromData(&data.front(), size)); 163 EXPECT_TRUE(emf.SafePlayback(dc.Get())); 164 ::EndDoc(dc.Get()); 165 // Since presumably the printer is not real, let us just delete the job from 166 // the queue. 167 HANDLE printer = NULL; 168 if (::OpenPrinter(const_cast<LPTSTR>(L"UnitTest Printer"), &printer, NULL)) { 169 ::SetJob(printer, job_id, 0, NULL, JOB_CONTROL_DELETE); 170 ClosePrinter(printer); 171 } 172 } 173 174 TEST(EmfTest, FileBackedEmf) { 175 // Simplest use case. 176 base::ScopedTempDir scratch_metafile_dir; 177 ASSERT_TRUE(scratch_metafile_dir.CreateUniqueTempDir()); 178 base::FilePath metafile_path; 179 EXPECT_TRUE(base::CreateTemporaryFileInDir(scratch_metafile_dir.path(), 180 &metafile_path)); 181 uint32 size; 182 std::vector<char> data; 183 { 184 Emf emf; 185 EXPECT_TRUE(emf.InitToFile(metafile_path)); 186 EXPECT_TRUE(emf.context() != NULL); 187 // An empty EMF is invalid, so we put at least a rectangle in it. 188 ::Rectangle(emf.context(), 10, 10, 190, 190); 189 EXPECT_TRUE(emf.FinishDocument()); 190 size = emf.GetDataSize(); 191 EXPECT_GT(size, EMF_HEADER_SIZE); 192 EXPECT_TRUE(emf.GetDataAsVector(&data)); 193 EXPECT_EQ(data.size(), size); 194 } 195 int64 file_size = 0; 196 base::GetFileSize(metafile_path, &file_size); 197 EXPECT_EQ(size, file_size); 198 199 // Playback the data. 200 HDC hdc = CreateCompatibleDC(NULL); 201 EXPECT_TRUE(hdc); 202 Emf emf; 203 EXPECT_TRUE(emf.InitFromFile(metafile_path)); 204 RECT output_rect = {0, 0, 10, 10}; 205 EXPECT_TRUE(emf.Playback(hdc, &output_rect)); 206 EXPECT_TRUE(DeleteDC(hdc)); 207 } 208 209 TEST(EmfTest, RasterizeMetafile) { 210 Emf emf; 211 EXPECT_TRUE(emf.Init()); 212 EXPECT_TRUE(emf.context() != NULL); 213 HBRUSH brush = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)); 214 for (int i = 0; i < 4; ++i) { 215 RECT rect = { 5 + i, 5 + i, 5 + i + 1, 5 + i + 2}; 216 FillRect(emf.context(), &rect, brush); 217 } 218 EXPECT_TRUE(emf.FinishDocument()); 219 220 scoped_ptr<Emf> raster(emf.RasterizeMetafile(1)); 221 // Just 1px bitmap but should be stretched to the same bounds. 222 EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1)); 223 224 raster = emf.RasterizeMetafile(20); 225 EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1)); 226 227 raster = emf.RasterizeMetafile(16 * 1024 * 1024); 228 // Expected size about 64MB. 229 EXPECT_LE(abs(int(raster->GetDataSize()) - 64 * 1024 * 1024), 1024 * 1024); 230 // Bounds should still be the same. 231 EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1)); 232 } 233 234 } // namespace printing 235