Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / printing / print_preview_pdf_generated_browsertest.cc
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   ~PrintPreviewObserver() override {}
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   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     ~UIDoneLoadingMessageHandler() override {}
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     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   void DidCloneToNewWebContents(WebContents* old_web_contents,
281                                 WebContents* new_web_contents) override {
282     Observe(new_web_contents);
283   }
284
285   Browser* browser_;
286   base::Closure quit_closure_;
287   scoped_ptr<PrintPreviewSettings> settings_;
288
289   // State of the observer. The state indicates what message to send
290   // next. The state advances whenever the message handler calls
291   // ManipulatePreviewSettings() on the observer.
292   State state_;
293   std::string failed_setting_;
294   const base::FilePath pdf_file_save_path_;
295
296   DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver);
297 };
298
299 class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest {
300  public:
301   PrintPreviewPdfGeneratedBrowserTest() {}
302   ~PrintPreviewPdfGeneratedBrowserTest() override {}
303
304   // Navigates to the given web page, then initiates print preview and waits
305   // for all the settings to be set, then save the preview to PDF.
306   void NavigateAndPrint(const base::FilePath::StringType& file_name,
307                           const PrintPreviewSettings& settings) {
308     print_preview_observer_->SetPrintPreviewSettings(settings);
309     base::FilePath path(file_name);
310     GURL gurl = net::FilePathToFileURL(path);
311
312     ui_test_utils::NavigateToURL(browser(), gurl);
313
314     base::RunLoop loop;
315     print_preview_observer_->set_quit_closure(loop.QuitClosure());
316     chrome::Print(browser());
317     loop.Run();
318
319     // Need to check whether the save was successful. Ending the loop only
320     // means the save was attempted.
321     base::File pdf_file(
322         pdf_file_save_path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
323     ASSERT_TRUE(pdf_file.IsValid());
324   }
325
326   // Initializes function pointers from the PDF library. Called once when the
327   // test starts. The library is closed when the browser test ends.
328   void InitPdfFunctions() {
329     base::FilePath pdf_module_path;
330
331     ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path));
332     ASSERT_TRUE(base::PathExists(pdf_module_path));
333     pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL));
334
335     ASSERT_TRUE(pdf_lib_.is_valid());
336     pdf_to_bitmap_func_ =
337         reinterpret_cast<PDFPageToBitmapProc>(
338             pdf_lib_.GetFunctionPointer("RenderPDFPageToBitmap"));
339
340     pdf_doc_info_func_ =
341         reinterpret_cast<GetPDFDocInfoProc>(
342             pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
343
344     pdf_page_size_func_ =
345         reinterpret_cast<GetPDFPageSizeByIndexProc>(
346             pdf_lib_.GetFunctionPointer("GetPDFPageSizeByIndex"));
347
348     ASSERT_TRUE(pdf_to_bitmap_func_);
349     ASSERT_TRUE(pdf_doc_info_func_);
350     ASSERT_TRUE(pdf_page_size_func_);
351   }
352
353   // Converts the PDF to a PNG file so that the layout test can do an image
354   // diff on this image and a reference image.
355   void PdfToPng() {
356     int num_pages;
357     double max_width_in_points = 0;
358     std::vector<uint8_t> bitmap_data;
359     double total_height_in_pixels = 0;
360     std::string pdf_data;
361
362     ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data));
363     ASSERT_TRUE(pdf_doc_info_func_(pdf_data.data(),
364                                    pdf_data.size(),
365                                    &num_pages,
366                                    &max_width_in_points));
367
368     ASSERT_GT(num_pages, 0);
369     double max_width_in_pixels =
370         ConvertUnitDouble(max_width_in_points, kPointsPerInch, kDpi);
371
372     for (int i = 0; i < num_pages; ++i) {
373       double width_in_points, height_in_points;
374       ASSERT_TRUE(pdf_page_size_func_(pdf_data.data(),
375                                       pdf_data.size(),
376                                       i,
377                                       &width_in_points,
378                                       &height_in_points));
379
380       double width_in_pixels = ConvertUnitDouble(
381           width_in_points, kPointsPerInch, kDpi);
382       double height_in_pixels = ConvertUnitDouble(
383           height_in_points, kPointsPerInch, kDpi);
384
385       // The image will be rotated if |width_in_pixels| is greater than
386       // |height_in_pixels|. This is because the page will be rotated to fit
387       // within a piece of paper. Therefore, |width_in_pixels| and
388       // |height_in_pixels| have to be swapped or else they won't reflect the
389       // dimensions of the rotated page.
390       if (width_in_pixels > height_in_pixels)
391         std::swap(width_in_pixels, height_in_pixels);
392
393       total_height_in_pixels += height_in_pixels;
394       gfx::Rect rect(width_in_pixels, height_in_pixels);
395       PdfRenderSettings settings(rect, kDpi, true);
396
397       int int_max = std::numeric_limits<int>::max();
398       if (settings.area().width() > int_max / kColorChannels ||
399           settings.area().height() > int_max / (kColorChannels *
400               settings.area().width())) {
401         FAIL() << "The dimensions of the image are too large."
402                << "Decrease the DPI or the dimensions of the image.";
403       }
404
405       std::vector<uint8_t> page_bitmap_data(
406           kColorChannels * settings.area().size().GetArea());
407
408       ASSERT_TRUE(pdf_to_bitmap_func_(pdf_data.data(),
409                                       pdf_data.size(),
410                                       i,
411                                       page_bitmap_data.data(),
412                                       settings.area().size().width(),
413                                       settings.area().size().height(),
414                                       settings.dpi(),
415                                       settings.dpi(),
416                                       true));
417       FillPng(&page_bitmap_data,
418               width_in_pixels,
419               max_width_in_pixels,
420               settings.area().size().height());
421       bitmap_data.insert(bitmap_data.end(),
422                          page_bitmap_data.begin(),
423                          page_bitmap_data.end());
424     }
425
426     CreatePng(bitmap_data, max_width_in_pixels, total_height_in_pixels);
427   }
428
429   // Fills out a bitmap with whitespace so that the image will correctly fit
430   // within a PNG that is wider than the bitmap itself.
431   void FillPng(std::vector<uint8_t>* bitmap,
432                int current_width,
433                int desired_width,
434                int height) {
435     ASSERT_TRUE(bitmap);
436     ASSERT_GT(height, 0);
437     ASSERT_LE(current_width, desired_width);
438
439     if (current_width == desired_width)
440       return;
441
442     int current_width_in_bytes = current_width * kColorChannels;
443     int desired_width_in_bytes = desired_width * kColorChannels;
444
445     // The color format is BGRA, so to set the color to white, every pixel is
446     // set to 0xFFFFFFFF.
447     const uint8_t kColorByte = 255;
448     std::vector<uint8_t> filled_bitmap(
449         desired_width * kColorChannels * height, kColorByte);
450     std::vector<uint8_t>::iterator filled_bitmap_it = filled_bitmap.begin();
451     std::vector<uint8_t>::iterator bitmap_it = bitmap->begin();
452
453     for (int i = 0; i < height; ++i) {
454       std::copy(
455           bitmap_it, bitmap_it + current_width_in_bytes, filled_bitmap_it);
456       std::advance(bitmap_it, current_width_in_bytes);
457       std::advance(filled_bitmap_it, desired_width_in_bytes);
458     }
459
460     bitmap->assign(filled_bitmap.begin(), filled_bitmap.end());
461   }
462
463   // Sends the PNG image to the layout test framework for comparison.
464   void SendPng() {
465     // Send image header and |hash_| to the layout test framework.
466     std::cout << "Content-Type: image/png\n";
467     std::cout << "ActualHash: " << base::MD5DigestToBase16(hash_) << "\n";
468     std::cout << "Content-Length: " << png_output_.size() << "\n";
469
470     std::copy(png_output_.begin(),
471               png_output_.end(),
472               std::ostream_iterator<unsigned char>(std::cout, ""));
473
474     std::cout << "#EOF\n";
475     std::cout.flush();
476     std::cerr << "#EOF\n";
477     std::cerr.flush();
478   }
479
480   // Duplicates the tab that was created when the browser opened. This is done
481   // so that the observer can listen to the duplicated tab as soon as possible
482   // and start listening for messages related to print preview.
483   void DuplicateTab() {
484     WebContents* tab =
485         browser()->tab_strip_model()->GetActiveWebContents();
486     ASSERT_TRUE(tab);
487
488     print_preview_observer_.reset(
489         new PrintPreviewObserver(browser(), tab, pdf_file_save_path_));
490     chrome::DuplicateTab(browser());
491
492     WebContents* initiator =
493         browser()->tab_strip_model()->GetActiveWebContents();
494     ASSERT_TRUE(initiator);
495     ASSERT_NE(tab, initiator);
496   }
497
498   // Resets the test so that another web page can be printed. It also deletes
499   // the duplicated tab as it isn't needed anymore.
500   void Reset() {
501     png_output_.clear();
502     ASSERT_EQ(2, browser()->tab_strip_model()->count());
503     chrome::CloseTab(browser());
504     ASSERT_EQ(1, browser()->tab_strip_model()->count());
505   }
506
507   // Creates a temporary directory to store a text file that will be used for
508   // stdin to accept input from the layout test framework. A path for the PDF
509   // file is also created. The directory and files within it are automatically
510   // cleaned up once the test ends.
511   void SetupStdinAndSavePath() {
512     // Sets the filemode to binary because it will force |std::cout| to send LF
513     // rather than CRLF. Sending CRLF will cause an error message for the
514     // layout tests.
515 #if defined(OS_WIN)
516     _setmode(_fileno(stdout), _O_BINARY);
517     _setmode(_fileno(stderr), _O_BINARY);
518 #endif
519     // Sends a message to the layout test framework indicating indicating
520     // that the browser test has completed setting itself up. The layout
521     // test will then expect the file path for stdin.
522     base::FilePath stdin_path;
523     std::cout << "#READY\n";
524     std::cout.flush();
525
526     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
527     ASSERT_TRUE(base::CreateTemporaryFileInDir(tmp_dir_.path(), &stdin_path));
528
529     // Redirects |std::cin| to the file |stdin_path|. |in| is not freed because
530     // if it goes out of scope, |std::cin.rdbuf| will be freed, causing an
531     // error.
532     std::ifstream* in = new std::ifstream(stdin_path.value().c_str());
533     ASSERT_TRUE(in->is_open());
534     std::cin.rdbuf(in->rdbuf());
535
536     pdf_file_save_path_ =
537         tmp_dir_.path().Append(FILE_PATH_LITERAL("dummy.pdf"));
538
539     // Send the file path to the layout test framework so that it can
540     // communicate with this browser test.
541     std::cout << "StdinPath: " << stdin_path.value() << "\n";
542     std::cout << "#EOF\n";
543     std::cout.flush();
544   }
545
546  private:
547   // Generates a png from bitmap data and stores it in |png_output_|.
548   void CreatePng(const std::vector<uint8_t>& bitmap_data,
549                  int width,
550                  int height) {
551     base::MD5Sum(static_cast<const void*>(bitmap_data.data()),
552                  bitmap_data.size(),
553                  &hash_);
554     gfx::Rect png_rect(width, height);
555
556     // tEXtchecksum looks funny, but that's what the layout test framework
557     // expects.
558     std::string comment_title("tEXtchecksum\x00");
559     gfx::PNGCodec::Comment hash_comment(comment_title,
560                                         base::MD5DigestToBase16(hash_));
561     std::vector<gfx::PNGCodec::Comment> comments;
562     comments.push_back(hash_comment);
563     ASSERT_TRUE(gfx::PNGCodec::Encode(bitmap_data.data(),
564                                       gfx::PNGCodec::FORMAT_BGRA,
565                                       png_rect.size(),
566                                       png_rect.size().width() * kColorChannels,
567                                       false,
568                                       comments,
569                                       &png_output_));
570   }
571
572   scoped_ptr<PrintPreviewObserver> print_preview_observer_;
573   base::FilePath pdf_file_save_path_;
574
575   // These typedefs are function pointers to pdflib functions that give
576   // information about the PDF as a whole and about specific pages.
577
578   // Converts the PDF to a bitmap.
579   typedef bool (*PDFPageToBitmapProc)(const void* pdf_buffer,
580                                       int pdf_buffer_size,
581                                       int page_number,
582                                       void* bitmap_buffer,
583                                       int bitmap_width,
584                                       int bitmap_height,
585                                       int dpi_x,
586                                       int dpi_y,
587                                       bool autorotate);
588
589   // Gets the page count and maximum page width of the PDF in points.
590   typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
591                                     int buffer_size,
592                                     int* pages_count,
593                                     double* max_page_width);
594
595   // Gets the dimensions of a specific page within a PDF.
596   typedef bool (*GetPDFPageSizeByIndexProc)(const void* pdf_buffer,
597                                             int buffer_size,
598                                             int index,
599                                             double* width,
600                                             double* height);
601
602   // Instantiations of the function pointers described above.
603   PDFPageToBitmapProc pdf_to_bitmap_func_;
604   GetPDFDocInfoProc pdf_doc_info_func_;
605   GetPDFPageSizeByIndexProc pdf_page_size_func_;
606
607   // Used to open up the pdf plugin, which contains the functions above.
608   base::ScopedNativeLibrary pdf_lib_;
609
610   // Vector for storing the PNG to be sent to the layout test framework.
611   // TODO(ivandavid): Eventually change this to uint32_t and make everything
612   // work with that. It might be a bit tricky to fix everything to work with
613   // uint32_t, but not too tricky.
614   std::vector<unsigned char> png_output_;
615
616   // Image hash of the bitmap that is turned into a PNG. The hash is put into
617   // the PNG as a comment, as it is needed by the layout test framework.
618   base::MD5Digest hash_;
619
620   // Temporary directory for storing the pdf and the file for stdin. It is
621   // deleted by the layout tests.
622   // TODO(ivandavid): Keep it as a ScopedTempDir and change the layout test
623   // framework so that it tells the browser test how many test files there are.
624   base::ScopedTempDir tmp_dir_;
625
626   DISALLOW_COPY_AND_ASSIGN(PrintPreviewPdfGeneratedBrowserTest);
627 };
628
629 // This test acts as a driver for the layout test framework.
630 IN_PROC_BROWSER_TEST_F(PrintPreviewPdfGeneratedBrowserTest,
631                        MANUAL_LayoutTestDriver) {
632   // What this code is supposed to do:
633   // - Setup communication with the layout test framework
634   // - Print webpage to a pdf
635   // - Convert pdf to a png
636   // - Send png to layout test framework, where it doesn an image diff
637   //   on the image sent by this test and a reference image.
638   //
639   // Throughout this code, there will be |std::cout| statements. The layout test
640   // framework uses stdout to get data from the browser test and uses stdin
641   // to send data to the browser test. Writing "EOF\n" to |std::cout| indicates
642   // that whatever block of data that the test was expecting has been completely
643   // sent. Sometimes EOF is printed to stderr because the test will expect it
644   // from stderr in addition to stdout for certain blocks of data.
645   InitPdfFunctions();
646   SetupStdinAndSavePath();
647
648   while (true) {
649     std::string input;
650     while (input.empty()) {
651       std::getline(std::cin, input);
652       if (std::cin.eof())
653         std::cin.clear();
654     }
655
656     // If the layout test framework sends "QUIT" to this test, that means there
657     // are no more tests for this instance to run and it should quit.
658     if (input == "QUIT")
659       break;
660
661     base::FilePath::StringType file_extension = FILE_PATH_LITERAL(".pdf");
662     base::FilePath::StringType cmd;
663 #if defined(OS_POSIX)
664     cmd = input;
665 #elif defined(OS_WIN)
666     cmd = base::UTF8ToWide(input);
667 #endif
668
669     DuplicateTab();
670     PrintPreviewSettings settings(
671         true,
672         "",
673         false,
674         false,
675         DEFAULT_MARGINS,
676         cmd.find(file_extension) != base::FilePath::StringType::npos);
677
678     // Splits the command sent by the layout test framework. The first command
679     // is always the file path to use for the test. The rest isn't relevant,
680     // so it can be ignored. The separator for the commands is an apostrophe.
681     std::vector<base::FilePath::StringType> cmd_arguments;
682     base::SplitString(cmd, '\'', &cmd_arguments);
683
684     ASSERT_GE(cmd_arguments.size(), 1U);
685     base::FilePath::StringType test_name(cmd_arguments[0]);
686     NavigateAndPrint(test_name, settings);
687     PdfToPng();
688
689     // Message to the layout test framework indicating that it should start
690     // waiting for the image data, as there is no more text data to be read.
691     // There actually isn't any text data at all, however because the layout
692     // test framework requires it, a message has to be sent to stop it from
693     // waiting for this message and start waiting for the image data.
694     std::cout << "#EOF\n";
695     std::cout.flush();
696
697     SendPng();
698     Reset();
699   }
700 }
701
702 }  // namespace printing