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.
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"
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"
53 using content::WebContents
;
54 using content::WebContentsObserver
;
58 // Number of color channels in a BGRA bitmap.
59 const int kColorChannels
= 4;
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.
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,
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
,
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
),
97 source_is_pdf(source_is_pdf
) {}
100 std::string page_numbers
;
101 bool headers_and_footers
;
102 bool background_colors_and_images
;
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
{
112 PrintPreviewObserver(Browser
* browser
,
114 const base::FilePath
& pdf_file_save_path
)
115 : WebContentsObserver(dialog
),
117 state_(kWaitingToSendSaveAsPdf
),
118 failed_setting_("None"),
119 pdf_file_save_path_(pdf_file_save_path
) {}
121 virtual ~PrintPreviewObserver() {}
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
;
128 // Actually stops the message loop so that the test can proceed.
130 base::MessageLoop::current()->PostTask(FROM_HERE
, quit_closure_
);
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();
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
);
150 // Gets the PrintPreviewUI so that certain elements can be accessed.
151 PrintPreviewUI
* GetUI() {
152 return static_cast<PrintPreviewUI
*>(
153 GetDialog()->GetWebUI()->GetController());
156 // Calls native_layer.onManipulateSettingsForTest() and sends a dictionary
157 // value containing the type of setting and the value to set that settings
159 void ManipulatePreviewSettings() {
160 base::DictionaryValue script_argument
;
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_
);
202 ASSERT_FALSE(script_argument
.empty());
203 GetUI()->web_ui()->CallJavascriptFunction(
204 "onManipulateSettingsForTest", script_argument
);
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
));
212 // Returns the setting that could not be set in the preview dialog.
213 const std::string
& GetFailedSetting() const {
214 return failed_setting_
;
218 // Listens for messages from the print preview dialog. Specifically, it
219 // listens for 'UILoadedForTest' and 'UIFailedLoadingForTest.'
220 class UIDoneLoadingMessageHandler
: public content::WebUIMessageHandler
{
222 explicit UIDoneLoadingMessageHandler(PrintPreviewObserver
* observer
)
223 : observer_(observer
) {}
225 virtual ~UIDoneLoadingMessageHandler() {}
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();
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();
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(
248 base::Bind(&UIDoneLoadingMessageHandler::HandleDone
,
249 base::Unretained(this)));
251 web_ui()->RegisterMessageCallback(
252 "UIFailedLoadingForTest",
253 base::Bind(&UIDoneLoadingMessageHandler::HandleFailure
,
254 base::Unretained(this)));
258 PrintPreviewObserver
* const observer_
;
260 DISALLOW_COPY_AND_ASSIGN(UIDoneLoadingMessageHandler
);
263 // Called when the observer gets the IPC message stating that the page count
265 void OnDidGetPreviewPageCount(
266 const PrintHostMsg_DidGetPreviewPageCount_Params
¶ms
) {
267 WebContents
* web_contents
= GetDialog();
268 ASSERT_TRUE(web_contents
);
269 Observe(web_contents
);
271 PrintPreviewUI
* ui
= GetUI();
273 ASSERT_TRUE(ui
->web_ui());
275 // The |ui->web_ui()| owns the message handler.
276 ui
->web_ui()->AddMessageHandler(new UIDoneLoadingMessageHandler(this));
277 ui
->web_ui()->CallJavascriptFunction("onEnableManipulateSettingsForTest");
280 virtual void DidCloneToNewWebContents(
281 WebContents
* old_web_contents
,
282 WebContents
* new_web_contents
) override
{
283 Observe(new_web_contents
);
287 base::Closure quit_closure_
;
288 scoped_ptr
<PrintPreviewSettings
> settings_
;
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.
294 std::string failed_setting_
;
295 const base::FilePath pdf_file_save_path_
;
297 DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver
);
300 class PrintPreviewPdfGeneratedBrowserTest
: public InProcessBrowserTest
{
302 PrintPreviewPdfGeneratedBrowserTest() {}
303 virtual ~PrintPreviewPdfGeneratedBrowserTest() {}
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
);
313 ui_test_utils::NavigateToURL(browser(), gurl
);
316 print_preview_observer_
->set_quit_closure(loop
.QuitClosure());
317 chrome::Print(browser());
320 // Need to check whether the save was successful. Ending the loop only
321 // means the save was attempted.
323 pdf_file_save_path_
, base::File::FLAG_OPEN
| base::File::FLAG_READ
);
324 ASSERT_TRUE(pdf_file
.IsValid());
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
;
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
));
336 ASSERT_TRUE(pdf_lib_
.is_valid());
337 pdf_to_bitmap_func_
=
338 reinterpret_cast<PDFPageToBitmapProc
>(
339 pdf_lib_
.GetFunctionPointer("RenderPDFPageToBitmap"));
342 reinterpret_cast<GetPDFDocInfoProc
>(
343 pdf_lib_
.GetFunctionPointer("GetPDFDocInfo"));
345 pdf_page_size_func_
=
346 reinterpret_cast<GetPDFPageSizeByIndexProc
>(
347 pdf_lib_
.GetFunctionPointer("GetPDFPageSizeByIndex"));
349 ASSERT_TRUE(pdf_to_bitmap_func_
);
350 ASSERT_TRUE(pdf_doc_info_func_
);
351 ASSERT_TRUE(pdf_page_size_func_
);
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.
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
;
363 ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_
, &pdf_data
));
364 ASSERT_TRUE(pdf_doc_info_func_(pdf_data
.data(),
367 &max_width_in_points
));
369 ASSERT_GT(num_pages
, 0);
370 double max_width_in_pixels
=
371 ConvertUnitDouble(max_width_in_points
, kPointsPerInch
, kDpi
);
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(),
381 double width_in_pixels
= ConvertUnitDouble(
382 width_in_points
, kPointsPerInch
, kDpi
);
383 double height_in_pixels
= ConvertUnitDouble(
384 height_in_points
, kPointsPerInch
, kDpi
);
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
);
394 total_height_in_pixels
+= height_in_pixels
;
395 gfx::Rect
rect(width_in_pixels
, height_in_pixels
);
396 PdfRenderSettings
settings(rect
, kDpi
, true);
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.";
406 std::vector
<uint8_t> page_bitmap_data(
407 kColorChannels
* settings
.area().size().GetArea());
409 ASSERT_TRUE(pdf_to_bitmap_func_(pdf_data
.data(),
412 page_bitmap_data
.data(),
413 settings
.area().size().width(),
414 settings
.area().size().height(),
418 FillPng(&page_bitmap_data
,
421 settings
.area().size().height());
422 bitmap_data
.insert(bitmap_data
.end(),
423 page_bitmap_data
.begin(),
424 page_bitmap_data
.end());
427 CreatePng(bitmap_data
, max_width_in_pixels
, total_height_in_pixels
);
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
,
437 ASSERT_GT(height
, 0);
438 ASSERT_LE(current_width
, desired_width
);
440 if (current_width
== desired_width
)
443 int current_width_in_bytes
= current_width
* kColorChannels
;
444 int desired_width_in_bytes
= desired_width
* kColorChannels
;
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();
454 for (int i
= 0; i
< height
; ++i
) {
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
);
461 bitmap
->assign(filled_bitmap
.begin(), filled_bitmap
.end());
464 // Sends the PNG image to the layout test framework for comparison.
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";
471 std::copy(png_output_
.begin(),
473 std::ostream_iterator
<unsigned char>(std::cout
, ""));
475 std::cout
<< "#EOF\n";
477 std::cerr
<< "#EOF\n";
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() {
486 browser()->tab_strip_model()->GetActiveWebContents();
489 print_preview_observer_
.reset(
490 new PrintPreviewObserver(browser(), tab
, pdf_file_save_path_
));
491 chrome::DuplicateTab(browser());
493 WebContents
* initiator
=
494 browser()->tab_strip_model()->GetActiveWebContents();
495 ASSERT_TRUE(initiator
);
496 ASSERT_NE(tab
, initiator
);
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.
503 ASSERT_EQ(2, browser()->tab_strip_model()->count());
504 chrome::CloseTab(browser());
505 ASSERT_EQ(1, browser()->tab_strip_model()->count());
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
517 _setmode(_fileno(stdout
), _O_BINARY
);
518 _setmode(_fileno(stderr
), _O_BINARY
);
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";
527 ASSERT_TRUE(tmp_dir_
.CreateUniqueTempDir());
528 ASSERT_TRUE(base::CreateTemporaryFileInDir(tmp_dir_
.path(), &stdin_path
));
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
533 std::ifstream
* in
= new std::ifstream(stdin_path
.value().c_str());
534 ASSERT_TRUE(in
->is_open());
535 std::cin
.rdbuf(in
->rdbuf());
537 pdf_file_save_path_
=
538 tmp_dir_
.path().Append(FILE_PATH_LITERAL("dummy.pdf"));
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";
548 // Generates a png from bitmap data and stores it in |png_output_|.
549 void CreatePng(const std::vector
<uint8_t>& bitmap_data
,
552 base::MD5Sum(static_cast<const void*>(bitmap_data
.data()),
555 gfx::Rect
png_rect(width
, height
);
557 // tEXtchecksum looks funny, but that's what the layout test framework
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
,
567 png_rect
.size().width() * kColorChannels
,
573 scoped_ptr
<PrintPreviewObserver
> print_preview_observer_
;
574 base::FilePath pdf_file_save_path_
;
576 // These typedefs are function pointers to pdflib functions that give
577 // information about the PDF as a whole and about specific pages.
579 // Converts the PDF to a bitmap.
580 typedef bool (*PDFPageToBitmapProc
)(const void* pdf_buffer
,
590 // Gets the page count and maximum page width of the PDF in points.
591 typedef bool (*GetPDFDocInfoProc
)(const void* pdf_buffer
,
594 double* max_page_width
);
596 // Gets the dimensions of a specific page within a PDF.
597 typedef bool (*GetPDFPageSizeByIndexProc
)(const void* pdf_buffer
,
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_
;
608 // Used to open up the pdf plugin, which contains the functions above.
609 base::ScopedNativeLibrary pdf_lib_
;
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_
;
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_
;
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_
;
627 DISALLOW_COPY_AND_ASSIGN(PrintPreviewPdfGeneratedBrowserTest
);
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.
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.
647 SetupStdinAndSavePath();
651 while (input
.empty()) {
652 std::getline(std::cin
, input
);
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.
662 base::FilePath::StringType file_extension
= FILE_PATH_LITERAL(".pdf");
663 base::FilePath::StringType cmd
;
664 #if defined(OS_POSIX)
666 #elif defined(OS_WIN)
667 cmd
= base::UTF8ToWide(input
);
671 PrintPreviewSettings
settings(
677 cmd
.find(file_extension
) != base::FilePath::StringType::npos
);
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
);
685 ASSERT_GE(cmd_arguments
.size(), 1U);
686 base::FilePath::StringType
test_name(cmd_arguments
[0]);
687 NavigateAndPrint(test_name
, settings
);
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";
703 } // namespace printing