blob: 0c9055a355e4eab05d6d68f143d2bbf5ae0329e8 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/printing/renderer/print_render_frame_helper.h"
#include <stddef.h>
#include <cmath>
#include <memory>
#include <string_view>
#include <utility>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/printing/common/print.mojom-test-utils.h"
#include "components/printing/common/print.mojom.h"
#include "components/printing/common/print_params.h"
#include "components/printing/test/mock_printer.h"
#include "components/printing/test/print_test_content_renderer_client.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/test/mock_render_thread.h"
#include "content/public/test/render_view_test.h"
#include "ipc/ipc_listener.h"
#include "printing/buildflags/buildflags.h"
#include "printing/image.h"
#include "printing/mojom/print.mojom.h"
#include "printing/page_range.h"
#include "printing/print_job_constants.h"
#include "printing/printing_utils.h"
#include "printing/units.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_range.h"
#include "third_party/blink/public/web/web_view.h"
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
#include "components/printing/browser/print_manager_utils.h"
#include "printing/print_settings.h"
#include "printing/print_settings_conversion.h"
#endif
using blink::WebFrame;
using blink::WebLocalFrame;
using blink::WebString;
namespace printing {
namespace {
// A simple web page.
const char kHelloWorldHTML[] = "<body><p>Hello World!</p></body>";
// Web page used for testing onbeforeprint/onafterprint.
const char kBeforeAfterPrintHtml[] =
"<body>"
"<script>"
"var beforePrintCount = 0;"
"var afterPrintCount = 0;"
"window.onbeforeprint = () => { ++beforePrintCount; };"
"window.onafterprint = () => { ++afterPrintCount; };"
"</script>"
"<button id=\"print\" onclick=\"window.print();\">Hello World!</button>"
"</body>";
// 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>";
#if !BUILDFLAG(IS_CHROMEOS_ASH)
// 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 BUILDFLAG(ENABLE_PRINT_PREVIEW)
// 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>";
const char kHTMLWithManyLinesOfText[] =
"<html><head><style>"
"p { font-size: 24px; }"
"</style></head><body>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"<p>The quick brown fox jumped over the lazy dog.</p>"
"</body></html>";
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
class FakePrintPreviewUI : public mojom::PrintPreviewUI {
public:
struct PageData {
uint32_t index;
uint32_t content_data_size;
};
FakePrintPreviewUI() = default;
~FakePrintPreviewUI() override = default;
mojo::PendingAssociatedRemote<mojom::PrintPreviewUI> BindReceiver() {
return receiver_.BindNewEndpointAndPassDedicatedRemote();
}
void ResetPreviewStatus() {
// Make sure there is no active request.
DCHECK(!quit_closure_);
preview_status_ = PreviewStatus::kNone;
}
// Waits until the preview request is failed, canceled, invalid, or done.
void WaitUntilPreviewUpdate() {
// If |preview_status_| is updated, it doesn't need to wait.
if (preview_status_ != PreviewStatus::kNone)
return;
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
// Sets the page number to be cancelled.
void set_print_preview_cancel_page_number(uint32_t page) {
print_preview_cancel_page_number_ = page;
}
bool PreviewFailed() const {
return preview_status_ == PreviewStatus::kFailed;
}
bool PreviewCancelled() const {
return preview_status_ == PreviewStatus::kCancelled;
}
bool InvalidPrinterSetting() const {
return preview_status_ == PreviewStatus::kInvalidSetting;
}
bool IsMetafileReadyForPrinting() const {
return preview_status_ == PreviewStatus::kMetafileReadyForPrinting;
}
uint32_t page_count() const { return page_count_; }
mojom::PageSizeMargins* page_layout() const {
return page_layout_ ? page_layout_.get() : nullptr;
}
uint32_t print_preview_pages_remaining() const {
return print_preview_pages_remaining_;
}
mojom::DidPreviewDocumentParams* did_preview_document_params() const {
return did_preview_document_params_ ? did_preview_document_params_.get()
: nullptr;
}
const std::vector<PageData>& print_preview_pages() const {
return print_preview_pages_;
}
bool all_pages_have_custom_size() const {
return all_pages_have_custom_size_;
}
bool all_pages_have_custom_orientation() const {
return all_pages_have_custom_orientation_;
}
// mojom::PrintPreviewUI:
void SetOptionsFromDocument(const mojom::OptionsFromDocumentParamsPtr params,
int32_t request_id) override {}
void DidPrepareDocumentForPreview(int32_t document_cookie,
int32_t request_id) override {}
void DidPreviewPage(mojom::DidPreviewPageParamsPtr params,
int32_t request_id) override {
uint32_t page_index = params->page_index;
DCHECK_NE(page_index, kInvalidPageIndex);
print_preview_pages_remaining_--;
print_preview_pages_.emplace_back(
params->page_index, params->content->metafile_data_region.GetSize());
}
void MetafileReadyForPrinting(mojom::DidPreviewDocumentParamsPtr params,
int32_t request_id) override {
DCHECK_EQ(preview_status_, PreviewStatus::kNone);
preview_status_ = PreviewStatus::kMetafileReadyForPrinting;
did_preview_document_params_ = std::move(params);
RunQuitClosure();
}
void PrintPreviewFailed(int32_t document_cookie,
int32_t request_id) override {
DCHECK_EQ(preview_status_, PreviewStatus::kNone);
preview_status_ = PreviewStatus::kFailed;
RunQuitClosure();
}
void PrintPreviewCancelled(int32_t document_cookie,
int32_t request_id) override {
DCHECK_EQ(preview_status_, PreviewStatus::kNone);
preview_status_ = PreviewStatus::kCancelled;
RunQuitClosure();
}
void PrinterSettingsInvalid(int32_t document_cookie,
int32_t request_id) override {
DCHECK_EQ(preview_status_, PreviewStatus::kNone);
preview_status_ = PreviewStatus::kInvalidSetting;
RunQuitClosure();
}
void DidGetDefaultPageLayout(mojom::PageSizeMarginsPtr page_layout_in_points,
const gfx::RectF& printable_area_in_points,
bool all_pages_have_custom_size,
bool all_pages_have_custom_orientation,
int32_t request_id) override {
page_layout_ = std::move(page_layout_in_points);
all_pages_have_custom_size_ = all_pages_have_custom_size;
all_pages_have_custom_orientation_ = all_pages_have_custom_orientation;
}
void DidStartPreview(mojom::DidStartPreviewParamsPtr params,
int32_t request_id) override {
page_count_ = params->page_count;
print_preview_pages_remaining_ = params->page_count;
}
// Determines whether to cancel a print preview request.
bool ShouldCancelRequest() const {
return print_preview_pages_remaining_ == print_preview_cancel_page_number_;
}
private:
void RunQuitClosure() {
if (!quit_closure_)
return;
std::move(quit_closure_).Run();
}
enum class PreviewStatus {
kNone = 0,
kFailed,
kCancelled,
kInvalidSetting,
kMetafileReadyForPrinting,
};
PreviewStatus preview_status_ = PreviewStatus::kNone;
uint32_t page_count_ = 0;
bool all_pages_have_custom_size_ = false;
bool all_pages_have_custom_orientation_ = false;
// Simulates cancelling print preview if |print_preview_pages_remaining_|
// equals this.
uint32_t print_preview_cancel_page_number_ = kInvalidPageIndex;
mojom::PageSizeMarginsPtr page_layout_;
mojom::DidPreviewDocumentParamsPtr did_preview_document_params_;
// Number of pages to generate for print preview.
uint32_t print_preview_pages_remaining_ = 0;
// Vector of <page_index, content_data_size> that were previewed.
std::vector<PageData> print_preview_pages_;
base::OnceClosure quit_closure_;
base::OnceClosure quit_closure_for_preview_started_;
mojo::AssociatedReceiver<mojom::PrintPreviewUI> receiver_{this};
};
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
class TestPrintManagerHost
: public mojom::PrintManagerHostInterceptorForTesting {
public:
TestPrintManagerHost(content::RenderFrame* frame, MockPrinter* printer)
: printer_(printer) {
Init(frame);
}
~TestPrintManagerHost() override = default;
// mojom::PrintManagerHostInterceptorForTesting
mojom::PrintManagerHost* GetForwardingInterface() override { return nullptr; }
void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override {
if (number_pages_ > 0)
EXPECT_EQ(number_pages, number_pages_);
printer_->SetPrintedPagesCount(cookie, number_pages);
}
void DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
DidPrintDocumentCallback callback) override {
base::RunLoop().RunUntilIdle();
printer_->OnDocumentPrinted(std::move(params));
std::move(callback).Run(true);
is_printed_ = true;
}
void IsPrintingEnabled(IsPrintingEnabledCallback callback) override {
std::move(callback).Run(is_printing_enabled_);
}
void GetDefaultPrintSettings(
GetDefaultPrintSettingsCallback callback) override {
printing::mojom::PrintParamsPtr params =
printer_->GetDefaultPrintSettings();
std::move(callback).Run(std::move(params));
}
void DidShowPrintDialog() override {}
void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params,
ScriptedPrintCallback callback) override {
if (!print_dialog_user_response_) {
std::move(callback).Run(nullptr);
return;
}
auto settings = printing::mojom::PrintPagesParams::New();
settings->params = printing::mojom::PrintParams::New();
printer_->ScriptedPrint(params->cookie, params->expected_pages_count,
params->has_selection, settings.get());
if (!PrintMsgPrintParamsIsValid(*settings->params)) {
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(std::move(settings));
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void UpdatePrintSettings(base::Value::Dict job_settings,
UpdatePrintSettingsCallback callback) override {
// Check and make sure the required settings are all there.
std::optional<int> margins_type = job_settings.FindInt(kSettingMarginsType);
if (!margins_type.has_value() ||
!job_settings.FindBool(kSettingLandscape) ||
!job_settings.FindBool(kSettingCollate) ||
!job_settings.FindInt(kSettingColor) ||
!job_settings.FindInt(kSettingPrinterType) ||
!job_settings.FindBool(kIsFirstRequest) ||
!job_settings.FindString(kSettingDeviceName) ||
!job_settings.FindInt(kSettingDuplexMode) ||
!job_settings.FindInt(kSettingCopies) ||
!job_settings.FindInt(kPreviewUIID) ||
!job_settings.FindInt(kPreviewRequestID)) {
std::move(callback).Run(nullptr);
return;
}
std::unique_ptr<PrintSettings> print_settings =
PrintSettingsFromJobSettings(job_settings);
if (!print_settings) {
std::move(callback).Run(nullptr);
return;
}
mojom::PrintPagesParamsPtr settings = mojom::PrintPagesParams::New();
settings->pages = GetPageRangesFromJobSettings(job_settings);
settings->params = mojom::PrintParams::New();
RenderParamsFromPrintSettings(*print_settings, settings->params.get());
settings->params->document_cookie = PrintSettings::NewCookie();
if (!PrintMsgPrintParamsIsValid(*settings->params)) {
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(std::move(settings));
}
void SetupScriptedPrintPreview(
SetupScriptedPrintPreviewCallback callback) override {
is_setup_scripted_print_preview_ = true;
std::move(callback).Run();
}
void ShowScriptedPrintPreview(bool source_is_modifiable) override {}
void RequestPrintPreview(
mojom::RequestPrintPreviewParamsPtr params) override {}
void CheckForCancel(int32_t preview_ui_id,
int32_t request_id,
CheckForCancelCallback callback) override {
// Waits until other mojo messages are handled before checking if
// the print preview is canceled.
base::RunLoop().RunUntilIdle();
std::move(callback).Run(preview_ui_->ShouldCancelRequest());
}
void SetAccessibilityTree(
int32_t cookie,
const ui::AXTreeUpdate& accessibility_tree) override {
++accessibility_tree_set_count_;
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
bool IsSetupScriptedPrintPreview() {
return is_setup_scripted_print_preview_;
}
void ResetSetupScriptedPrintPreview() {
is_setup_scripted_print_preview_ = false;
}
bool IsPrinted() { return is_printed_; }
void SetExpectedPagesCount(uint32_t number_pages) {
number_pages_ = number_pages;
}
void WaitUntilBinding() {
if (receiver_.is_bound())
return;
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
void SetPrintingEnabled(bool enabled) { is_printing_enabled_ = enabled; }
// Call with |response| set to true if the user wants to print.
// False if the user decides to cancel.
void SetPrintDialogUserResponse(bool response) {
print_dialog_user_response_ = response;
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void set_preview_ui(FakePrintPreviewUI* preview_ui) {
preview_ui_ = preview_ui;
}
#endif
int accessibility_tree_set_count() const {
return accessibility_tree_set_count_;
}
private:
void Init(content::RenderFrame* frame) {
frame->GetRemoteAssociatedInterfaces()->OverrideBinderForTesting(
mojom::PrintManagerHost::Name_,
base::BindRepeating(&TestPrintManagerHost::BindPrintManagerReceiver,
base::Unretained(this)));
}
void BindPrintManagerReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
receiver_.Bind(mojo::PendingAssociatedReceiver<mojom::PrintManagerHost>(
std::move(handle)));
if (!quit_closure_)
return;
std::move(quit_closure_).Run();
}
uint32_t number_pages_ = 0;
bool is_setup_scripted_print_preview_ = false;
bool is_printed_ = false;
raw_ptr<MockPrinter> printer_;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
raw_ptr<FakePrintPreviewUI> preview_ui_;
#endif
base::OnceClosure quit_closure_;
bool is_printing_enabled_ = true;
// True to simulate user clicking print. False to cancel.
bool print_dialog_user_response_ = true;
int accessibility_tree_set_count_ = 0;
mojo::AssociatedReceiver<mojom::PrintManagerHost> receiver_{this};
};
} // namespace
class PrintRenderFrameHelperTestBase : public content::RenderViewTest {
public:
PrintRenderFrameHelperTestBase() = default;
PrintRenderFrameHelperTestBase(const PrintRenderFrameHelperTestBase&) =
delete;
PrintRenderFrameHelperTestBase& operator=(
const PrintRenderFrameHelperTestBase&) = delete;
~PrintRenderFrameHelperTestBase() override = default;
protected:
// content::RenderViewTest:
content::ContentRendererClient* CreateContentRendererClient() override {
return new PrintTestContentRendererClient(/*generate_tagged_pdfs=*/false);
}
void SetUp() override {
render_thread_ = std::make_unique<content::MockRenderThread>();
printer_ = std::make_unique<MockPrinter>();
content::RenderViewTest::SetUp();
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
preview_ui_ = std::make_unique<FakePrintPreviewUI>();
#endif
BindPrintManagerHost(content::RenderFrame::FromWebFrame(GetMainFrame()));
}
void TearDown() override {
#if defined(LEAK_SANITIZER)
// Do this before shutting down V8 in RenderViewTest::TearDown().
// http://crbug.com/328552
__lsan_do_leak_check();
#endif
content::RenderViewTest::TearDown();
}
void BindPrintManagerHost(content::RenderFrame* frame) {
auto print_manager =
std::make_unique<TestPrintManagerHost>(frame, printer());
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
print_manager->set_preview_ui(preview_ui_.get());
#endif
GetPrintRenderFrameHelperForFrame(frame)->GetPrintManagerHost();
print_manager->WaitUntilBinding();
frame_to_print_manager_map_.emplace(frame, std::move(print_manager));
}
void ClearPrintManagerHost() { frame_to_print_manager_map_.clear(); }
void PrintWithJavaScript() {
print_manager()->ResetSetupScriptedPrintPreview();
ExecuteJavaScriptForTests("window.print();");
base::RunLoop().RunUntilIdle();
}
// Verifies whether the pages printed or not.
void VerifyPagesPrintedForFrame(bool expect_printed,
content::RenderFrame* render_frame) {
ASSERT_EQ(expect_printed, print_manager(render_frame)->IsPrinted());
}
// Same as VerifyPagesPrintedForFrame(), but defaults to the main frame.
void VerifyPagesPrinted(bool expect_printed) {
auto* render_frame = content::RenderFrame::FromWebFrame(GetMainFrame());
VerifyPagesPrintedForFrame(expect_printed, render_frame);
}
void OnPrintPages() {
GetPrintRenderFrameHelper()->PrintRequestedPages();
base::RunLoop().RunUntilIdle();
}
void OnPrintPagesInFrame(std::string_view frame_name) {
blink::WebFrame* frame =
GetMainFrame()->FindFrameByName(blink::WebString::FromUTF8(frame_name));
ASSERT_TRUE(frame);
content::RenderFrame* render_frame =
content::RenderFrame::FromWebFrame(frame->ToWebLocalFrame());
BindPrintManagerHost(render_frame);
PrintRenderFrameHelper* helper =
GetPrintRenderFrameHelperForFrame(render_frame);
ASSERT_TRUE(helper);
helper->PrintRequestedPages();
base::RunLoop().RunUntilIdle();
}
PrintRenderFrameHelper* GetPrintRenderFrameHelper() {
return PrintRenderFrameHelper::Get(
content::RenderFrame::FromWebFrame(GetMainFrame()));
}
PrintRenderFrameHelper* GetPrintRenderFrameHelperForFrame(
content::RenderFrame* frame) {
return PrintRenderFrameHelper::Get(frame);
}
void ClickMouseButton(const gfx::Rect& bounds) {
EXPECT_FALSE(bounds.IsEmpty());
blink::WebMouseEvent mouse_event(
blink::WebInputEvent::Type::kMouseDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
mouse_event.button = blink::WebMouseEvent::Button::kLeft;
mouse_event.SetPositionInWidget(bounds.CenterPoint().x(),
bounds.CenterPoint().y());
mouse_event.click_count = 1;
SendWebMouseEvent(mouse_event);
mouse_event.SetType(blink::WebInputEvent::Type::kMouseUp);
SendWebMouseEvent(mouse_event);
}
void ExpectNoBeforeNoAfterPrintEvent() {
int result;
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"beforePrintCount", &result));
EXPECT_EQ(0, result) << "beforeprint event should not be dispatched.";
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"afterPrintCount", &result));
EXPECT_EQ(0, result) << "afterprint event should not be dispatched.";
}
void ExpectOneBeforeNoAfterPrintEvent() {
int result;
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"beforePrintCount", &result));
EXPECT_EQ(1, result) << "beforeprint event should be dispatched once.";
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"afterPrintCount", &result));
EXPECT_EQ(0, result) << "afterprint event should not be dispatched.";
}
void ExpectOneBeforeOneAfterPrintEvent() {
int result;
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"beforePrintCount", &result));
EXPECT_EQ(1, result) << "beforeprint event should be dispatched once.";
ASSERT_TRUE(
ExecuteJavaScriptAndReturnIntValue(u"afterPrintCount", &result));
EXPECT_EQ(1, result) << "afterprint event should be dispatched once.";
}
TestPrintManagerHost* print_manager(content::RenderFrame* frame = nullptr) {
if (!frame)
frame = content::RenderFrame::FromWebFrame(GetMainFrame());
auto it = frame_to_print_manager_map_.find(frame);
return it->second.get();
}
MockPrinter* printer() { return printer_.get(); }
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
FakePrintPreviewUI* preview_ui() { return preview_ui_.get(); }
#endif
private:
// A mock printer device used for printing tests.
std::unique_ptr<MockPrinter> printer_;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
std::unique_ptr<FakePrintPreviewUI> preview_ui_;
#endif
std::map<content::RenderFrame*, std::unique_ptr<TestPrintManagerHost>>
frame_to_print_manager_map_;
};
// RenderViewTest-based tests crash on Android
// http://crbug.com/187500
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_PrintRenderFrameHelperTest DISABLED_PrintRenderFrameHelperTest
#else
#define MAYBE_PrintRenderFrameHelperTest PrintRenderFrameHelperTest
#endif // BUILDFLAG(IS_ANDROID)
class MAYBE_PrintRenderFrameHelperTest : public PrintRenderFrameHelperTestBase {
public:
MAYBE_PrintRenderFrameHelperTest() = default;
MAYBE_PrintRenderFrameHelperTest(const MAYBE_PrintRenderFrameHelperTest&) =
delete;
MAYBE_PrintRenderFrameHelperTest& operator=(
const MAYBE_PrintRenderFrameHelperTest&) = delete;
~MAYBE_PrintRenderFrameHelperTest() override = default;
};
// This tests only for platforms without print preview.
#if !BUILDFLAG(ENABLE_PRINT_PREVIEW)
// Tests that the renderer blocks window.print() calls if they occur too
// frequently.
TEST_F(MAYBE_PrintRenderFrameHelperTest, BlockScriptInitiatedPrinting) {
// Pretend user will cancel printing.
print_manager()->SetPrintDialogUserResponse(false);
// Try to print with window.print() a few times.
PrintWithJavaScript();
PrintWithJavaScript();
PrintWithJavaScript();
VerifyPagesPrinted(false);
// Pretend user will print. (but printing is blocked.)
print_manager()->SetPrintDialogUserResponse(true);
PrintWithJavaScript();
VerifyPagesPrinted(false);
// Unblock script initiated printing and verify printing works.
GetPrintRenderFrameHelper()->scripting_throttler_.Reset();
printer()->Reset();
print_manager()->SetExpectedPagesCount(1);
PrintWithJavaScript();
VerifyPagesPrinted(true);
}
// Tests that the renderer always allows window.print() calls if they are user
// initiated.
TEST_F(MAYBE_PrintRenderFrameHelperTest, AllowUserOriginatedPrinting) {
// Pretend user will cancel printing.
print_manager()->SetPrintDialogUserResponse(false);
// Try to print with window.print() a few times.
PrintWithJavaScript();
PrintWithJavaScript();
PrintWithJavaScript();
VerifyPagesPrinted(false);
// Pretend user will print. (but printing is blocked.)
print_manager()->SetPrintDialogUserResponse(true);
PrintWithJavaScript();
VerifyPagesPrinted(false);
// Try again as if user initiated, without resetting the print count.
printer()->Reset();
LoadHTML(kPrintOnUserAction);
gfx::Size new_size(200, 100);
Resize(new_size, false);
print_manager()->SetExpectedPagesCount(1);
gfx::Rect bounds = GetElementBounds("print");
ClickMouseButton(bounds);
base::RunLoop().RunUntilIdle();
VerifyPagesPrinted(true);
}
// Duplicate of OnPrintPagesTest only using javascript to print.
TEST_F(MAYBE_PrintRenderFrameHelperTest, PrintWithJavascript) {
print_manager()->SetExpectedPagesCount(1);
PrintWithJavaScript();
VerifyPagesPrinted(true);
}
// Regression test for https://crbug.com/912966
TEST_F(MAYBE_PrintRenderFrameHelperTest, WindowPrintBeforePrintAfterPrint) {
LoadHTML(kBeforeAfterPrintHtml);
ExpectNoBeforeNoAfterPrintEvent();
print_manager()->SetExpectedPagesCount(1);
PrintWithJavaScript();
VerifyPagesPrinted(true);
ExpectOneBeforeOneAfterPrintEvent();
}
#endif // !BUILDFLAG(ENABLE_PRINT_PREVIEW)
// Tests that printing pages work and sending and receiving messages through
// that channel all works.
TEST_F(MAYBE_PrintRenderFrameHelperTest, OnPrintPages) {
LoadHTML(kHelloWorldHTML);
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, BasicBeforePrintAfterPrint) {
LoadHTML(kBeforeAfterPrintHtml);
ExpectNoBeforeNoAfterPrintEvent();
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
ExpectOneBeforeOneAfterPrintEvent();
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, BasicBeforePrintAfterPrintSubFrame) {
static const char kCloseOnBeforeHtml[] =
"<body>Hello"
"<iframe name=sub srcdoc='<script>"
"window.onbeforeprint = () => { window.frameElement.remove(); };"
"</script>'></iframe>"
"</body>";
LoadHTML(kCloseOnBeforeHtml);
content::RenderFrame* sub_render_frame = content::RenderFrame::FromWebFrame(
GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());
OnPrintPagesInFrame("sub");
EXPECT_EQ(nullptr, GetMainFrame()->FindFrameByName("sub"));
VerifyPagesPrintedForFrame(false, sub_render_frame);
ClearPrintManagerHost();
static const char kCloseOnAfterHtml[] =
"<body>Hello"
"<iframe name=sub srcdoc='<script>"
"window.onafterprint = () => { window.frameElement.remove(); };"
"</script>'></iframe>"
"</body>";
LoadHTML(kCloseOnAfterHtml);
sub_render_frame = content::RenderFrame::FromWebFrame(
GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());
OnPrintPagesInFrame("sub");
EXPECT_EQ(nullptr, GetMainFrame()->FindFrameByName("sub"));
VerifyPagesPrintedForFrame(true, sub_render_frame);
}
// https://crbug.com/1372396
//
// There used to be a Blink bug when entering print preview with a monolithic
// absolutely positioned box that extended into a page where the parent had no
// representation. It could only be reproduced when entering print preview,
// because print preview apparently enters print mode, runs a rendering
// lifecycle update, leaves print mode *without* running a rendering lifecycle
// update, then enter print mode a second time. When running a rendering
// lifecycle update this time, we'd fail a DCHECK, because when leaving print
// mode the first time, we'd mark for paint invalidation. Not handling it at
// that point (no lifecycle update) is fine in principle, but it used to cause
// some bad ancestry node marking when we got to the lifecycle update when
// entering print mode for the second time.
TEST_F(MAYBE_PrintRenderFrameHelperTest, MonolithicAbsposOverflowingParent) {
LoadHTML(R"HTML(
<style>
#trouble {
contain: size;
position: absolute;
top: 5000px;
width: 100px;
height: 100px;
background: lime;
}
</style>
<div style="position:relative; height:10000px;">
<div>
<div id="trouble"></div>
</div>
</div>
)HTML");
OnPrintPages();
}
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
TEST_F(MAYBE_PrintRenderFrameHelperTest, Pixels) {
// This test should generate two pages. The first should be 16x16 CSS pixels
// large, and the second should be 24x24. The pixels and page size information
// are going on a ride through the machineries, so use size values carefully,
// to avoid subpixel issues. At some point on the journey, everything will be
// changed to 300 DPI, and the page sizes involved will be rounded to integers
// (so we need something that ends up with integers after having been
// multiplied by 300/72 and back). See crbug.com/1466995 . Furthermore, the
// final output will be in points, not CSS pixels, which is why the
// expectation is to get 12x12 and 18x18 pages instead of 16x16 and 24x24 (and
// a 4px border becomes a 3pt border).
LoadHTML(R"HTML(
<style>
@page {
size: 24px;
margin: 0;
}
@page:first {
size: 16px;
}
body {
margin: 0;
}
div {
box-sizing: border-box;
border: 4px solid;
}
</style>
<div style="width:16px; height:16px; border-color:#00ff00;"></div>
<div style="width:24px; height:24px; border-color:#0000ff;"></div>
)HTML");
printer()->set_should_generate_page_images(true);
printer()->Params().should_print_backgrounds = true;
OnPrintPages();
// First page:
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const Image& first_image = page->image();
ASSERT_EQ(first_image.size(), gfx::Size(12, 12));
// Top left corner:
EXPECT_EQ(first_image.pixel_at(0, 0), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(2, 2), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(3, 3), 0xffffffU);
// Top right corner:
EXPECT_EQ(first_image.pixel_at(11, 0), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(9, 2), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(8, 3), 0xffffffU);
// Bottom right corner:
EXPECT_EQ(first_image.pixel_at(11, 11), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(9, 9), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(8, 8), 0xffffffU);
// Bottom left corner:
EXPECT_EQ(first_image.pixel_at(0, 11), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(2, 9), 0x00ff00U);
EXPECT_EQ(first_image.pixel_at(3, 8), 0xffffffU);
// Second page:
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
const Image& second_image = page->image();
ASSERT_EQ(second_image.size(), gfx::Size(18, 18));
// Top left corner:
EXPECT_EQ(second_image.pixel_at(0, 0), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(2, 2), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(3, 3), 0xffffffU);
// Top right corner:
EXPECT_EQ(second_image.pixel_at(0, 17), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(2, 15), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(3, 14), 0xffffffU);
// Bottom right corner:
EXPECT_EQ(second_image.pixel_at(17, 17), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(15, 15), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(14, 14), 0xffffffU);
// Bottom left corner:
EXPECT_EQ(second_image.pixel_at(0, 17), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(2, 15), 0x0000ffU);
EXPECT_EQ(second_image.pixel_at(3, 14), 0xffffffU);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, RoundingAndHeadersAndFooters) {
// Use values that end up as fractional values. The output is converted from
// CSS pixels (96 DPI) to points (72 DPI), and also via 300 DPI, and some
// rounding is applied on the way. See also crbug.com/1466995
LoadHTML(R"HTML(
<style>
@page {
size: 21px;
margin: 4px;
}
body {
margin: 0;
background: #0000ff;
}
</style>
<body></body>
)HTML");
// Print without headers and footers.
printer()->set_should_generate_page_images(true);
printer()->Params().should_print_backgrounds = true;
printer()->Params().display_header_footer = false;
OnPrintPages();
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
printing::Image image(page->image());
printer()->Reset();
// Print again, this time with headers and footers. Note that no headers or
// footers will actually be shown, since the page margins are so small, so
// this should look identical to the output with headers and footers turned
// off.
printer()->Params().display_header_footer = true;
OnPrintPages();
page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
// First check that the two results are identical.
ASSERT_EQ(image, page->image());
// Then check the size, and some pixels. Just check the corners. Note that
// assumptions about how subpixels are treated are being made here, meaning
// that if code changes cause the following expectations to fail, maybe it's
// the test that needs to be adjusted.
ASSERT_EQ(image.size(), gfx::Size(17, 17));
// Top left corner:
EXPECT_EQ(image.pixel_at(2, 2), 0xffffffU);
EXPECT_EQ(image.pixel_at(3, 3), 0x0000ffU);
// Top right corner:
EXPECT_EQ(image.pixel_at(13, 2), 0xffffffU);
EXPECT_EQ(image.pixel_at(12, 3), 0x0000ffU);
// Bottom right corner:
EXPECT_EQ(image.pixel_at(13, 13), 0xffffffU);
EXPECT_EQ(image.pixel_at(12, 12), 0x0000ffU);
// Bottom left corner:
EXPECT_EQ(image.pixel_at(2, 13), 0xffffffU);
EXPECT_EQ(image.pixel_at(3, 12), 0x0000ffU);
}
#endif // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize1) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize2) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123.1px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123.1px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize3) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123.9px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123.9px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, MediaQueryDefaultCSSPageMargins) {
// The default page size in these tests is US Letter (see MockPrinter). The
// default margin is 1/2 inch on each side, and this is taken into account for
// media query evaluation in this implementation, which is interoperable with
// others. The spec, on the other hand, says to match against the page *box*
// [1], not the page area [1]. I.e. margins shouldn't make any difference at
// all, according to the spec.
//
// [1] https://www.w3.org/TR/css-page-3/#page-model
LoadHTML(R"HTML(
<style>
@page {
/* The default margins are overridden here (to 0) as far as page area
size and layout are concerned, but that cannot affect media query
evaluation, as that might cause cyclic dependencies. So the 1/2 inch
default margins are still taken into account for media query
evaluation. */
margin: 0;
}
/* As explained above, this media query won't match, because of the
half-inch default margins. */
@media (width: 8.5in) and (height: 11in) {
div { break-before: page; }
}
</style>
First page
<div>Also first page</div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, MediaQueryNoCSSPageMargins) {
LoadHTML(R"HTML(
<style>
@page {
/* This has no effect on media query evaluation (it affects the page
area size and layout, though). Only the default margins can affect
media query evaluation. */
margin: 100px;
}
/* This media query will match, since the default margins are 0,
and the default page size is US-Letter. */
@media (width: 8.5in) and (height: 11in) {
div { break-before: page; }
}
</style>
First page
<div>Second page</div>
)HTML");
// Set the default margins to 0, and the page area size equal to the page box
// size.
mojom::PrintParams& params = printer()->Params();
params.margin_left = 0;
params.margin_top = 0;
params.content_size = params.page_size;
print_manager()->SetExpectedPagesCount(2);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, InputScale1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 2 shrinks this to 5 inches. Content that
// is 50 inches tall should therefore require 10 pages.
LoadHTML(R"HTML(
<style>
@page {
margin: 0.5in;
}
body {
margin: 0;
}
</style>
<div style="height:50in;"></div>
)HTML");
printer()->Params().scale_factor = 2;
print_manager()->SetExpectedPagesCount(10);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, InputScale2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 2 shrinks this to 5 inches. Content that
// is 45.5 inches tall should therefore require just a bit more than 9 pages,
// i.e. 10 pages.
LoadHTML(R"HTML(
<style>
@page {
margin: 0.5in;
}
body {
margin: 0;
}
</style>
<div style="height:45.5in;"></div>
)HTML");
printer()->Params().scale_factor = 2;
print_manager()->SetExpectedPagesCount(10);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, InputScaleAndAvoidOverflowScale1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in and horizontal margins to 2.25in leaves
// 4in by 10in for the page area. Setting the input scale factor to 2 shrinks
// this to 2in by 5in. There's a 3in wide block in the test. To make it fit
// without overflowing, Blink will increase the page area size by 3/2,
// i.e. 50% larger, so that the final page area for layout is 3 by 7.5
// inches. Content that is 75 inches tall should therefore require 10 pages.
LoadHTML(R"HTML(
<style>
@page {
margin: 0.5in 2.25in;
}
body {
margin: 0;
}
</style>
<div style="width:3in; height:75in;"></div>
)HTML");
printer()->Params().scale_factor = 2;
print_manager()->SetExpectedPagesCount(10);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, InputScaleAndAvoidOverflowScale2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in and horizontal margins to 2.25in leaves
// 4in by 10in for the page area. Setting the input scale factor to 2 shrinks
// this to 2in by 5in. There's a 3in wide block in the test. To make it fit
// without overflowing, Blink will increase the page area size by 3/2,
// i.e. 50% larger, so that the final page area for layout is 3 by 7.5
// inches. Content that is 68 inches tall should therefore require just a bit
// more than 9 pages, i.e. 10 pages.
LoadHTML(R"HTML(
<style>
@page {
margin: 0.5in 2.25in;
}
body {
margin: 0;
}
</style>
<div style="width:3in; height:68in;"></div>
)HTML");
printer()->Params().scale_factor = 2;
print_manager()->SetExpectedPagesCount(10);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest,
PrintMultiplePagesWithHeadersAndFooters) {
LoadHTML(kMultipageHTML);
printer()->Params().display_header_footer = true;
print_manager()->SetExpectedPagesCount(3);
OnPrintPages();
VerifyPagesPrinted(true);
}
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
TEST_F(MAYBE_PrintRenderFrameHelperTest, PrintWithIframe) {
// Document that populates an iframe.
static 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>');"
" frames['sub1'].document.close();"
"</script></body></html>";
printer()->set_should_generate_page_images(true);
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 =
web_view_->MainFrame()->ToWebLocalFrame()->FindFrameByName(
WebString::FromUTF8("sub1"));
ASSERT_TRUE(sub1_frame);
web_view_->SetFocusedFrame(sub1_frame);
ASSERT_NE(web_view_->FocusedFrame(), web_view_->MainFrame());
// Initiate printing.
OnPrintPages();
VerifyPagesPrinted(true);
// Verify output through MockPrinter.
const MockPrinter* mock_printer(printer());
ASSERT_EQ(1, mock_printer->GetPageCount());
const Image& image1(mock_printer->GetPrinterPage(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 // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
// These print preview tests do not work on Chrome OS yet.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
class PrintRenderFrameHelperPreviewTest
: public PrintRenderFrameHelperTestBase {
public:
PrintRenderFrameHelperPreviewTest() = default;
PrintRenderFrameHelperPreviewTest(const PrintRenderFrameHelperPreviewTest&) =
delete;
PrintRenderFrameHelperPreviewTest& operator=(
const PrintRenderFrameHelperPreviewTest&) = delete;
~PrintRenderFrameHelperPreviewTest() override = default;
void SetUp() override {
PrintRenderFrameHelperTestBase::SetUp();
BindToFakePrintPreviewUI();
CreatePrintSettingsDictionary();
}
protected:
void BindToFakePrintPreviewUI() {
PrintRenderFrameHelper* frame_helper = GetPrintRenderFrameHelper();
frame_helper->SetPrintPreviewUI(preview_ui()->BindReceiver());
}
void OnPrintPreview() {
PrintRenderFrameHelper* print_render_frame_helper =
GetPrintRenderFrameHelper();
print_render_frame_helper->InitiatePrintPreview(
#if BUILDFLAG(IS_CHROMEOS_ASH)
mojo::NullAssociatedRemote(),
#endif
/*has_selection=*/false);
print_render_frame_helper->PrintPreview(print_settings_.Clone());
preview_ui()->WaitUntilPreviewUpdate();
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
if (const mojom::DidPreviewDocumentParams* preview_params =
preview_ui()->did_preview_document_params()) {
const auto& region = preview_params->content->metafile_data_region;
ASSERT_TRUE(region.IsValid());
printer()->GeneratePageImages(region.Map());
}
#endif // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
}
void OnPrintPreviewRerender() {
preview_ui()->ResetPreviewStatus();
GetPrintRenderFrameHelper()->PrintPreview(print_settings_.Clone());
preview_ui()->WaitUntilPreviewUpdate();
}
// A function to set up the preview environment for `frame`. Done here to
// access private members of the test class.
void OnPrintPreviewForRenderFrame(WebLocalFrame* frame,
bool has_selection,
FakePrintPreviewUI* preview_ui) {
content::RenderFrame* render_frame =
content::RenderFrame::FromWebFrame(frame);
BindPrintManagerHost(render_frame);
PrintRenderFrameHelper* print_render_frame_helper =
GetPrintRenderFrameHelperForFrame(render_frame);
print_render_frame_helper->SetPrintPreviewUI(preview_ui->BindReceiver());
print_render_frame_helper->InitiatePrintPreview(
#if BUILDFLAG(IS_CHROMEOS_ASH)
mojo::NullAssociatedRemote(),
#endif
has_selection);
print_render_frame_helper->PrintPreview(print_settings().Clone());
preview_ui->WaitUntilPreviewUpdate();
}
void OnClosePrintPreviewDialog() {
GetPrintRenderFrameHelper()->OnPrintPreviewDialogClosed();
}
void OnPrintForSystemDialog() {
GetPrintRenderFrameHelper()->PrintForSystemDialog();
}
void VerifyPreviewRequest(bool expect_request) {
EXPECT_EQ(expect_request, print_manager()->IsSetupScriptedPrintPreview());
}
// 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(uint32_t expected_count) {
EXPECT_EQ(expected_count, preview_ui()->page_count());
}
void VerifyPrintPreviewCancelled(bool expect_cancel) {
EXPECT_EQ(expect_cancel, preview_ui()->PreviewCancelled());
}
void VerifyPrintPreviewFailed(bool expect_fail) {
EXPECT_EQ(expect_fail, preview_ui()->PreviewFailed());
}
void VerifyPrintPreviewGenerated(bool expect_generated) {
ASSERT_EQ(expect_generated, preview_ui()->IsMetafileReadyForPrinting());
if (preview_ui()->IsMetafileReadyForPrinting()) {
ASSERT_TRUE(preview_ui()->did_preview_document_params());
const auto& param = *preview_ui()->did_preview_document_params();
EXPECT_NE(0, param.document_cookie);
EXPECT_NE(0U, param.expected_pages_count);
auto mapped = param.content->metafile_data_region.Map();
ASSERT_TRUE(mapped.IsValid());
EXPECT_TRUE(LooksLikePdf(mapped.GetMemoryAsSpan<const uint8_t>()));
}
}
void VerifyPrintPreviewInvalidPrinterSettings(bool expect_invalid_settings) {
EXPECT_EQ(expect_invalid_settings, preview_ui()->InvalidPrinterSetting());
}
// `page_index` is 0-based.
void VerifyDidPreviewPage(bool expect_generated,
uint32_t page_index,
FakePrintPreviewUI* preview_ui) {
bool msg_found = false;
uint32_t data_size = 0;
for (const auto& preview : preview_ui->print_preview_pages()) {
if (preview.index == page_index) {
msg_found = true;
data_size = preview.content_data_size;
break;
}
}
EXPECT_EQ(expect_generated, msg_found)
<< "For page at index " << page_index;
if (expect_generated)
EXPECT_NE(0U, data_size) << "For page at index " << page_index;
}
void VerifyDidPreviewPage(bool expect_generated, uint32_t page_index) {
VerifyDidPreviewPage(expect_generated, page_index, preview_ui());
}
void VerifyDefaultPageLayout(
int expected_content_width,
int expected_content_height,
int expected_margin_top,
int expected_margin_bottom,
int expected_margin_left,
int expected_margin_right,
bool expected_all_pages_have_custom_size,
bool expected_all_pages_have_custom_orientation) {
const mojom::PageSizeMargins* page_layout = preview_ui()->page_layout();
ASSERT_TRUE(page_layout);
EXPECT_EQ(expected_content_width, std::round(page_layout->content_width));
EXPECT_EQ(expected_content_height, std::round(page_layout->content_height));
EXPECT_EQ(expected_margin_top, std::round(page_layout->margin_top));
EXPECT_EQ(expected_margin_bottom, std::round(page_layout->margin_bottom));
EXPECT_EQ(expected_margin_left, std::round(page_layout->margin_left));
EXPECT_EQ(expected_margin_right, std::round(page_layout->margin_right));
EXPECT_EQ(expected_all_pages_have_custom_size,
preview_ui()->all_pages_have_custom_size());
EXPECT_EQ(expected_all_pages_have_custom_orientation,
preview_ui()->all_pages_have_custom_orientation());
}
base::Value::Dict& print_settings() { return print_settings_; }
private:
void CreatePrintSettingsDictionary() {
print_settings_ =
base::Value::Dict()
.Set(kSettingLandscape, false)
.Set(kSettingCollate, false)
.Set(kSettingColor, static_cast<int>(mojom::ColorModel::kGray))
.Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kPdf))
.Set(kSettingDuplexMode,
static_cast<int>(mojom::DuplexMode::kSimplex))
.Set(kSettingCopies, 1)
.Set(kSettingDeviceName, "dummy")
.Set(kSettingDpiHorizontal, 72)
.Set(kSettingDpiVertical, 72)
.Set(kPreviewUIID, 4)
.Set(kSettingRasterizePdf, false)
.Set(kPreviewRequestID, 12345)
.Set(kSettingScaleFactor, 100)
.Set(kIsFirstRequest, true)
.Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kDefaultMargins))
.Set(kSettingPagesPerSheet, 1)
.Set(kSettingPreviewModifiable, true)
.Set(kSettingPreviewIsFromArc, false)
.Set(kSettingHeaderFooterEnabled, false)
.Set(kSettingShouldPrintBackgrounds, false)
.Set(kSettingShouldPrintSelectionOnly, false);
// Using a media size with realistic dimensions for a Letter paper.
auto media_size = base::Value::Dict()
.Set(kSettingMediaSizeWidthMicrons, 215900)
.Set(kSettingMediaSizeHeightMicrons, 279400)
.Set(kSettingsImageableAreaLeftMicrons, 12700)
.Set(kSettingsImageableAreaBottomMicrons, 0)
.Set(kSettingsImageableAreaRightMicrons, 209550)
.Set(kSettingsImageableAreaTopMicrons, 254000);
print_settings_.Set(kSettingMediaSize, std::move(media_size));
}
base::Value::Dict print_settings_;
};
TEST_F(PrintRenderFrameHelperPreviewTest, BlockScriptInitiatedPrinting) {
LoadHTML(kHelloWorldHTML);
print_manager()->SetPrintingEnabled(false);
PrintWithJavaScript();
VerifyPreviewRequest(false);
print_manager()->SetPrintingEnabled(true);
PrintWithJavaScript();
VerifyPreviewRequest(true);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintWithJavaScript) {
LoadHTML(kPrintOnUserAction);
gfx::Size new_size(200, 100);
Resize(new_size, false);
gfx::Rect bounds = GetElementBounds("print");
ClickMouseButton(bounds);
VerifyPreviewRequest(true);
OnClosePrintPreviewDialog();
}
// Tests that print preview work and sending and receiving messages through
// that channel all works.
TEST_F(PrintRenderFrameHelperPreviewTest, OnPrintPreview) {
LoadHTML(kHelloWorldHTML);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyDefaultPageLayout(548, 692, 72, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewWithSrcdocSelection) {
static const char kHTMLWithSrcdocChildFrame[] =
"<html><body>"
"<iframe name='srcdoc_frame' srcdoc='foo'></iframe>"
"</body></html>";
LoadHTML(kHTMLWithSrcdocChildFrame);
// Create selection in the child frame.
WebLocalFrame* srcdoc_frame =
GetMainFrame()->FindFrameByName("srcdoc_frame")->ToWebLocalFrame();
srcdoc_frame->ExecuteCommand("SelectAll");
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
// Verify that print preview succeeds.
// The subframe will need its own preview UI. Declare it here so it can be
// passed to `VerifyDidPreviewPage` after `OnPrintPreviewForRenderFrame`
// completes.
std::unique_ptr<FakePrintPreviewUI> subframe_preview_ui =
std::make_unique<FakePrintPreviewUI>();
OnPrintPreviewForRenderFrame(srcdoc_frame, /*has_selection=*/true,
subframe_preview_ui.get());
VerifyDidPreviewPage(true, 0, subframe_preview_ui.get());
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewHTMLWithPageMarginsCss) {
// A simple web page with print margins css.
static const char kHTMLWithPageMarginsCss[] =
"<html><head><style>"
"@media print {"
" @page {"
" margin: 3in 1in 2in 0.3in;"
" }"
"}"
"</style></head>"
"<body>Lorem Ipsum:"
"</body></html>";
LoadHTML(kHTMLWithPageMarginsCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(518, 432, 216, 144, 22, 72, false, false);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview ignores print media css when non-default
// margin is selected.
TEST_F(PrintRenderFrameHelperPreviewTest,
NonDefaultMarginsSelectedIgnorePrintCss) {
LoadHTML(kHTMLWithPageSizeCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kNoMargins));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(612, 792, 0, 0, 0, 0, true, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// 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(PrintRenderFrameHelperPreviewTest, PrintToPDFSelectedHonorPrintCss) {
LoadHTML(kHTMLWithPageSizeCss);
print_settings().Set(
kSettingMarginsType,
static_cast<int>(mojom::MarginType::kPrintableAreaMargins));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
// Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
// size.
VerifyDefaultPageLayout(234, 216, 72, 0, 36, 18, true, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PreviewLayoutTriggeredByResize) {
// A simple web page with print margins css.
static const char kHTMLWithPageCss[] =
"<!DOCTYPE html>"
"<style>"
"@media (min-width: 540px) {"
" #container {"
" width: 540px;"
" }"
"}"
".testlist {"
" list-style-type: none;"
"}"
"</style>"
"<div id='container'>"
" <ul class='testlist'>"
" <li>"
" <p>"
" 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
" ccccccccccccccccccccccccccccccccccccccc"
" ddddddddddddddddddddddddddddddddddddddd"
" eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
" fffffffffffffffffffffffffffffffffffffff"
" ggggggggggggggggggggggggggggggggggggggg"
" hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
" iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
" jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
" kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
" lllllllllllllllllllllllllllllllllllllll"
" mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm':"
" </p>"
" </li>"
" <li>"
" <p>"
" 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
" ccccccccccccccccccccccccccccccccccccccc"
" ddddddddddddddddddddddddddddddddddddddd"
" eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
" fffffffffffffffffffffffffffffffffffffff"
" ggggggggggggggggggggggggggggggggggggggg"
" hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
" iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
" jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
" kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
" lllllllllllllllllllllllllllllllllllllll"
" mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm'"
" </p>"
" </li>"
" <li>"
" <p>"
" 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
" ccccccccccccccccccccccccccccccccccccccc"
" ddddddddddddddddddddddddddddddddddddddd"
" eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
" fffffffffffffffffffffffffffffffffffffff"
" ggggggggggggggggggggggggggggggggggggggg"
" hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
" iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
" jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
" kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
" lllllllllllllllllllllllllllllllllllllll"
" mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm'"
" </p>"
" </li>"
" <li>"
" <p>"
" 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
" ccccccccccccccccccccccccccccccccccccccc"
" ddddddddddddddddddddddddddddddddddddddd"
" eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
" fffffffffffffffffffffffffffffffffffffff"
" ggggggggggggggggggggggggggggggggggggggg"
" hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
" iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
" jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
" kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
" lllllllllllllllllllllllllllllllllllllll"
" mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm'"
" </p>"
" </li>"
" <li>"
" <p>"
" 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
" ccccccccccccccccccccccccccccccccccccccc"
" ddddddddddddddddddddddddddddddddddddddd"
" eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
" fffffffffffffffffffffffffffffffffffffff"
" ggggggggggggggggggggggggggggggggggggggg"
" hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
" iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
" jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
" kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"
" lllllllllllllllllllllllllllllllllllllll"
" mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm'"
" </p>"
" </li>"
" </ul>"
"</div>";
LoadHTML(kHTMLWithPageCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyDidPreviewPage(true, 1);
VerifyPreviewPageCount(2);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// 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(PrintRenderFrameHelperPreviewTest,
PrintToPDFSelectedHonorPageMarginsCss) {
// A simple web page with print margins css.
static 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);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
// Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
// size.
VerifyDefaultPageLayout(914, 648, 216, 144, 22, 72, true, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview workflow center the html page contents to
// fit the page size.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewCenterToFitPage) {
LoadHTML(kHTMLWithPageSizeCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(224, 188, 324, 280, 198, 190, true, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview workflow scale the html page contents to
// fit the page size.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewShrinkToFitPage) {
// A simple web page with print margins css.
static const char kHTMLWithPageCss[] =
"<html><head><style>"
"@media print {"
" @page {"
" size: 15in 17in;"
" }"
"}"
"</style></head>"
"<body>Lorem Ipsum:"
"</body></html>";
LoadHTML(kHTMLWithPageCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 637, 90, 65, 20, 16, true, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview workflow scale the html page contents to
// fit the page size, and that orientation implied by specified CSS page size is
// honored, even though the size itself is to be ignored.
TEST_F(PrintRenderFrameHelperPreviewTest, ShrinkToFitPageMatchOrientation) {
LoadHTML(R"HTML(
<style>
@page { size: 17in 15in; }
</style>
:-D
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
base::Value::Dict custom_margins;
custom_margins.Set(kSettingMarginTop, 10);
custom_margins.Set(kSettingMarginRight, 20);
custom_margins.Set(kSettingMarginBottom, 30);
custom_margins.Set(kSettingMarginLeft, 40);
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kCustomMargins));
print_settings().Set(kSettingMarginsCustom, std::move(custom_margins));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(732, 572, 10, 30, 40, 20, true, true);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview workflow scale the html page contents to
// fit the page size, and that orientation implied by specified CSS page size is
// honored.
TEST_F(PrintRenderFrameHelperPreviewTest,
ShrinkToFitPageMatchOrientationCssMargins) {
LoadHTML(R"HTML(
<style>
@page {
size: 20in 17in;
margin: 1in 2in 3in 4in;
}
</style>
:-D
)HTML");
// The default page size is 8.5 by 11 inches. The @page descriptor wants it in
// landscape mode, so 11 by 8.5 inches, then. The content should be scaled to
// fit on the page. The requested page size is 20 by 17 inches. Figure out
// which axis needs the most scaling. 20/11 < 17/8.5. 17/8.5 is 2. The content
// needs to be scaled down by a factor of 2. To retain the aspect ratio of the
// paper size, additional horizontal margins will be inserted, so that the
// page width before scaling becomes 22in (11*2). The requested page size is
// 20in, so add an additional 1in to the left and the right margins. This
// means that the result would be the same as if this were in the CSS:
//
// @page {
// size: 22in 17in;
// margin: 1in 3in 3in 5in;
// }
//
// Then scale everything down by a factor of 2.
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(504, 468, 36, 108, 180, 108, true, true);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsAndInputScaleToPdf1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 200% shrinks this to 5 inches. Content
// that is 50 inches tall should therefore require 10 pages.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; }
body { margin:0; }
</style>
<div style="height:50in;"></div>
)HTML");
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false, false);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsAndInputScaleToPdf2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 200% shrinks this to 5 inches. Content
// that is 45.5 inches tall should therefore require just a bit more than 9
// pages, i.e. 10 pages.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; }
body { margin:0; }
</style>
<div style="height:45.5in;"></div>
)HTML");
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false, false);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsAndInputScaleToPrinter1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 200% shrinks this to 5 inches. Content
// that is 50 inches tall should therefore require 10 pages.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; }
body { margin:0; }
</style>
<div style="height:50in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false, false);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsAndInputScaleToPrinter2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting vertical margins to 0.5in results in a page area of 10 inches.
// Setting the input scale factor to 200% shrinks this to 5 inches. Content
// that is 45.5 inches tall should therefore require just a bit more than 9
// pages, i.e. 10 pages.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; }
body { margin:0; }
</style>
<div style="height:45.5in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false, false);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsSizeAndInputScaleToPrinter1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page width to 34 inches and vertical margins to 1 inch results
// in a page area of 32 inches. Setting the input scale factor to 200% shrinks
// this to 16 inches. Content that is 160 inches tall should therefore require
// 10 pages. Furthermore, setting the page width to 34 inches and having to
// fit this to the actual "paper" means that everything needs to be scaled
// down by 34/8.5 = 4. This also applies to the final margins. Horizontal
// margins will therefore become 1/4 inch. Being in portrait mode, the actual
// "paper" height is larger than the width, although the CSS-specified page
// size has the same height and width. In order to resolve the
// over-constrained situation, this means that vertical margins will be
// adjusted to center the page area on "paper".
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:34in; }
body { margin:0; }
</style>
<div style="height:160in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 576, 108, 108, 18, 18, true, true);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, MarginsSizeAndInputScaleToPrinter2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page width to 34 inches and vertical margins to 1 inch results
// in a page area of 32 inches. Setting the input scale factor to 200% shrinks
// this to 16 inches. Content that is 145 inches tall should therefore require
// just a bit more than 9 pages, i.e. 10 pages. Furthermore, setting the page
// width to 34 inches and having to fit this to the actual "paper" means that
// everything needs to be scaled down by 34/8.5 = 4. This also applies to the
// final margins. Horizontal margins will therefore become 1/4 inch. Being in
// portrait mode, the actual "paper" height is larger than the width, although
// the CSS-specified page size has the same height and width. In order to
// resolve the over-constrained situation, this means that vertical margins
// will be adjusted to center the page area on "paper".
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:34in; }
body { margin:0; }
</style>
<div style="height:145in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 576, 108, 108, 18, 18, true, true);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter1) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page width to 34 inches and vertical margins to 1 inch results
// in a page area of 32 inches. Setting the input scale factor to 200% shrinks
// this to 16 inches. There's a 48in wide block in the test. To make it fit
// without overflowing, Blink will increase the page area size by 3/2 (48/32),
// i.e. 50% larger, so that the final page area for layout is 24 by 24 inches.
// Content that is 240 inches tall should therefore require 10
// pages. Furthermore, setting the page width to 34 inches and having to fit
// this to the actual "paper" means that everything needs to be scaled down by
// 34/8.5 = 4. This also applies to the final margins. Horizontal margins will
// therefore become 1/4 inch. Being in portrait mode, the actual "paper"
// height is larger than the width, although the CSS-specified page size has
// the same height and width. In order to resolve the over-constrained
// situation, this means that vertical margins will be adjusted to center the
// page area on "paper".
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:34in; }
body { margin:0; }
</style>
<div style="width:48in; height:240in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 576, 108, 108, 18, 18, true, true);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter2) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page width to 34 inches and vertical margins to 1 inch results
// in a page area of 32 inches. Setting the input scale factor to 200% shrinks
// this to 16 inches. There's a 48in wide block in the test. To make it fit
// without overflowing, Blink will increase the page area size by 3/2 (48/32),
// i.e. 50% larger, so that the final page area for layout is 24 by 24 inches.
// Content that is 217 inches tall should therefore require just a bit more
// than 9 pages, i.e. 10 pages. Furthermore, setting the page width to 34
// inches and having to fit this to the actual "paper" means that everything
// needs to be scaled down by 34/8.5 = 4. This also applies to the final
// margins. Horizontal margins will therefore become 1/4 inch. Being in
// portrait mode, the actual "paper" height is larger than the width, although
// the CSS-specified page size has the same height and width. In order to
// resolve the over-constrained situation, this means that vertical margins
// will be adjusted to center the page area on "paper".
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:34in; }
body { margin:0; }
</style>
<div style="width:48in; height:217in;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 576, 108, 108, 18, 18, true, true);
VerifyPreviewPageCount(10);
OnClosePrintPreviewDialog();
}
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter3) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page size to 3 inches and margins to 0.5 inches results in a
// page area of 2 by 2 inches. Setting the input scale factor to 200% shrinks
// this to 1 inch. There's a 1.5in wide block in the test. To make it fit
// without overflowing, Blink will increase the page area size by 3/2 (1.5/1),
// i.e. 50% larger, so that the final page area for layout is 1.5 by 1.5
// inches. Content that is 5.25 inches tall should therefore require 3 and a
// half pages (1.5 * 3.5 = 5.25). The specified page size is smaller than the
// paper (8.5x11 inches), and should be centered on paper, meaning that the
// margins will be changed so that the sum of the margins and the page size
// will be equal to the paper size.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; size:3in; }
body { margin:0; }
</style>
<div style="width:1.5in; height:5.25in; background:#0000ff;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
print_settings().Set(kSettingShouldPrintBackgrounds, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(144, 144, 324, 324, 234, 234, true, true);
VerifyPreviewPageCount(4);
// Look for the #0000ff background on all the pages.
// First page:
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image* image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(233, 323), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(234, 324), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(377, 467), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(378, 468), 0xffffffU); // white outside
// Second page:
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(233, 323), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(234, 324), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(377, 467), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(378, 468), 0xffffffU); // white outside
// Third page:
page = printer()->GetPrinterPage(2);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(233, 323), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(234, 324), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(377, 467), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(378, 468), 0xffffffU); // white outside
// Fourth and last page:
page = printer()->GetPrinterPage(3);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(233, 323), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(234, 324), 0x0000ffU); // blue inside
// Bottom right corner of the DIV (which occupies half of the last page).
EXPECT_EQ(image->pixel_at(377, 395), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(378, 396), 0xffffffU); // white outside
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter4) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page size to 5 by 3 inches and margins to 0.5 inches results in
// a page area of 4 by 2 inches. Setting the input scale factor to 200%
// shrinks this to 2 by 1 inches. There's a 3in wide block in the test. To
// make it fit without overflowing, Blink will increase the page area size by
// 3/2, i.e. 50% larger, so that the final page area for layout is 3 by 1.5
// inches. Content that is 2.25 inches tall should therefore require one and a
// half page (1.5 * 1.5 = 2.25). The specified page size is smaller than the
// paper (8.5x11 inches), and should be centered on paper, meaning that the
// margins will be changed so that the sum of the margins and the page size
// will be equal to the paper size. Additionally, the orientation is
// landscape.
LoadHTML(R"HTML(
<style>
@page { margin:0.5in; size:5in 3in; }
body { margin:0; }
</style>
<div style="width:3in; height:2.25in; background:#0000ff;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
print_settings().Set(kSettingShouldPrintBackgrounds, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(288, 144, 234, 234, 252, 252, true, true);
VerifyPreviewPageCount(2);
// Look for the #0000ff background on all the pages.
// First page:
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image* image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(792, 612));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(251, 233), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(252, 234), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(539, 377), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(540, 378), 0xffffffU); // white outside
// Second page:
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(792, 612));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(251, 233), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(252, 234), 0x0000ffU); // blue inside
// Bottom right corner of the DIV (which occupies half of the last page).
EXPECT_EQ(image->pixel_at(539, 305), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(540, 306), 0xffffffU); // white outside
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter5) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page size to 34 inches and margins to 1 inch results in a page
// area of 32 inches. Setting the input scale factor to 200% shrinks this to
// 16 inches. There's a 24in wide block in the test. To make it fit without
// overflowing, Blink will increase the page area size by 3/2 (24/16),
// i.e. 50% larger, so that the final page area for layout is 24 by 24 inches.
// Content that is 36 inches tall should therefore require one and a half page
// (1.5 * 1.5 = 2.25). The specified page size is larger than the paper
// (8.5x11 inches), and needs to be zoomed down to fit. The zoom factor will
// be 0.25. 8.5 / 34 (short edges) = 0.25, which is less than 11 / 34 (long
// edges). Margins are also adjusted accordingly, since it's essentially the
// entire page box that's scaled down. The result should be centered on paper.
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:34in; }
body { margin:0; }
</style>
<div style="width:24in; height:36in; background:#0000ff;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
print_settings().Set(kSettingShouldPrintBackgrounds, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(576, 576, 108, 108, 18, 18, true, true);
VerifyPreviewPageCount(2);
// Look for the #0000ff background on the first and last pages.
// First page:
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image* image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(17, 107), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(18, 108), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(557, 683), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(558, 684), 0xffffffU); // white outside
// Second page:
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(612, 792));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(17, 107), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(18, 108), 0x0000ffU); // blue inside
// Bottom right corner of the DIV (which occupies half of the last page).
EXPECT_EQ(image->pixel_at(557, 395), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(558, 396), 0xffffffU); // white outside
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
MarginsSizeAndInputScaleAndAvoidOverflowScaleToPrinter6) {
// The default page size in these tests is US Letter - 8.5 by 11 inches.
// Setting the page size to 33 by 18 inches and margins to 1 inch results in a
// page area of 31 by 16 inches. Setting the input scale factor to 200%
// shrinks this to 15.5 by 8 inches. There's a 23.25in wide block in the
// test. To make it fit without overflowing, Blink will increase the page area
// size by 3/2 (23.25/15.5), i.e. 50% larger, so that the final page area for
// layout is 23.25 by 12 inches. Content that is 18 inches tall should
// therefore require one and a half page (12 * 1.5 = 18). The specified page
// size is larger than the paper (8.5x11 inches), and needs to be zoomed down
// to fit. The zoom factor will be 1/3. 11 / 33 (long edges) = 1/3, which is
// less than 8.5 / 18 (short edges). Margins are also adjusted accordingly,
// since it's essentially the entire page box that's scaled down.
// Additionally, the orientation is landscape. The result should be centered
// on paper.
LoadHTML(R"HTML(
<style>
@page { margin:1in; size:33in 18in; }
body { margin:0; }
</style>
<div style="width:23.25in; height:18in; background:#0000ff;"></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingScaleFactor, 200);
print_settings().Set(kSettingShouldPrintBackgrounds, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(744, 384, 114, 114, 24, 24, true, true);
VerifyPreviewPageCount(2);
// Look for the #0000ff background on the first and last pages.
// First page:
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image* image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(792, 612));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(23, 113), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(24, 114), 0x0000ffU); // blue inside
// Bottom right page content area corner.
EXPECT_EQ(image->pixel_at(767, 497), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(768, 498), 0xffffffU); // white outside
// Second page:
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
image = &page->image();
ASSERT_EQ(image->size(), gfx::Size(792, 612));
// Top left page content area corner.
EXPECT_EQ(image->pixel_at(23, 113), 0xffffffU); // white outside
EXPECT_EQ(image->pixel_at(24, 114), 0x0000ffU); // blue inside
// Bottom right corner of the DIV (which occupies half of the last page).
EXPECT_EQ(image->pixel_at(767, 305), 0x0000ffU); // blue inside
EXPECT_EQ(image->pixel_at(768, 306), 0xffffffU); // white outside
OnClosePrintPreviewDialog();
}
#endif // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
// Test to verify that print preview workflow honor the orientation settings
// specified in css.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewHonorsOrientationCss) {
LoadHTML(kHTMLWithLandscapePageCss);
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kNoMargins));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(792, 612, 0, 0, 0, 0, false, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that print preview workflow honors the orientation settings
// specified in css when PRINT_TO_PDF is selected.
TEST_F(PrintRenderFrameHelperPreviewTest,
PrintToPDFSelectedHonorOrientationCss) {
LoadHTML(kHTMLWithLandscapePageCss);
base::Value::Dict custom_margins;
custom_margins.Set(kSettingMarginTop, 21);
custom_margins.Set(kSettingMarginBottom, 23);
custom_margins.Set(kSettingMarginLeft, 21);
custom_margins.Set(kSettingMarginRight, 23);
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kCustomMargins));
print_settings().Set(kSettingMarginsCustom, std::move(custom_margins));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDefaultPageLayout(748, 568, 21, 23, 21, 23, false, true);
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewForMultiplePages) {
LoadHTML(kMultipageHTML);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyDidPreviewPage(true, 1);
VerifyDidPreviewPage(true, 2);
VerifyPreviewPageCount(3);
VerifyDefaultPageLayout(548, 692, 72, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
PrintPreviewForMultiplePagesWithHeadersAndFooters) {
LoadHTML(kMultipageHTML);
print_settings().Set(kSettingHeaderFooterEnabled, true);
print_settings().Set(kSettingHeaderFooterTitle, "The Chromiums");
print_settings().Set(kSettingHeaderFooterURL, "https://chromium.org");
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyDidPreviewPage(true, 1);
VerifyDidPreviewPage(true, 2);
VerifyPreviewPageCount(3);
VerifyDefaultPageLayout(548, 678, 86, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewForSelectedPages) {
LoadHTML(kMultipageHTML);
// 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::Value::Dict page_range;
page_range.Set(kSettingPageRangeFrom, base::Value(2));
page_range.Set(kSettingPageRangeTo, base::Value(3));
base::Value::List page_range_array;
page_range_array.Append(std::move(page_range));
print_settings().Set(kSettingPageRange, std::move(page_range_array));
OnPrintPreview();
// The expected page count below is 3 because the total number of pages in the
// document, without the page range, is 3. Since only 2 pages have been
// generated, the print_preview_pages_remaining() result is 1.
// TODO(thestig): Fix this on the browser side to accept the number of actual
// pages generated instead, or to take both page counts.
EXPECT_EQ(1u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(false, 0);
VerifyDidPreviewPage(true, 1);
VerifyDidPreviewPage(true, 2);
VerifyPreviewPageCount(3);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewInvalidPageRange) {
LoadHTML(kHelloWorldHTML);
// Request a page beyond the end of document and assure we get the entire
// document back.
base::Value::Dict page_range;
page_range.Set(kSettingPageRangeFrom, 2);
page_range.Set(kSettingPageRangeTo, 2);
base::Value::List page_range_array;
page_range_array.Append(std::move(page_range));
print_settings().Set(kSettingPageRange, std::move(page_range_array));
OnPrintPreview();
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
OnClosePrintPreviewDialog();
}
// Test to verify that preview generated only for one page.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewForSelectedText) {
LoadHTML(kMultipageHTML);
GetMainFrame()->SelectRange(blink::WebRange(1, 3),
blink::WebLocalFrame::kHideSelectionHandle,
blink::mojom::SelectionMenuBehavior::kHide,
blink::WebLocalFrame::kSelectionSetFocus);
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Test to verify that preview generated only for two pages.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewForSelectedText2) {
LoadHTML(kMultipageHTML);
GetMainFrame()->SelectRange(blink::WebRange(1, 8),
blink::WebLocalFrame::kHideSelectionHandle,
blink::mojom::SelectionMenuBehavior::kHide,
blink::WebLocalFrame::kSelectionSetFocus);
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(2);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewForManyLinesOfText) {
LoadHTML(kHTMLWithManyLinesOfText);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
PrintPreviewForManyLinesOfTextWithScaling) {
LoadHTML(kHTMLWithManyLinesOfText);
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
constexpr int kExpectedPageCount = 3;
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
for (int i = 0; i < kExpectedPageCount; ++i)
VerifyDidPreviewPage(true, i);
VerifyPreviewPageCount(kExpectedPageCount);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
PrintPreviewForManyLinesOfTextWithTextSelection) {
LoadHTML(kHTMLWithManyLinesOfText);
GetMainFrame()->ExecuteCommand("SelectAll");
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
PrintPreviewForManyLinesOfTextWithTextSelectionAndScaling) {
LoadHTML(kHTMLWithManyLinesOfText);
GetMainFrame()->ExecuteCommand("SelectAll");
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreview();
constexpr int kExpectedPageCount = 3;
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
for (int i = 0; i < kExpectedPageCount; ++i)
VerifyDidPreviewPage(true, i);
VerifyPreviewPageCount(kExpectedPageCount);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
TEST_F(PrintRenderFrameHelperPreviewTest, TextSelectionPageRules) {
LoadHTML(R"HTML(
<style>
@page :first {
size: 300px;
page-orientation: rotate-right;
}
@page {
size: 400px;
page-orientation: rotate-left;
}
</style>
<div style="break-after:page;">page 1</div>
<div style="break-after:page;">page 2</div>
)HTML");
GetMainFrame()->ExecuteCommand("SelectAll");
print_settings().Set(kSettingShouldPrintSelectionOnly, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
VerifyPreviewPageCount(2);
// The @page rules should be ignored when printing the selection. The default
// page size (US Letter in this case) should be used.
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
EXPECT_EQ(page->image().size(), gfx::Size(612, 792));
page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
EXPECT_EQ(page->image().size(), gfx::Size(612, 792));
OnClosePrintPreviewDialog();
}
#endif // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
// Tests that cancelling print preview works.
TEST_F(PrintRenderFrameHelperPreviewTest, PrintPreviewCancel) {
LoadHTML(kLongPageHTML);
const uint32_t kCancelPage = 3;
preview_ui()->set_print_preview_cancel_page_number(kCancelPage);
OnPrintPreview();
EXPECT_EQ(kCancelPage, preview_ui()->print_preview_pages_remaining());
VerifyPrintPreviewCancelled(true);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(false);
VerifyPagesPrinted(false);
OnClosePrintPreviewDialog();
}
// Tests that when default printer has invalid printer settings, print preview
// receives error message.
TEST_F(PrintRenderFrameHelperPreviewTest,
OnPrintPreviewUsingInvalidPrinterSettings) {
LoadHTML(kPrintPreviewHTML);
// Set mock printer to provide invalid settings.
// A missing color entry is invalid.
print_settings().Remove(kSettingColor);
OnPrintPreview();
// We should have received invalid printer settings from |printer_|.
VerifyPrintPreviewInvalidPrinterSettings(true);
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
// It should receive the invalid printer settings message only.
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(false);
OnClosePrintPreviewDialog();
}
// Tests that when the selected printer has an invalid media size, print preview
// receives error message.
TEST_F(PrintRenderFrameHelperPreviewTest, OnPrintPreviewUsingInvalidMediaSize) {
LoadHTML(kPrintPreviewHTML);
print_settings().Set(kSettingMediaSize, base::Value::Dict());
OnPrintPreview();
VerifyPrintPreviewInvalidPrinterSettings(true);
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
// It should receive the invalid printer settings message only.
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(false);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, BasicBeforePrintAfterPrint) {
LoadHTML(kBeforeAfterPrintHtml);
ExpectNoBeforeNoAfterPrintEvent();
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyDefaultPageLayout(548, 692, 72, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
ExpectOneBeforeNoAfterPrintEvent();
OnClosePrintPreviewDialog();
ExpectOneBeforeOneAfterPrintEvent();
}
// Regression test for https://crbug.com/912966
TEST_F(PrintRenderFrameHelperPreviewTest, WindowPrintBeforePrintAfterPrint) {
LoadHTML(kBeforeAfterPrintHtml);
gfx::Size new_size(200, 100);
Resize(new_size, false);
ExpectNoBeforeNoAfterPrintEvent();
gfx::Rect bounds = GetElementBounds("print");
ClickMouseButton(bounds);
VerifyPreviewRequest(true);
ExpectOneBeforeNoAfterPrintEvent();
OnClosePrintPreviewDialog();
ExpectOneBeforeOneAfterPrintEvent();
}
TEST_F(PrintRenderFrameHelperPreviewTest, OnlySomePagesWithCustomSize) {
// A specified page size will set both size and orientation (not just for any
// given fixed size, but also for well-known page sizes, such as B5). In this
// test, however, only the first page will match the @page rule, whereas the
// size and orientation of the second page may be freely controlled by UI
// settings.
LoadHTML(R"HTML(
<style>
@page custom { size:B5; }
</style>
<div style="page:custom;">Custom page</div>
Default page
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
EXPECT_FALSE(preview_ui()->all_pages_have_custom_size());
EXPECT_FALSE(preview_ui()->all_pages_have_custom_orientation());
VerifyPreviewPageCount(2);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, SingleNamedPageWithCustomSize) {
// There's only one page, and that page is named, and it matches the @page
// rule, which specifies a page size. There are no pages that can be
// controlled by UI options, so the options should be hidden.
LoadHTML(R"HTML(
<style>
@page custom { size:B5; }
</style>
<div style="page:custom;">Custom page</div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
EXPECT_TRUE(preview_ui()->all_pages_have_custom_size());
EXPECT_TRUE(preview_ui()->all_pages_have_custom_orientation());
VerifyPreviewPageCount(1);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, OnlySomePagesWithCustomOrientation) {
LoadHTML(R"HTML(
<style>
@page custom { size:portrait; }
</style>
<div style="page:custom;">Custom page</div>
Default page
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
EXPECT_FALSE(preview_ui()->all_pages_have_custom_size());
EXPECT_FALSE(preview_ui()->all_pages_have_custom_orientation());
VerifyPreviewPageCount(2);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest,
SingleNamedPageWithCustomOrientation) {
LoadHTML(R"HTML(
<style>
@page custom { size:portrait; }
</style>
<div style="page:custom;">Custom page</div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
EXPECT_FALSE(preview_ui()->all_pages_have_custom_size());
EXPECT_TRUE(preview_ui()->all_pages_have_custom_orientation());
VerifyPreviewPageCount(1);
OnClosePrintPreviewDialog();
}
TEST_F(PrintRenderFrameHelperPreviewTest, PrintForSystemDialog) {
LoadHTML(kHelloWorldHTML);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
VerifyPreviewPageCount(1);
// No need to call OnClosePrintPreviewDialog(), as OnPrintForSystemDialog()
// takes care of the Print Preview to system print dialog transition.
OnPrintForSystemDialog();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(true);
}
#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
TEST_F(PrintRenderFrameHelperPreviewTest, IgnorePageSizeAndMargin) {
LoadHTML(R"HTML(
<style>
@page {
size: 2000px;
margin: 100px;
}
html, body { height:100%; }
body {
margin: 0;
}
.flex {
display: flex;
height: 100%;
justify-content: flex-end;
align-items: flex-end;
}
.flex > div {
width: 1pt;
height: 1pt;
background: #00ff00;
}
</style>
<div class="flex"><div></div></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingShouldPrintBackgrounds, true);
base::Value::Dict custom_margins;
custom_margins.Set(kSettingMarginTop, 12);
custom_margins.Set(kSettingMarginRight, 6);
custom_margins.Set(kSettingMarginBottom, 12);
custom_margins.Set(kSettingMarginLeft, 6);
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kCustomMargins));
print_settings().Set(kSettingMarginsCustom, std::move(custom_margins));
printer()->set_should_generate_page_images(true);
OnPrintPreview();
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image& image(page->image());
// The specified page size is much larger than 8.5x11 inches, but it should be
// ignored, because CSS page size and margins are to be ignored, according to
// the settings above.
ASSERT_EQ(image.size(), gfx::Size(612, 792));
// Find the green point in the bottom right corner of the page.
EXPECT_EQ(image.pixel_at(605, 779), 0x00ff00U);
}
TEST_F(PrintRenderFrameHelperPreviewTest, LandscapeIgnorePageSizeAndMargin) {
LoadHTML(R"HTML(
<style>
@page {
size: landscape;
margin: 100px;
}
html, body { height:100%; }
body {
margin: 0;
}
.flex {
display: flex;
height: 100%;
justify-content: flex-end;
align-items: flex-end;
}
.flex > div {
width: 1pt;
height: 1pt;
background: #00ff00;
}
</style>
<div class="flex"><div></div></div>
)HTML");
print_settings().Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
print_settings().Set(kSettingShouldPrintBackgrounds, true);
base::Value::Dict custom_margins;
// TODO(crbug.com/40280219): Would be neat to test with different vertical and
// horizontal margins here.
custom_margins.Set(kSettingMarginTop, 12);
custom_margins.Set(kSettingMarginRight, 12);
custom_margins.Set(kSettingMarginBottom, 12);
custom_margins.Set(kSettingMarginLeft, 12);
print_settings().Set(kSettingMarginsType,
static_cast<int>(mojom::MarginType::kCustomMargins));
print_settings().Set(kSettingMarginsCustom, std::move(custom_margins));
printer()->set_should_generate_page_images(true);
OnPrintPreview();
const MockPrinterPage* page = printer()->GetPrinterPage(0);
ASSERT_TRUE(page);
const printing::Image& image(page->image());
// Specified page size should be ignored, according to the settings
// above. Page orientation (landscape vs portrait) should still be honored,
// though.
ASSERT_EQ(image.size(), gfx::Size(792, 612));
// Find the green point in the bottom right corner of the page.
EXPECT_EQ(image.pixel_at(779, 599), 0x00ff00U);
}
TEST_F(PrintRenderFrameHelperPreviewTest,
NonDefaultFirstPageSizeDefaultSecond) {
LoadHTML(R"HTML(
<style>
@page { margin:0; }
@page larger { size:15in; }
html, body { margin:0; height:100%; }
div { width:100%; height:100%; }
* { box-sizing:border-box; }
</style>
<div style="page:larger;"></div>
<div style="break-before:page; border:2pt solid #00ff00;"></div>
)HTML");
print_settings().Set(kSettingShouldPrintBackgrounds, true);
printer()->set_should_generate_page_images(true);
OnPrintPreview();
const MockPrinterPage* page = printer()->GetPrinterPage(1);
ASSERT_TRUE(page);
const printing::Image& image(page->image());
ASSERT_EQ(image.size(), gfx::Size(612, 792));
// Find the border in the bottom right corner of the page.
EXPECT_EQ(image.pixel_at(611, 788), 0x00ff00U);
EXPECT_EQ(image.pixel_at(611, 789), 0x00ff00U);
EXPECT_EQ(image.pixel_at(611, 790), 0x00ff00U);
EXPECT_EQ(image.pixel_at(611, 791), 0x00ff00U);
EXPECT_EQ(image.pixel_at(610, 791), 0x00ff00U);
EXPECT_EQ(image.pixel_at(609, 791), 0x00ff00U);
EXPECT_EQ(image.pixel_at(608, 791), 0x00ff00U);
}
#endif // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
class PrintRenderFrameHelperTaggedPreviewTest
: public PrintRenderFrameHelperPreviewTest,
public testing::WithParamInterface<bool> {
public:
PrintRenderFrameHelperTaggedPreviewTest() = default;
PrintRenderFrameHelperTaggedPreviewTest(
const PrintRenderFrameHelperTaggedPreviewTest&) = delete;
PrintRenderFrameHelperTaggedPreviewTest& operator=(
const PrintRenderFrameHelperTaggedPreviewTest&) = delete;
~PrintRenderFrameHelperTaggedPreviewTest() override = default;
// content::RenderViewTest:
content::ContentRendererClient* CreateContentRendererClient() override {
return new PrintTestContentRendererClient(GenerateTaggedPDFs());
}
bool GenerateTaggedPDFs() const { return GetParam(); }
bool ExpectsSetAccessibilityTreeCalls() const { return GenerateTaggedPDFs(); }
};
TEST_P(PrintRenderFrameHelperTaggedPreviewTest,
PrintPreviewRerenderGeneratesTaggedPDF) {
LoadHTML(kHelloWorldHTML);
OnPrintPreview();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyDefaultPageLayout(548, 692, 72, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
int expected_accessibility_tree_set_count =
ExpectsSetAccessibilityTreeCalls() ? 1 : 0;
EXPECT_EQ(expected_accessibility_tree_set_count,
print_manager()->accessibility_tree_set_count());
print_settings().Set(kSettingScaleFactor, 200);
OnPrintPreviewRerender();
EXPECT_EQ(0u, preview_ui()->print_preview_pages_remaining());
VerifyDidPreviewPage(true, 0);
VerifyPreviewPageCount(1);
VerifyDefaultPageLayout(548, 692, 72, 28, 36, 28, false, false);
VerifyPrintPreviewCancelled(false);
VerifyPrintPreviewFailed(false);
VerifyPrintPreviewGenerated(true);
VerifyPagesPrinted(false);
expected_accessibility_tree_set_count =
ExpectsSetAccessibilityTreeCalls() ? 2 : 0;
EXPECT_EQ(expected_accessibility_tree_set_count,
print_manager()->accessibility_tree_set_count());
}
INSTANTIATE_TEST_SUITE_P(All,
PrintRenderFrameHelperTaggedPreviewTest,
testing::Bool());
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace printing