Home | History | Annotate | Download | only in printing
      1 // Copyright 2014 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 <algorithm>
      6 #include <fstream>
      7 #include <iostream>
      8 #include <iterator>
      9 #include <limits>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "base/bind.h"
     15 #include "base/callback.h"
     16 #include "base/files/file.h"
     17 #include "base/files/file_path.h"
     18 #include "base/files/file_util.h"
     19 #include "base/files/scoped_temp_dir.h"
     20 #include "base/logging.h"
     21 #include "base/md5.h"
     22 #include "base/memory/scoped_ptr.h"
     23 #include "base/path_service.h"
     24 #include "base/run_loop.h"
     25 #include "base/scoped_native_library.h"
     26 #include "base/strings/string_split.h"
     27 #include "base/strings/utf_string_conversions.h"
     28 #include "chrome/browser/printing/print_preview_dialog_controller.h"
     29 #include "chrome/browser/ui/browser.h"
     30 #include "chrome/browser/ui/browser_commands.h"
     31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     32 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
     33 #include "chrome/common/chrome_paths.h"
     34 #include "chrome/common/print_messages.h"
     35 #include "chrome/test/base/in_process_browser_test.h"
     36 #include "chrome/test/base/ui_test_utils.h"
     37 #include "content/public/browser/web_contents.h"
     38 #include "content/public/browser/web_ui_message_handler.h"
     39 #include "content/public/test/browser_test_utils.h"
     40 #include "ipc/ipc_message_macros.h"
     41 #include "net/base/filename_util.h"
     42 #include "printing/pdf_render_settings.h"
     43 #include "printing/units.h"
     44 #include "ui/gfx/codec/png_codec.h"
     45 #include "ui/gfx/geometry/rect.h"
     46 #include "url/gurl.h"
     47 
     48 #if defined(OS_WIN)
     49 #include <fcntl.h>
     50 #include <io.h>
     51 #endif
     52 
     53 using content::WebContents;
     54 using content::WebContentsObserver;
     55 
     56 namespace printing {
     57 
     58 // Number of color channels in a BGRA bitmap.
     59 const int kColorChannels = 4;
     60 const int kDpi = 300;
     61 
     62 // Every state is used when the document is a non-PDF source. When the source is
     63 // a PDF, kWaitingToSendSaveAsPDF, kWaitingToSendPageNumbers, and
     64 // kWaitingForFinalMessage are the only states used.
     65 enum State {
     66   // Waiting for the first message so the program can select Save as PDF
     67   kWaitingToSendSaveAsPdf = 0,
     68   // Waiting for the second message so the test can set the layout
     69   kWaitingToSendLayoutSettings = 1,
     70   // Waiting for the third message so the test can set the page numbers
     71   kWaitingToSendPageNumbers = 2,
     72   // Waiting for the forth message so the test can set the headers checkbox
     73   kWaitingToSendHeadersAndFooters = 3,
     74   // Waiting for the fifth message so the test can set the background checkbox
     75   kWaitingToSendBackgroundColorsAndImages = 4,
     76   // Waiting for the sixth message so the test can set the margins combobox
     77   kWaitingToSendMargins = 5,
     78   // Waiting for the final message so the program can save to PDF.
     79   kWaitingForFinalMessage = 6,
     80 };
     81 
     82 // Settings for print preview. It reflects the current options provided by
     83 // print preview. If more options are added, more states should be added and
     84 // there should be more settings added to this struct.
     85 struct PrintPreviewSettings {
     86   PrintPreviewSettings(bool is_portrait,
     87                        const std::string& page_numbers,
     88                        bool headers_and_footers,
     89                        bool background_colors_and_images,
     90                        MarginType margins,
     91                        bool source_is_pdf)
     92       : is_portrait(is_portrait),
     93         page_numbers(page_numbers),
     94         headers_and_footers(headers_and_footers),
     95         background_colors_and_images(background_colors_and_images),
     96         margins(margins),
     97         source_is_pdf(source_is_pdf) {}
     98 
     99   bool is_portrait;
    100   std::string page_numbers;
    101   bool headers_and_footers;
    102   bool background_colors_and_images;
    103   MarginType margins;
    104   bool source_is_pdf;
    105 };
    106 
    107 // Observes the print preview webpage. Once it observes the PreviewPageCount
    108 // message, will send a sequence of commands to the print preview dialog and
    109 // change the settings of the preview dialog.
    110 class PrintPreviewObserver : public WebContentsObserver {
    111  public:
    112   PrintPreviewObserver(Browser* browser,
    113                        WebContents* dialog,
    114                        const base::FilePath& pdf_file_save_path)
    115       : WebContentsObserver(dialog),
    116         browser_(browser),
    117         state_(kWaitingToSendSaveAsPdf),
    118         failed_setting_("None"),
    119         pdf_file_save_path_(pdf_file_save_path) {}
    120 
    121   virtual ~PrintPreviewObserver() {}
    122 
    123   // Sets closure for the observer so that it can end the loop.
    124   void set_quit_closure(const base::Closure &closure) {
    125     quit_closure_ = closure;
    126   }
    127 
    128   // Actually stops the message loop so that the test can proceed.
    129   void EndLoop() {
    130     base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
    131   }
    132 
    133   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    134     IPC_BEGIN_MESSAGE_MAP(PrintPreviewObserver, message)
    135       IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPreviewPageCount,
    136                           OnDidGetPreviewPageCount)
    137     IPC_END_MESSAGE_MAP();
    138     return false;
    139   }
    140 
    141   // Gets the web contents for the print preview dialog so that the UI and
    142   // other elements can be accessed.
    143   WebContents* GetDialog() {
    144     WebContents* tab = browser_->tab_strip_model()->GetActiveWebContents();
    145     PrintPreviewDialogController* dialog_controller =
    146         PrintPreviewDialogController::GetInstance();
    147     return dialog_controller->GetPrintPreviewForContents(tab);
    148   }
    149 
    150   // Gets the PrintPreviewUI so that certain elements can be accessed.
    151   PrintPreviewUI* GetUI() {
    152     return static_cast<PrintPreviewUI*>(
    153         GetDialog()->GetWebUI()->GetController());
    154   }
    155 
    156   // Calls native_layer.onManipulateSettingsForTest() and sends a dictionary
    157   // value containing the type of setting and the value to set that settings
    158   // to.
    159   void ManipulatePreviewSettings() {
    160     base::DictionaryValue script_argument;
    161 
    162     if (state_ == kWaitingToSendSaveAsPdf) {
    163       script_argument.SetBoolean("selectSaveAsPdfDestination", true);
    164       state_ = settings_->source_is_pdf ?
    165                kWaitingToSendPageNumbers : kWaitingToSendLayoutSettings;
    166       failed_setting_ = "Save as PDF";
    167     } else if (state_ == kWaitingToSendLayoutSettings) {
    168       script_argument.SetBoolean("layoutSettings.portrait",
    169                                  settings_->is_portrait);
    170       state_ = kWaitingToSendPageNumbers;
    171       failed_setting_ = "Layout Settings";
    172     } else if (state_ == kWaitingToSendPageNumbers) {
    173       script_argument.SetString("pageRange", settings_->page_numbers);
    174       state_ = settings_->source_is_pdf ?
    175                kWaitingForFinalMessage : kWaitingToSendHeadersAndFooters;
    176       failed_setting_ = "Page Range";
    177     } else if (state_ == kWaitingToSendHeadersAndFooters) {
    178       script_argument.SetBoolean("headersAndFooters",
    179                                  settings_->headers_and_footers);
    180       state_ = kWaitingToSendBackgroundColorsAndImages;
    181       failed_setting_ = "Headers and Footers";
    182     } else if (state_ == kWaitingToSendBackgroundColorsAndImages) {
    183       script_argument.SetBoolean("backgroundColorsAndImages",
    184                                  settings_->background_colors_and_images);
    185       state_ = kWaitingToSendMargins;
    186       failed_setting_ = "Background Colors and Images";
    187     } else if (state_ == kWaitingToSendMargins) {
    188       script_argument.SetInteger("margins", settings_->margins);
    189       state_ = kWaitingForFinalMessage;
    190       failed_setting_ = "Margins";
    191     } else if (state_ == kWaitingForFinalMessage) {
    192       // Called by |GetUI()->handler_|, it is a callback function that call
    193       // |EndLoop| when an attempt to save the PDF has been made.
    194       base::Closure end_loop_closure =
    195           base::Bind(&PrintPreviewObserver::EndLoop, base::Unretained(this));
    196       GetUI()->SetPdfSavedClosureForTesting(end_loop_closure);
    197       ASSERT_FALSE(pdf_file_save_path_.empty());
    198       GetUI()->SetSelectedFileForTesting(pdf_file_save_path_);
    199       return;
    200     }
    201 
    202     ASSERT_FALSE(script_argument.empty());
    203     GetUI()->web_ui()->CallJavascriptFunction(
    204         "onManipulateSettingsForTest", script_argument);
    205   }
    206 
    207   // Saves the print preview settings to be sent to the print preview dialog.
    208   void SetPrintPreviewSettings(const PrintPreviewSettings& settings) {
    209     settings_.reset(new PrintPreviewSettings(settings));
    210   }
    211 
    212   // Returns the setting that could not be set in the preview dialog.
    213   const std::string& GetFailedSetting() const {
    214     return failed_setting_;
    215   }
    216 
    217  private:
    218   // Listens for messages from the print preview dialog. Specifically, it
    219   // listens for 'UILoadedForTest' and 'UIFailedLoadingForTest.'
    220   class UIDoneLoadingMessageHandler : public content::WebUIMessageHandler {
    221    public:
    222     explicit UIDoneLoadingMessageHandler(PrintPreviewObserver* observer)
    223         : observer_(observer) {}
    224 
    225     virtual ~UIDoneLoadingMessageHandler() {}
    226 
    227     // When a setting has been set succesfully, this is called and the observer
    228     // is told to send the next setting to be set.
    229     void HandleDone(const base::ListValue* /* args */) {
    230       observer_->ManipulatePreviewSettings();
    231     }
    232 
    233     // Ends the test because a setting was not set successfully. Called when
    234     // this class hears 'UIFailedLoadingForTest.'
    235     void HandleFailure(const base::ListValue* /* args */) {
    236       FAIL() << "Failed to set: " << observer_->GetFailedSetting();
    237     }
    238 
    239     // Allows this class to listen for the 'UILoadedForTest' and
    240     // 'UIFailedLoadingForTest' messages. These messages are sent by the print
    241     // preview dialog. 'UILoadedForTest' is sent when a setting has been
    242     // successfully set and its effects have been finalized.
    243     // 'UIFailedLoadingForTest' is sent when the setting could not be set. This
    244     // causes the browser test to fail.
    245     virtual void RegisterMessages() OVERRIDE {
    246       web_ui()->RegisterMessageCallback(
    247           "UILoadedForTest",
    248           base::Bind(&UIDoneLoadingMessageHandler::HandleDone,
    249                      base::Unretained(this)));
    250 
    251       web_ui()->RegisterMessageCallback(
    252           "UIFailedLoadingForTest",
    253           base::Bind(&UIDoneLoadingMessageHandler::HandleFailure,
    254                      base::Unretained(this)));
    255     }
    256 
    257    private:
    258     PrintPreviewObserver* const observer_;
    259 
    260     DISALLOW_COPY_AND_ASSIGN(UIDoneLoadingMessageHandler);
    261   };
    262 
    263   // Called when the observer gets the IPC message stating that the page count
    264   // is ready.
    265   void OnDidGetPreviewPageCount(
    266         const PrintHostMsg_DidGetPreviewPageCount_Params &params) {
    267     WebContents* web_contents = GetDialog();
    268     ASSERT_TRUE(web_contents);
    269     Observe(web_contents);
    270 
    271     PrintPreviewUI* ui = GetUI();
    272     ASSERT_TRUE(ui);
    273     ASSERT_TRUE(ui->web_ui());
    274 
    275     // The |ui->web_ui()| owns the message handler.
    276     ui->web_ui()->AddMessageHandler(new UIDoneLoadingMessageHandler(this));
    277     ui->web_ui()->CallJavascriptFunction("onEnableManipulateSettingsForTest");
    278   }
    279 
    280   virtual void DidCloneToNewWebContents(
    281       WebContents* old_web_contents,
    282       WebContents* new_web_contents) OVERRIDE {
    283     Observe(new_web_contents);
    284   }
    285 
    286   Browser* browser_;
    287   base::Closure quit_closure_;
    288   scoped_ptr<PrintPreviewSettings> settings_;
    289 
    290   // State of the observer. The state indicates what message to send
    291   // next. The state advances whenever the message handler calls
    292   // ManipulatePreviewSettings() on the observer.
    293   State state_;
    294   std::string failed_setting_;
    295   const base::FilePath pdf_file_save_path_;
    296 
    297   DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver);
    298 };
    299 
    300 class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest {
    301  public:
    302   PrintPreviewPdfGeneratedBrowserTest() {}
    303   virtual ~PrintPreviewPdfGeneratedBrowserTest() {}
    304 
    305   // Navigates to the given web page, then initiates print preview and waits
    306   // for all the settings to be set, then save the preview to PDF.
    307   void NavigateAndPrint(const base::FilePath::StringType& file_name,
    308                           const PrintPreviewSettings& settings) {
    309     print_preview_observer_->SetPrintPreviewSettings(settings);
    310     base::FilePath path(file_name);
    311     GURL gurl = net::FilePathToFileURL(path);
    312 
    313     ui_test_utils::NavigateToURL(browser(), gurl);
    314 
    315     base::RunLoop loop;
    316     print_preview_observer_->set_quit_closure(loop.QuitClosure());
    317     chrome::Print(browser());
    318     loop.Run();
    319 
    320     // Need to check whether the save was successful. Ending the loop only
    321     // means the save was attempted.
    322     base::File pdf_file(
    323         pdf_file_save_path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
    324     ASSERT_TRUE(pdf_file.IsValid());
    325   }
    326 
    327   // Initializes function pointers from the PDF library. Called once when the
    328   // test starts. The library is closed when the browser test ends.
    329   void InitPdfFunctions() {
    330     base::FilePath pdf_module_path;
    331 
    332     ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path));
    333     ASSERT_TRUE(base::PathExists(pdf_module_path));
    334     pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL));
    335 
    336     ASSERT_TRUE(pdf_lib_.is_valid());
    337     pdf_to_bitmap_func_ =
    338         reinterpret_cast<PDFPageToBitmapProc>(
    339             pdf_lib_.GetFunctionPointer("RenderPDFPageToBitmap"));
    340 
    341     pdf_doc_info_func_ =
    342         reinterpret_cast<GetPDFDocInfoProc>(
    343             pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
    344 
    345     pdf_page_size_func_ =
    346         reinterpret_cast<GetPDFPageSizeByIndexProc>(
    347             pdf_lib_.GetFunctionPointer("GetPDFPageSizeByIndex"));
    348 
    349     ASSERT_TRUE(pdf_to_bitmap_func_);
    350     ASSERT_TRUE(pdf_doc_info_func_);
    351     ASSERT_TRUE(pdf_page_size_func_);
    352   }
    353 
    354   // Converts the PDF to a PNG file so that the layout test can do an image
    355   // diff on this image and a reference image.
    356   void PdfToPng() {
    357     int num_pages;
    358     double max_width_in_points = 0;
    359     std::vector<uint8_t> bitmap_data;
    360     double total_height_in_pixels = 0;
    361     std::string pdf_data;
    362 
    363     ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data));
    364     ASSERT_TRUE(pdf_doc_info_func_(pdf_data.data(),
    365                                    pdf_data.size(),
    366                                    &num_pages,
    367                                    &max_width_in_points));
    368 
    369     ASSERT_GT(num_pages, 0);
    370     double max_width_in_pixels =
    371         ConvertUnitDouble(max_width_in_points, kPointsPerInch, kDpi);
    372 
    373     for (int i = 0; i < num_pages; ++i) {
    374       double width_in_points, height_in_points;
    375       ASSERT_TRUE(pdf_page_size_func_(pdf_data.data(),
    376                                       pdf_data.size(),
    377                                       i,
    378                                       &width_in_points,
    379                                       &height_in_points));
    380 
    381       double width_in_pixels = ConvertUnitDouble(
    382           width_in_points, kPointsPerInch, kDpi);
    383       double height_in_pixels = ConvertUnitDouble(
    384           height_in_points, kPointsPerInch, kDpi);
    385 
    386       // The image will be rotated if |width_in_pixels| is greater than
    387       // |height_in_pixels|. This is because the page will be rotated to fit
    388       // within a piece of paper. Therefore, |width_in_pixels| and
    389       // |height_in_pixels| have to be swapped or else they won't reflect the
    390       // dimensions of the rotated page.
    391       if (width_in_pixels > height_in_pixels)
    392         std::swap(width_in_pixels, height_in_pixels);
    393 
    394       total_height_in_pixels += height_in_pixels;
    395       gfx::Rect rect(width_in_pixels, height_in_pixels);
    396       PdfRenderSettings settings(rect, kDpi, true);
    397 
    398       int int_max = std::numeric_limits<int>::max();
    399       if (settings.area().width() > int_max / kColorChannels ||
    400           settings.area().height() > int_max / (kColorChannels *
    401               settings.area().width())) {
    402         FAIL() << "The dimensions of the image are too large."
    403                << "Decrease the DPI or the dimensions of the image.";
    404       }
    405 
    406       std::vector<uint8_t> page_bitmap_data(
    407           kColorChannels * settings.area().size().GetArea());
    408 
    409       ASSERT_TRUE(pdf_to_bitmap_func_(pdf_data.data(),
    410                                       pdf_data.size(),
    411                                       i,
    412                                       page_bitmap_data.data(),
    413                                       settings.area().size().width(),
    414                                       settings.area().size().height(),
    415                                       settings.dpi(),
    416                                       settings.dpi(),
    417                                       true));
    418       FillPng(&page_bitmap_data,
    419               width_in_pixels,
    420               max_width_in_pixels,
    421               settings.area().size().height());
    422       bitmap_data.insert(bitmap_data.end(),
    423                          page_bitmap_data.begin(),
    424                          page_bitmap_data.end());
    425     }
    426 
    427     CreatePng(bitmap_data, max_width_in_pixels, total_height_in_pixels);
    428   }
    429 
    430   // Fills out a bitmap with whitespace so that the image will correctly fit
    431   // within a PNG that is wider than the bitmap itself.
    432   void FillPng(std::vector<uint8_t>* bitmap,
    433                int current_width,
    434                int desired_width,
    435                int height) {
    436     ASSERT_TRUE(bitmap);
    437     ASSERT_GT(height, 0);
    438     ASSERT_LE(current_width, desired_width);
    439 
    440     if (current_width == desired_width)
    441       return;
    442 
    443     int current_width_in_bytes = current_width * kColorChannels;
    444     int desired_width_in_bytes = desired_width * kColorChannels;
    445 
    446     // The color format is BGRA, so to set the color to white, every pixel is
    447     // set to 0xFFFFFFFF.
    448     const uint8_t kColorByte = 255;
    449     std::vector<uint8_t> filled_bitmap(
    450         desired_width * kColorChannels * height, kColorByte);
    451     std::vector<uint8_t>::iterator filled_bitmap_it = filled_bitmap.begin();
    452     std::vector<uint8_t>::iterator bitmap_it = bitmap->begin();
    453 
    454     for (int i = 0; i < height; ++i) {
    455       std::copy(
    456           bitmap_it, bitmap_it + current_width_in_bytes, filled_bitmap_it);
    457       std::advance(bitmap_it, current_width_in_bytes);
    458       std::advance(filled_bitmap_it, desired_width_in_bytes);
    459     }
    460 
    461     bitmap->assign(filled_bitmap.begin(), filled_bitmap.end());
    462   }
    463 
    464   // Sends the PNG image to the layout test framework for comparison.
    465   void SendPng() {
    466     // Send image header and |hash_| to the layout test framework.
    467     std::cout << "Content-Type: image/png\n";
    468     std::cout << "ActualHash: " << base::MD5DigestToBase16(hash_) << "\n";
    469     std::cout << "Content-Length: " << png_output_.size() << "\n";
    470 
    471     std::copy(png_output_.begin(),
    472               png_output_.end(),
    473               std::ostream_iterator<unsigned char>(std::cout, ""));
    474 
    475     std::cout << "#EOF\n";
    476     std::cout.flush();
    477     std::cerr << "#EOF\n";
    478     std::cerr.flush();
    479   }
    480 
    481   // Duplicates the tab that was created when the browser opened. This is done
    482   // so that the observer can listen to the duplicated tab as soon as possible
    483   // and start listening for messages related to print preview.
    484   void DuplicateTab() {
    485     WebContents* tab =
    486         browser()->tab_strip_model()->GetActiveWebContents();
    487     ASSERT_TRUE(tab);
    488 
    489     print_preview_observer_.reset(
    490         new PrintPreviewObserver(browser(), tab, pdf_file_save_path_));
    491     chrome::DuplicateTab(browser());
    492 
    493     WebContents* initiator =
    494         browser()->tab_strip_model()->GetActiveWebContents();
    495     ASSERT_TRUE(initiator);
    496     ASSERT_NE(tab, initiator);
    497   }
    498 
    499   // Resets the test so that another web page can be printed. It also deletes
    500   // the duplicated tab as it isn't needed anymore.
    501   void Reset() {
    502     png_output_.clear();
    503     ASSERT_EQ(2, browser()->tab_strip_model()->count());
    504     chrome::CloseTab(browser());
    505     ASSERT_EQ(1, browser()->tab_strip_model()->count());
    506   }
    507 
    508   // Creates a temporary directory to store a text file that will be used for
    509   // stdin to accept input from the layout test framework. A path for the PDF
    510   // file is also created. The directory and files within it are automatically
    511   // cleaned up once the test ends.
    512   void SetupStdinAndSavePath() {
    513     // Sets the filemode to binary because it will force |std::cout| to send LF
    514     // rather than CRLF. Sending CRLF will cause an error message for the
    515     // layout tests.
    516 #if defined(OS_WIN)
    517     _setmode(_fileno(stdout), _O_BINARY);
    518     _setmode(_fileno(stderr), _O_BINARY);
    519 #endif
    520     // Sends a message to the layout test framework indicating indicating
    521     // that the browser test has completed setting itself up. The layout
    522     // test will then expect the file path for stdin.
    523     base::FilePath stdin_path;
    524     std::cout << "#READY\n";
    525     std::cout.flush();
    526 
    527     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
    528     ASSERT_TRUE(base::CreateTemporaryFileInDir(tmp_dir_.path(), &stdin_path));
    529 
    530     // Redirects |std::cin| to the file |stdin_path|. |in| is not freed because
    531     // if it goes out of scope, |std::cin.rdbuf| will be freed, causing an
    532     // error.
    533     std::ifstream* in = new std::ifstream(stdin_path.value().c_str());
    534     ASSERT_TRUE(in->is_open());
    535     std::cin.rdbuf(in->rdbuf());
    536 
    537     pdf_file_save_path_ =
    538         tmp_dir_.path().Append(FILE_PATH_LITERAL("dummy.pdf"));
    539 
    540     // Send the file path to the layout test framework so that it can
    541     // communicate with this browser test.
    542     std::cout << "StdinPath: " << stdin_path.value() << "\n";
    543     std::cout << "#EOF\n";
    544     std::cout.flush();
    545   }
    546 
    547  private:
    548   // Generates a png from bitmap data and stores it in |png_output_|.
    549   void CreatePng(const std::vector<uint8_t>& bitmap_data,
    550                  int width,
    551                  int height) {
    552     base::MD5Sum(static_cast<const void*>(bitmap_data.data()),
    553                  bitmap_data.size(),
    554                  &hash_);
    555     gfx::Rect png_rect(width, height);
    556 
    557     // tEXtchecksum looks funny, but that's what the layout test framework
    558     // expects.
    559     std::string comment_title("tEXtchecksum\x00");
    560     gfx::PNGCodec::Comment hash_comment(comment_title,
    561                                         base::MD5DigestToBase16(hash_));
    562     std::vector<gfx::PNGCodec::Comment> comments;
    563     comments.push_back(hash_comment);
    564     ASSERT_TRUE(gfx::PNGCodec::Encode(bitmap_data.data(),
    565                                       gfx::PNGCodec::FORMAT_BGRA,
    566                                       png_rect.size(),
    567                                       png_rect.size().width() * kColorChannels,
    568                                       false,
    569                                       comments,
    570                                       &png_output_));
    571   }
    572 
    573   scoped_ptr<PrintPreviewObserver> print_preview_observer_;
    574   base::FilePath pdf_file_save_path_;
    575 
    576   // These typedefs are function pointers to pdflib functions that give
    577   // information about the PDF as a whole and about specific pages.
    578 
    579   // Converts the PDF to a bitmap.
    580   typedef bool (*PDFPageToBitmapProc)(const void* pdf_buffer,
    581                                       int pdf_buffer_size,
    582                                       int page_number,
    583                                       void* bitmap_buffer,
    584                                       int bitmap_width,
    585                                       int bitmap_height,
    586                                       int dpi_x,
    587                                       int dpi_y,
    588                                       bool autorotate);
    589 
    590   // Gets the page count and maximum page width of the PDF in points.
    591   typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
    592                                     int buffer_size,
    593                                     int* pages_count,
    594                                     double* max_page_width);
    595 
    596   // Gets the dimensions of a specific page within a PDF.
    597   typedef bool (*GetPDFPageSizeByIndexProc)(const void* pdf_buffer,
    598                                             int buffer_size,
    599                                             int index,
    600                                             double* width,
    601                                             double* height);
    602 
    603   // Instantiations of the function pointers described above.
    604   PDFPageToBitmapProc pdf_to_bitmap_func_;
    605   GetPDFDocInfoProc pdf_doc_info_func_;
    606   GetPDFPageSizeByIndexProc pdf_page_size_func_;
    607 
    608   // Used to open up the pdf plugin, which contains the functions above.
    609   base::ScopedNativeLibrary pdf_lib_;
    610 
    611   // Vector for storing the PNG to be sent to the layout test framework.
    612   // TODO(ivandavid): Eventually change this to uint32_t and make everything
    613   // work with that. It might be a bit tricky to fix everything to work with
    614   // uint32_t, but not too tricky.
    615   std::vector<unsigned char> png_output_;
    616 
    617   // Image hash of the bitmap that is turned into a PNG. The hash is put into
    618   // the PNG as a comment, as it is needed by the layout test framework.
    619   base::MD5Digest hash_;
    620 
    621   // Temporary directory for storing the pdf and the file for stdin. It is
    622   // deleted by the layout tests.
    623   // TODO(ivandavid): Keep it as a ScopedTempDir and change the layout test
    624   // framework so that it tells the browser test how many test files there are.
    625   base::ScopedTempDir tmp_dir_;
    626 
    627   DISALLOW_COPY_AND_ASSIGN(PrintPreviewPdfGeneratedBrowserTest);
    628 };
    629 
    630 // This test acts as a driver for the layout test framework.
    631 IN_PROC_BROWSER_TEST_F(PrintPreviewPdfGeneratedBrowserTest,
    632                        MANUAL_LayoutTestDriver) {
    633   // What this code is supposed to do:
    634   // - Setup communication with the layout test framework
    635   // - Print webpage to a pdf
    636   // - Convert pdf to a png
    637   // - Send png to layout test framework, where it doesn an image diff
    638   //   on the image sent by this test and a reference image.
    639   //
    640   // Throughout this code, there will be |std::cout| statements. The layout test
    641   // framework uses stdout to get data from the browser test and uses stdin
    642   // to send data to the browser test. Writing "EOF\n" to |std::cout| indicates
    643   // that whatever block of data that the test was expecting has been completely
    644   // sent. Sometimes EOF is printed to stderr because the test will expect it
    645   // from stderr in addition to stdout for certain blocks of data.
    646   InitPdfFunctions();
    647   SetupStdinAndSavePath();
    648 
    649   while (true) {
    650     std::string input;
    651     while (input.empty()) {
    652       std::getline(std::cin, input);
    653       if (std::cin.eof())
    654         std::cin.clear();
    655     }
    656 
    657     // If the layout test framework sends "QUIT" to this test, that means there
    658     // are no more tests for this instance to run and it should quit.
    659     if (input == "QUIT")
    660       break;
    661 
    662     base::FilePath::StringType file_extension = FILE_PATH_LITERAL(".pdf");
    663     base::FilePath::StringType cmd;
    664 #if defined(OS_POSIX)
    665     cmd = input;
    666 #elif defined(OS_WIN)
    667     cmd = base::UTF8ToWide(input);
    668 #endif
    669 
    670     DuplicateTab();
    671     PrintPreviewSettings settings(
    672         true,
    673         "",
    674         false,
    675         false,
    676         DEFAULT_MARGINS,
    677         cmd.find(file_extension) != base::FilePath::StringType::npos);
    678 
    679     // Splits the command sent by the layout test framework. The first command
    680     // is always the file path to use for the test. The rest isn't relevant,
    681     // so it can be ignored. The separator for the commands is an apostrophe.
    682     std::vector<base::FilePath::StringType> cmd_arguments;
    683     base::SplitString(cmd, '\'', &cmd_arguments);
    684 
    685     ASSERT_GE(cmd_arguments.size(), 1U);
    686     base::FilePath::StringType test_name(cmd_arguments[0]);
    687     NavigateAndPrint(test_name, settings);
    688     PdfToPng();
    689 
    690     // Message to the layout test framework indicating that it should start
    691     // waiting for the image data, as there is no more text data to be read.
    692     // There actually isn't any text data at all, however because the layout
    693     // test framework requires it, a message has to be sent to stop it from
    694     // waiting for this message and start waiting for the image data.
    695     std::cout << "#EOF\n";
    696     std::cout.flush();
    697 
    698     SendPng();
    699     Reset();
    700   }
    701 }
    702 
    703 }  // namespace printing
    704