Home | History | Annotate | Download | only in printing
      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   base::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(base::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   base::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