root/chrome/renderer/printing/print_web_view_helper_browsertest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CreatePrintSettingsDictionary
  2. PrintWithJavaScript
  3. VerifyPageCount
  4. VerifyPreviewPageCount
  5. VerifyPagesPrinted
  6. OnPrintPages
  7. OnPrintPreview
  8. OnPrintForPrintPreview
  9. SetUp
  10. TEST_F
  11. TEST_F
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. TEST_F
  16. TEST_F
  17. SetUp
  18. VerifyPrintPreviewCancelled
  19. VerifyPrintPreviewFailed
  20. VerifyPrintPreviewGenerated
  21. VerifyPrintFailed
  22. VerifyPrintPreviewInvalidPrinterSettings
  23. VerifyDidPreviewPage
  24. VerifyDefaultPageLayout
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F
  31. TEST_F
  32. TEST_F
  33. TEST_F
  34. TEST_F
  35. TEST_F
  36. TEST_F
  37. TEST_F
  38. TEST_F
  39. TEST_F
  40. TEST_F
  41. TEST_F
  42. TEST_F
  43. TEST_F
  44. SetUp
  45. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/print_messages.h"
#include "chrome/renderer/mock_printer.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "chrome/test/base/chrome_render_view_test.h"
#include "content/public/renderer/render_view.h"
#include "printing/print_job_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebRange.h"
#include "third_party/WebKit/public/web/WebView.h"

#if defined(OS_WIN) || defined(OS_MACOSX)
#include "base/file_util.h"
#include "printing/image.h"

using blink::WebFrame;
using blink::WebString;
#endif

namespace printing {

namespace {

// A simple web page.
const char kHelloWorldHTML[] = "<body><p>Hello World!</p></body>";

// A simple webpage with a button to print itself with.
const char kPrintOnUserAction[] =
    "<body>"
    "  <button id=\"print\" onclick=\"window.print();\">Hello World!</button>"
    "</body>";

#if !defined(OS_CHROMEOS)
// HTML with 3 pages.
const char kMultipageHTML[] =
  "<html><head><style>"
  ".break { page-break-after: always; }"
  "</style></head>"
  "<body>"
  "<div class='break'>page1</div>"
  "<div class='break'>page2</div>"
  "<div>page3</div>"
  "</body></html>";

// A simple web page with print page size css.
const char kHTMLWithPageSizeCss[] =
    "<html><head><style>"
    "@media print {"
    "  @page {"
    "     size: 4in 4in;"
    "  }"
    "}"
    "</style></head>"
    "<body>Lorem Ipsum:"
    "</body></html>";

// A simple web page with print page layout css.
const char kHTMLWithLandscapePageCss[] =
    "<html><head><style>"
    "@media print {"
    "  @page {"
    "     size: landscape;"
    "  }"
    "}"
    "</style></head>"
    "<body>Lorem Ipsum:"
    "</body></html>";

// A longer web page.
const char kLongPageHTML[] =
    "<body><img src=\"\" width=10 height=10000 /></body>";

// A web page to simulate the print preview page.
const char kPrintPreviewHTML[] =
    "<body><p id=\"pdf-viewer\">Hello World!</p></body>";

void CreatePrintSettingsDictionary(base::DictionaryValue* dict) {
  dict->SetBoolean(kSettingLandscape, false);
  dict->SetBoolean(kSettingCollate, false);
  dict->SetInteger(kSettingColor, GRAY);
  dict->SetBoolean(kSettingPrintToPDF, true);
  dict->SetInteger(kSettingDuplexMode, SIMPLEX);
  dict->SetInteger(kSettingCopies, 1);
  dict->SetString(kSettingDeviceName, "dummy");
  dict->SetInteger(kPreviewUIID, 4);
  dict->SetInteger(kPreviewRequestID, 12345);
  dict->SetBoolean(kIsFirstRequest, true);
  dict->SetInteger(kSettingMarginsType, DEFAULT_MARGINS);
  dict->SetBoolean(kSettingPreviewModifiable, false);
  dict->SetBoolean(kSettingHeaderFooterEnabled, false);
  dict->SetBoolean(kSettingGenerateDraftData, true);
  dict->SetBoolean(kSettingShouldPrintBackgrounds, false);
  dict->SetBoolean(kSettingShouldPrintSelectionOnly, false);
}
#endif  // !defined(OS_CHROMEOS)

}  // namespace

class PrintWebViewHelperTestBase : public ChromeRenderViewTest {
 public:
  PrintWebViewHelperTestBase() {}
  virtual ~PrintWebViewHelperTestBase() {}

 protected:
  void PrintWithJavaScript() {
    ExecuteJavaScript("window.print();");
    ProcessPendingMessages();
  }
  // The renderer should be done calculating the number of rendered pages
  // according to the specified settings defined in the mock render thread.
  // Verify the page count is correct.
  void VerifyPageCount(int count) {
#if defined(OS_CHROMEOS)
    // The DidGetPrintedPagesCount message isn't sent on ChromeOS. Right now we
    // always print all pages, and there are checks to that effect built into
    // the print code.
#else
    const IPC::Message* page_cnt_msg =
        render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_DidGetPrintedPagesCount::ID);
    ASSERT_TRUE(page_cnt_msg);
    PrintHostMsg_DidGetPrintedPagesCount::Param post_page_count_param;
    PrintHostMsg_DidGetPrintedPagesCount::Read(page_cnt_msg,
                                               &post_page_count_param);
    EXPECT_EQ(count, post_page_count_param.b);
#endif  // defined(OS_CHROMEOS)
  }

  // The renderer should be done calculating the number of rendered pages
  // according to the specified settings defined in the mock render thread.
  // Verify the page count is correct.
  void VerifyPreviewPageCount(int count) {
    const IPC::Message* page_cnt_msg =
        render_thread_->sink().GetUniqueMessageMatching(
        PrintHostMsg_DidGetPreviewPageCount::ID);
    ASSERT_TRUE(page_cnt_msg);
    PrintHostMsg_DidGetPreviewPageCount::Param post_page_count_param;
    PrintHostMsg_DidGetPreviewPageCount::Read(page_cnt_msg,
                                              &post_page_count_param);
    EXPECT_EQ(count, post_page_count_param.a.page_count);
  }

  // Verifies whether the pages printed or not.
  void VerifyPagesPrinted(bool printed) {
#if defined(OS_CHROMEOS)
    bool did_print_msg = (render_thread_->sink().GetUniqueMessageMatching(
        PrintHostMsg_TempFileForPrintingWritten::ID) != NULL);
    ASSERT_EQ(printed, did_print_msg);
#else
    const IPC::Message* print_msg =
        render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_DidPrintPage::ID);
    bool did_print_msg = (NULL != print_msg);
    ASSERT_EQ(printed, did_print_msg);
    if (printed) {
      PrintHostMsg_DidPrintPage::Param post_did_print_page_param;
      PrintHostMsg_DidPrintPage::Read(print_msg, &post_did_print_page_param);
      EXPECT_EQ(0, post_did_print_page_param.a.page_number);
    }
#endif  // defined(OS_CHROMEOS)
  }
  void OnPrintPages() {
    PrintWebViewHelper::Get(view_)->OnPrintPages();
    ProcessPendingMessages();
  }

  void OnPrintPreview(const base::DictionaryValue& dict) {
    PrintWebViewHelper* print_web_view_helper = PrintWebViewHelper::Get(view_);
    print_web_view_helper->OnInitiatePrintPreview(false);
    print_web_view_helper->OnPrintPreview(dict);
    ProcessPendingMessages();
  }

  void OnPrintForPrintPreview(const base::DictionaryValue& dict) {
    PrintWebViewHelper::Get(view_)->OnPrintForPrintPreview(dict);
    ProcessPendingMessages();
  }

  DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelperTestBase);
};

class PrintWebViewHelperTest : public PrintWebViewHelperTestBase {
 public:
  PrintWebViewHelperTest() {}
  virtual ~PrintWebViewHelperTest() {}

  virtual void SetUp() OVERRIDE {
    ChromeRenderViewTest::SetUp();
  }

 protected:
  DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelperTest);
};

// Tests that printing pages work and sending and receiving messages through
// that channel all works.
TEST_F(PrintWebViewHelperTest, OnPrintPages) {
  LoadHTML(kHelloWorldHTML);
  OnPrintPages();

  VerifyPageCount(1);
  VerifyPagesPrinted(true);
}

// Duplicate of OnPrintPagesTest only using javascript to print.
TEST_F(PrintWebViewHelperTest, PrintWithJavascript) {
  PrintWithJavaScript();

  VerifyPageCount(1);
  VerifyPagesPrinted(true);
}

// Tests that the renderer blocks window.print() calls if they occur too
// frequently.
TEST_F(PrintWebViewHelperTest, BlockScriptInitiatedPrinting) {
  // Pretend user will cancel printing.
  chrome_render_thread_->set_print_dialog_user_response(false);
  // Try to print with window.print() a few times.
  PrintWithJavaScript();
  PrintWithJavaScript();
  PrintWithJavaScript();
  VerifyPagesPrinted(false);

  // Pretend user will print. (but printing is blocked.)
  chrome_render_thread_->set_print_dialog_user_response(true);
  PrintWithJavaScript();
  VerifyPagesPrinted(false);

  // Unblock script initiated printing and verify printing works.
  PrintWebViewHelper::Get(view_)->ResetScriptedPrintCount();
  chrome_render_thread_->printer()->ResetPrinter();
  PrintWithJavaScript();
  VerifyPageCount(1);
  VerifyPagesPrinted(true);
}

// Tests that the renderer always allows window.print() calls if they are user
// initiated.
TEST_F(PrintWebViewHelperTest, AllowUserOriginatedPrinting) {
  // Pretend user will cancel printing.
  chrome_render_thread_->set_print_dialog_user_response(false);
  // Try to print with window.print() a few times.
  PrintWithJavaScript();
  PrintWithJavaScript();
  PrintWithJavaScript();
  VerifyPagesPrinted(false);

  // Pretend user will print. (but printing is blocked.)
  chrome_render_thread_->set_print_dialog_user_response(true);
  PrintWithJavaScript();
  VerifyPagesPrinted(false);

  // Try again as if user initiated, without resetting the print count.
  chrome_render_thread_->printer()->ResetPrinter();
  LoadHTML(kPrintOnUserAction);
  gfx::Size new_size(200, 100);
  Resize(new_size, gfx::Rect(), false);

  gfx::Rect bounds = GetElementBounds("print");
  EXPECT_FALSE(bounds.IsEmpty());
  blink::WebMouseEvent mouse_event;
  mouse_event.type = blink::WebInputEvent::MouseDown;
  mouse_event.button = blink::WebMouseEvent::ButtonLeft;
  mouse_event.x = bounds.CenterPoint().x();
  mouse_event.y = bounds.CenterPoint().y();
  mouse_event.clickCount = 1;
  SendWebMouseEvent(mouse_event);
  mouse_event.type = blink::WebInputEvent::MouseUp;
  SendWebMouseEvent(mouse_event);
  ProcessPendingMessages();

  VerifyPageCount(1);
  VerifyPagesPrinted(true);
}

TEST_F(PrintWebViewHelperTest, BlockScriptInitiatedPrintingFromPopup) {
  PrintWebViewHelper* print_web_view_helper = PrintWebViewHelper::Get(view_);
  print_web_view_helper->SetScriptedPrintBlocked(true);
  PrintWithJavaScript();
  VerifyPagesPrinted(false);

  print_web_view_helper->SetScriptedPrintBlocked(false);
  PrintWithJavaScript();
  VerifyPageCount(1);
  VerifyPagesPrinted(true);
}

#if defined(OS_WIN) || defined(OS_MACOSX)
// TODO(estade): I don't think this test is worth porting to Linux. We will have
// to rip out and replace most of the IPC code if we ever plan to improve
// printing, and the comment below by sverrir suggests that it doesn't do much
// for us anyway.
TEST_F(PrintWebViewHelperTest, PrintWithIframe) {
  // Document that populates an iframe.
  const char html[] =
      "<html><body>Lorem Ipsum:"
      "<iframe name=\"sub1\" id=\"sub1\"></iframe><script>"
      "  document.write(frames['sub1'].name);"
      "  frames['sub1'].document.write("
      "      '<p>Cras tempus ante eu felis semper luctus!</p>');"
      "</script></body></html>";

  LoadHTML(html);

  // Find the frame and set it as the focused one.  This should mean that that
  // the printout should only contain the contents of that frame.
  WebFrame* sub1_frame =
      view_->GetWebView()->findFrameByName(WebString::fromUTF8("sub1"));
  ASSERT_TRUE(sub1_frame);
  view_->GetWebView()->setFocusedFrame(sub1_frame);
  ASSERT_NE(view_->GetWebView()->focusedFrame(),
            view_->GetWebView()->mainFrame());

  // Initiate printing.
  OnPrintPages();
  VerifyPagesPrinted(true);

  // Verify output through MockPrinter.
  const MockPrinter* printer(chrome_render_thread_->printer());
  ASSERT_EQ(1, printer->GetPrintedPages());
  const Image& image1(printer->GetPrintedPage(0)->image());

  // TODO(sverrir): Figure out a way to improve this test to actually print
  // only the content of the iframe.  Currently image1 will contain the full
  // page.
  EXPECT_NE(0, image1.size().width());
  EXPECT_NE(0, image1.size().height());
}
#endif

// Tests if we can print a page and verify its results.
// This test prints HTML pages into a pseudo printer and check their outputs,
// i.e. a simplified version of the PrintingLayoutTextTest UI test.
namespace {
// Test cases used in this test.
struct TestPageData {
  const char* page;
  size_t printed_pages;
  int width;
  int height;
  const char* checksum;
  const wchar_t* file;
};

#if defined(OS_WIN) || defined(OS_MACOSX)
const TestPageData kTestPages[] = {
  {"<html>"
  "<head>"
  "<meta"
  "  http-equiv=\"Content-Type\""
  "  content=\"text/html; charset=utf-8\"/>"
  "<title>Test 1</title>"
  "</head>"
  "<body style=\"background-color: white;\">"
  "<p style=\"font-family: arial;\">Hello World!</p>"
  "</body>",
#if defined(OS_MACOSX)
  // Mac printing code compensates for the WebKit scale factor while generating
  // the metafile, so we expect smaller pages.
  1, 600, 780,
#else
  1, 675, 900,
#endif
  NULL,
  NULL,
  },
};
#endif  // defined(OS_WIN) || defined(OS_MACOSX)
}  // namespace

// TODO(estade): need to port MockPrinter to get this on Linux. This involves
// hooking up Cairo to read a pdf stream, or accessing the cairo surface in the
// metafile directly.
#if defined(OS_WIN) || defined(OS_MACOSX)
TEST_F(PrintWebViewHelperTest, PrintLayoutTest) {
  bool baseline = false;

  EXPECT_TRUE(chrome_render_thread_->printer() != NULL);
  for (size_t i = 0; i < arraysize(kTestPages); ++i) {
    // Load an HTML page and print it.
    LoadHTML(kTestPages[i].page);
    OnPrintPages();
    VerifyPagesPrinted(true);

    // MockRenderThread::Send() just calls MockRenderThread::OnReceived().
    // So, all IPC messages sent in the above RenderView::OnPrintPages() call
    // has been handled by the MockPrinter object, i.e. this printing job
    // has been already finished.
    // So, we can start checking the output pages of this printing job.
    // Retrieve the number of pages actually printed.
    size_t pages = chrome_render_thread_->printer()->GetPrintedPages();
    EXPECT_EQ(kTestPages[i].printed_pages, pages);

    // Retrieve the width and height of the output page.
    int width = chrome_render_thread_->printer()->GetWidth(0);
    int height = chrome_render_thread_->printer()->GetHeight(0);

    // Check with margin for error.  This has been failing with a one pixel
    // offset on our buildbot.
    const int kErrorMargin = 5;  // 5%
    EXPECT_GT(kTestPages[i].width * (100 + kErrorMargin) / 100, width);
    EXPECT_LT(kTestPages[i].width * (100 - kErrorMargin) / 100, width);
    EXPECT_GT(kTestPages[i].height * (100 + kErrorMargin) / 100, height);
    EXPECT_LT(kTestPages[i].height* (100 - kErrorMargin) / 100, height);

    // Retrieve the checksum of the bitmap data from the pseudo printer and
    // compare it with the expected result.
    std::string bitmap_actual;
    EXPECT_TRUE(
        chrome_render_thread_->printer()->GetBitmapChecksum(0, &bitmap_actual));
    if (kTestPages[i].checksum)
      EXPECT_EQ(kTestPages[i].checksum, bitmap_actual);

    if (baseline) {
      // Save the source data and the bitmap data into temporary files to
      // create base-line results.
      base::FilePath source_path;
      base::CreateTemporaryFile(&source_path);
      chrome_render_thread_->printer()->SaveSource(0, source_path);

      base::FilePath bitmap_path;
      base::CreateTemporaryFile(&bitmap_path);
      chrome_render_thread_->printer()->SaveBitmap(0, bitmap_path);
    }
  }
}
#endif

// These print preview tests do not work on Chrome OS yet.
#if !defined(OS_CHROMEOS)
class PrintWebViewHelperPreviewTest : public PrintWebViewHelperTestBase {
 public:
  PrintWebViewHelperPreviewTest() {}
  virtual ~PrintWebViewHelperPreviewTest() {}

  virtual void SetUp() OVERRIDE {
    // Append the print preview switch before creating the PrintWebViewHelper.
    CommandLine::ForCurrentProcess()->AppendSwitch(
        switches::kRendererPrintPreview);

    ChromeRenderViewTest::SetUp();
  }

 protected:
  void VerifyPrintPreviewCancelled(bool did_cancel) {
    bool print_preview_cancelled =
        (render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_PrintPreviewCancelled::ID) != NULL);
    EXPECT_EQ(did_cancel, print_preview_cancelled);
  }

  void VerifyPrintPreviewFailed(bool did_fail) {
    bool print_preview_failed =
        (render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_PrintPreviewFailed::ID) != NULL);
    EXPECT_EQ(did_fail, print_preview_failed);
  }

  void VerifyPrintPreviewGenerated(bool generated_preview) {
    const IPC::Message* preview_msg =
        render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_MetafileReadyForPrinting::ID);
    bool did_get_preview_msg = (NULL != preview_msg);
    ASSERT_EQ(generated_preview, did_get_preview_msg);
    if (did_get_preview_msg) {
      PrintHostMsg_MetafileReadyForPrinting::Param preview_param;
      PrintHostMsg_MetafileReadyForPrinting::Read(preview_msg, &preview_param);
      EXPECT_NE(0, preview_param.a.document_cookie);
      EXPECT_NE(0, preview_param.a.expected_pages_count);
      EXPECT_NE(0U, preview_param.a.data_size);
    }
  }

  void VerifyPrintFailed(bool did_fail) {
    bool print_failed = (render_thread_->sink().GetUniqueMessageMatching(
        PrintHostMsg_PrintingFailed::ID) != NULL);
    EXPECT_EQ(did_fail, print_failed);
  }

  void VerifyPrintPreviewInvalidPrinterSettings(bool settings_invalid) {
    bool print_preview_invalid_printer_settings =
        (render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_PrintPreviewInvalidPrinterSettings::ID) != NULL);
    EXPECT_EQ(settings_invalid, print_preview_invalid_printer_settings);
  }

  // |page_number| is 0-based.
  void VerifyDidPreviewPage(bool generate_draft_pages, int page_number) {
    bool msg_found = false;
    size_t msg_count = render_thread_->sink().message_count();
    for (size_t i = 0; i < msg_count; ++i) {
      const IPC::Message* msg = render_thread_->sink().GetMessageAt(i);
      if (msg->type() == PrintHostMsg_DidPreviewPage::ID) {
        PrintHostMsg_DidPreviewPage::Param page_param;
        PrintHostMsg_DidPreviewPage::Read(msg, &page_param);
        if (page_param.a.page_number == page_number) {
          msg_found = true;
          if (generate_draft_pages)
            EXPECT_NE(0U, page_param.a.data_size);
          else
            EXPECT_EQ(0U, page_param.a.data_size);
          break;
        }
      }
    }
    ASSERT_EQ(generate_draft_pages, msg_found);
  }

  void VerifyDefaultPageLayout(int content_width, int content_height,
                               int margin_top, int margin_bottom,
                               int margin_left, int margin_right,
                               bool page_has_print_css) {
    const IPC::Message* default_page_layout_msg =
        render_thread_->sink().GetUniqueMessageMatching(
            PrintHostMsg_DidGetDefaultPageLayout::ID);
    bool did_get_default_page_layout_msg = (NULL != default_page_layout_msg);
    if (did_get_default_page_layout_msg) {
      PrintHostMsg_DidGetDefaultPageLayout::Param param;
      PrintHostMsg_DidGetDefaultPageLayout::Read(default_page_layout_msg,
                                                 &param);
      EXPECT_EQ(content_width, param.a.content_width);
      EXPECT_EQ(content_height, param.a.content_height);
      EXPECT_EQ(margin_top, param.a.margin_top);
      EXPECT_EQ(margin_right, param.a.margin_right);
      EXPECT_EQ(margin_left, param.a.margin_left);
      EXPECT_EQ(margin_bottom, param.a.margin_bottom);
      EXPECT_EQ(page_has_print_css, param.c);
    }
  }

  DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelperPreviewTest);
};

// Tests that print preview work and sending and receiving messages through
// that channel all works.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreview) {
  LoadHTML(kHelloWorldHTML);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
  VerifyPagesPrinted(false);
}

TEST_F(PrintWebViewHelperPreviewTest, PrintPreviewHTMLWithPageMarginsCss) {
  // A simple web page with print margins css.
  const char kHTMLWithPageMarginsCss[] =
      "<html><head><style>"
      "@media print {"
      "  @page {"
      "     margin: 3in 1in 2in 0.3in;"
      "  }"
      "}"
      "</style></head>"
      "<body>Lorem Ipsum:"
      "</body></html>";
  LoadHTML(kHTMLWithPageMarginsCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, false);
  dict.SetInteger(kSettingMarginsType, DEFAULT_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(519, 432, 216, 144, 21, 72, false);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
  VerifyPagesPrinted(false);
}

// Test to verify that print preview ignores print media css when non-default
// margin is selected.
TEST_F(PrintWebViewHelperPreviewTest, NonDefaultMarginsSelectedIgnorePrintCss) {
  LoadHTML(kHTMLWithPageSizeCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, false);
  dict.SetInteger(kSettingMarginsType, NO_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(612, 792, 0, 0, 0, 0, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
  VerifyPagesPrinted(false);
}

// Test to verify that print preview honor print media size css when
// PRINT_TO_PDF is selected and doesn't fit to printer default paper size.
TEST_F(PrintWebViewHelperPreviewTest, PrintToPDFSelectedHonorPrintCss) {
  LoadHTML(kHTMLWithPageSizeCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, true);
  dict.SetInteger(kSettingMarginsType,
                  PRINTABLE_AREA_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  // Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
  // size.
  VerifyDefaultPageLayout(252, 252, 18, 18, 18, 18, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
}

// Test to verify that print preview honor print margin css when PRINT_TO_PDF
// is selected and doesn't fit to printer default paper size.
TEST_F(PrintWebViewHelperPreviewTest, PrintToPDFSelectedHonorPageMarginsCss) {
  // A simple web page with print margins css.
  const char kHTMLWithPageCss[] =
      "<html><head><style>"
      "@media print {"
      "  @page {"
      "     margin: 3in 1in 2in 0.3in;"
      "     size: 14in 14in;"
      "  }"
      "}"
      "</style></head>"
      "<body>Lorem Ipsum:"
      "</body></html>";
  LoadHTML(kHTMLWithPageCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, true);
  dict.SetInteger(kSettingMarginsType, DEFAULT_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  // Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
  // size.
  VerifyDefaultPageLayout(915, 648, 216, 144, 21, 72, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
}

// Test to verify that print preview workflow center the html page contents to
// fit the page size.
TEST_F(PrintWebViewHelperPreviewTest, PrintPreviewCenterToFitPage) {
  LoadHTML(kHTMLWithPageSizeCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, false);
  dict.SetInteger(kSettingMarginsType, DEFAULT_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(216, 216, 288, 288, 198, 198, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
}

// Test to verify that print preview workflow scale the html page contents to
// fit the page size.
TEST_F(PrintWebViewHelperPreviewTest, PrintPreviewShrinkToFitPage) {
  // A simple web page with print margins css.
  const char kHTMLWithPageCss[] =
      "<html><head><style>"
      "@media print {"
      "  @page {"
      "     size: 15in 17in;"
      "  }"
      "}"
      "</style></head>"
      "<body>Lorem Ipsum:"
      "</body></html>";
  LoadHTML(kHTMLWithPageCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, false);
  dict.SetInteger(kSettingMarginsType, DEFAULT_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(571, 652, 69, 71, 20, 21, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
}

// Test to verify that print preview workflow honor the orientation settings
// specified in css.
TEST_F(PrintWebViewHelperPreviewTest, PrintPreviewHonorsOrientationCss) {
  LoadHTML(kHTMLWithLandscapePageCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, false);
  dict.SetInteger(kSettingMarginsType, NO_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(792, 612, 0, 0, 0, 0, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
}

// Test to verify that print preview workflow honors the orientation settings
// specified in css when PRINT_TO_PDF is selected.
TEST_F(PrintWebViewHelperPreviewTest, PrintToPDFSelectedHonorOrientationCss) {
  LoadHTML(kHTMLWithLandscapePageCss);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingPrintToPDF, true);
  dict.SetInteger(kSettingMarginsType, CUSTOM_MARGINS);
  OnPrintPreview(dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyDefaultPageLayout(748, 568, 21, 23, 21, 23, true);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
}

// Test to verify that complete metafile is generated for a subset of pages
// without creating draft pages.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreviewForSelectedPages) {
  LoadHTML(kMultipageHTML);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);

  // Set a page range and update the dictionary to generate only the complete
  // metafile with the selected pages. Page numbers used in the dictionary
  // are 1-based.
  base::DictionaryValue* page_range = new base::DictionaryValue();
  page_range->SetInteger(kSettingPageRangeFrom, 2);
  page_range->SetInteger(kSettingPageRangeTo, 3);

  base::ListValue* page_range_array = new base::ListValue();
  page_range_array->Append(page_range);

  dict.Set(kSettingPageRange, page_range_array);
  dict.SetBoolean(kSettingGenerateDraftData, false);

  OnPrintPreview(dict);

  VerifyDidPreviewPage(false, 0);
  VerifyDidPreviewPage(false, 1);
  VerifyDidPreviewPage(false, 2);
  VerifyPreviewPageCount(3);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
  VerifyPagesPrinted(false);
}

// Test to verify that preview generated only for one page.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreviewForSelectedText) {
  LoadHTML(kMultipageHTML);
  GetMainFrame()->selectRange(
      blink::WebRange::fromDocumentRange(GetMainFrame(), 1, 3));

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  dict.SetBoolean(kSettingShouldPrintSelectionOnly, true);

  OnPrintPreview(dict);

  VerifyPreviewPageCount(1);
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(true);
  VerifyPagesPrinted(false);
}

// Tests that print preview fails and receiving error messages through
// that channel all works.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreviewFail) {
  LoadHTML(kHelloWorldHTML);

  // An empty dictionary should fail.
  base::DictionaryValue empty_dict;
  OnPrintPreview(empty_dict);

  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());
  VerifyPrintPreviewCancelled(false);
  VerifyPrintPreviewFailed(true);
  VerifyPrintPreviewGenerated(false);
  VerifyPagesPrinted(false);
}

// Tests that cancelling print preview works.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintPreviewCancel) {
  LoadHTML(kLongPageHTML);

  const int kCancelPage = 3;
  chrome_render_thread_->set_print_preview_cancel_page_number(kCancelPage);
  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintPreview(dict);

  EXPECT_EQ(kCancelPage,
            chrome_render_thread_->print_preview_pages_remaining());
  VerifyPrintPreviewCancelled(true);
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(false);
  VerifyPagesPrinted(false);
}

// Tests that printing from print preview works and sending and receiving
// messages through that channel all works.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintForPrintPreview) {
  LoadHTML(kPrintPreviewHTML);

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintForPrintPreview(dict);

  VerifyPrintFailed(false);
  VerifyPagesPrinted(true);
}

// Tests that printing from print preview fails and receiving error messages
// through that channel all works.
TEST_F(PrintWebViewHelperPreviewTest, OnPrintForPrintPreviewFail) {
  LoadHTML(kPrintPreviewHTML);

  // An empty dictionary should fail.
  base::DictionaryValue empty_dict;
  OnPrintForPrintPreview(empty_dict);

  VerifyPagesPrinted(false);
}

// Tests that when default printer has invalid printer settings, print preview
// receives error message.
TEST_F(PrintWebViewHelperPreviewTest,
       OnPrintPreviewUsingInvalidPrinterSettings) {
  LoadHTML(kPrintPreviewHTML);

  // Set mock printer to provide invalid settings.
  chrome_render_thread_->printer()->UseInvalidSettings();

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintPreview(dict);

  // We should have received invalid printer settings from |printer_|.
  VerifyPrintPreviewInvalidPrinterSettings(true);
  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());

  // It should receive the invalid printer settings message only.
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(false);
}

// Tests that when the selected printer has invalid page settings, print preview
// receives error message.
TEST_F(PrintWebViewHelperPreviewTest,
       OnPrintPreviewUsingInvalidPageSize) {
  LoadHTML(kPrintPreviewHTML);

  chrome_render_thread_->printer()->UseInvalidPageSize();

  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintPreview(dict);

  VerifyPrintPreviewInvalidPrinterSettings(true);
  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());

  // It should receive the invalid printer settings message only.
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(false);
}

// Tests that when the selected printer has invalid content settings, print
// preview receives error message.
TEST_F(PrintWebViewHelperPreviewTest,
       OnPrintPreviewUsingInvalidContentSize) {
  LoadHTML(kPrintPreviewHTML);

  chrome_render_thread_->printer()->UseInvalidContentSize();

  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintPreview(dict);

  VerifyPrintPreviewInvalidPrinterSettings(true);
  EXPECT_EQ(0, chrome_render_thread_->print_preview_pages_remaining());

  // It should receive the invalid printer settings message only.
  VerifyPrintPreviewFailed(false);
  VerifyPrintPreviewGenerated(false);
}

TEST_F(PrintWebViewHelperPreviewTest,
       OnPrintForPrintPreviewUsingInvalidPrinterSettings) {
  LoadHTML(kPrintPreviewHTML);

  // Set mock printer to provide invalid settings.
  chrome_render_thread_->printer()->UseInvalidSettings();

  // Fill in some dummy values.
  base::DictionaryValue dict;
  CreatePrintSettingsDictionary(&dict);
  OnPrintForPrintPreview(dict);

  VerifyPrintFailed(true);
  VerifyPagesPrinted(false);
}

#endif  // !defined(OS_CHROMEOS)

class PrintWebViewHelperKioskTest : public PrintWebViewHelperTestBase {
 public:
  PrintWebViewHelperKioskTest() {}
  virtual ~PrintWebViewHelperKioskTest() {}

  virtual void SetUp() OVERRIDE {
    // Append the throttling disable switch before creating the
    // PrintWebViewHelper.
    CommandLine::ForCurrentProcess()->AppendSwitch(
        switches::kDisableScriptedPrintThrottling);

    ChromeRenderViewTest::SetUp();
  }

 protected:
  DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelperKioskTest);
};

// Tests that the switch overrides the throttling that blocks window.print()
// calls if they occur too frequently. Compare with
// PrintWebViewHelperTest.BlockScriptInitiatedPrinting above.
TEST_F(PrintWebViewHelperKioskTest, DontBlockScriptInitiatedPrinting) {
  // Pretend user will cancel printing.
  chrome_render_thread_->set_print_dialog_user_response(false);
  // Try to print with window.print() a few times.
  PrintWithJavaScript();
  chrome_render_thread_->printer()->ResetPrinter();
  PrintWithJavaScript();
  chrome_render_thread_->printer()->ResetPrinter();
  PrintWithJavaScript();
  chrome_render_thread_->printer()->ResetPrinter();
  VerifyPagesPrinted(false);

  // Pretend user will print, should not be throttled.
  chrome_render_thread_->set_print_dialog_user_response(true);
  PrintWithJavaScript();
  VerifyPagesPrinted(true);
}

}  // namespace printing

/* [<][>][^][v][top][bottom][index][help] */