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