1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/pdf/pdf_browsertest_base.h"
10 #include "base/command_line.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "third_party/skia/include/core/SkBitmap.h"
24 #include "ui/gfx/codec/png_codec.h"
25 #include "ui/gfx/screen.h"
28 #include "content/public/common/content_switches.h"
31 #if defined(OS_CHROMEOS)
32 #include "ui/compositor/compositor_switches.h"
37 // Include things like browser frame and scrollbar and make sure we're bigger
38 // than the test pdf document.
39 const int kBrowserWidth
= 1000;
40 const int kBrowserHeight
= 600;
44 PDFBrowserTest::PDFBrowserTest()
45 : snapshot_different_(true),
46 next_dummy_search_value_(0),
47 load_stop_notification_count_(0) {
48 base::FilePath src_dir
;
49 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT
, &src_dir
));
50 pdf_test_server_
.ServeFilesFromDirectory(src_dir
.AppendASCII(
51 "chrome/test/data/pdf_private"));
54 PDFBrowserTest::~PDFBrowserTest() {
57 void PDFBrowserTest::Load() {
58 // Make sure to set the window size before rendering, as otherwise rendering
59 // to a smaller window and then expanding leads to slight anti-aliasing
60 // differences of the text and the pixel comparison fails.
61 gfx::Rect
bounds(gfx::Rect(0, 0, kBrowserWidth
, kBrowserHeight
));
62 gfx::Rect screen_bounds
=
63 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().bounds();
64 ASSERT_GT(screen_bounds
.width(), kBrowserWidth
);
65 ASSERT_GT(screen_bounds
.height(), kBrowserHeight
);
66 browser()->window()->SetBounds(bounds
);
68 GURL
url(ui_test_utils::GetTestUrl(
69 base::FilePath(FILE_PATH_LITERAL("pdf_private")),
70 base::FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
71 ui_test_utils::NavigateToURL(browser(), url
);
74 void PDFBrowserTest::WaitForResponse() {
75 // Even if the plugin has loaded the data or scrolled, because of how
76 // pepper painting works, we might not have the data. One way to force this
77 // to be flushed is to do a find operation, since on this two-page test
78 // document, it'll wait for us to flush the renderer message loop twice and
79 // also the browser's once, at which point we're guaranteed to have updated
80 // the backingstore. Hacky, but it works.
81 // Note that we need to change the text each time, because if we don't the
82 // renderer code will think the second message is to go to next result, but
83 // there are none so the plugin will assert.
85 base::string16 query
= base::UTF8ToUTF16(
86 std::string("xyzxyz" + base::IntToString(next_dummy_search_value_
++)));
87 ASSERT_EQ(0, ui_test_utils::FindInPage(
88 browser()->tab_strip_model()->GetActiveWebContents(),
89 query
, true, false, NULL
, NULL
));
92 bool PDFBrowserTest::VerifySnapshot(const std::string
& expected_filename
) {
93 snapshot_different_
= true;
94 expected_filename_
= expected_filename
;
95 content::WebContents
* web_contents
=
96 browser()->tab_strip_model()->GetActiveWebContents();
99 content::RenderWidgetHost
* rwh
= web_contents
->GetRenderViewHost();
100 rwh
->CopyFromBackingStore(
103 base::Bind(&PDFBrowserTest::CopyFromBackingStoreCallback
, this),
106 content::RunMessageLoop();
108 if (snapshot_different_
) {
109 LOG(INFO
) << "Rendering didn't match, see result "
110 << snapshot_filename_
.value();
112 return !snapshot_different_
;
115 void PDFBrowserTest::CopyFromBackingStoreCallback(
116 const SkBitmap
& bitmap
,
117 content::ReadbackResponse response
) {
118 base::MessageLoopForUI::current()->Quit();
119 ASSERT_EQ(response
, content::READBACK_SUCCESS
);
120 base::FilePath reference
= ui_test_utils::GetTestFilePath(
121 base::FilePath(FILE_PATH_LITERAL("pdf_private")),
122 base::FilePath().AppendASCII(expected_filename_
));
123 base::File::Info info
;
124 ASSERT_TRUE(base::GetFileInfo(reference
, &info
));
125 int size
= static_cast<size_t>(info
.size
);
126 scoped_ptr
<char[]> data(new char[size
]);
127 ASSERT_EQ(size
, base::ReadFile(reference
, data
.get(), size
));
130 std::vector
<unsigned char> decoded
;
131 ASSERT_TRUE(gfx::PNGCodec::Decode(
132 reinterpret_cast<unsigned char*>(data
.get()), size
,
133 gfx::PNGCodec::FORMAT_BGRA
, &decoded
, &w
, &h
));
134 int32
* ref_pixels
= reinterpret_cast<int32
*>(&decoded
[0]);
136 SkAutoLockPixels
lock_image(bitmap
);
137 int32
* pixels
= static_cast<int32
*>(bitmap
.getPixels());
139 // Get the background color, and use it to figure out the x-offsets in
140 // each image. The reason is that depending on the theme in the OS, the
141 // same browser width can lead to slightly different plugin sizes, so the
142 // pdf content will start at different x offsets.
143 // Also note that the images we saved are cut off before the scrollbar, as
144 // that'll change depending on the theme, and also cut off vertically so
145 // that the ui controls don't show up, as those fade-in and so the timing
146 // will affect their transparency.
147 int32 bg_color
= ref_pixels
[0];
148 int ref_x_offset
, snapshot_x_offset
;
149 for (ref_x_offset
= 0; ref_x_offset
< w
; ++ref_x_offset
) {
150 if (ref_pixels
[ref_x_offset
] != bg_color
)
154 for (snapshot_x_offset
= 0; snapshot_x_offset
< bitmap
.width();
155 ++snapshot_x_offset
) {
156 if (pixels
[snapshot_x_offset
] != bg_color
)
160 int x_max
= std::min(w
- ref_x_offset
, bitmap
.width() - snapshot_x_offset
);
161 int y_max
= std::min(h
, bitmap
.height());
162 int stride
= bitmap
.rowBytes();
163 snapshot_different_
= false;
164 for (int y
= 0; y
< y_max
&& !snapshot_different_
; ++y
) {
165 for (int x
= 0; x
< x_max
&& !snapshot_different_
; ++x
) {
166 if (pixels
[y
* stride
/ sizeof(int32
) + x
+ snapshot_x_offset
] !=
167 ref_pixels
[y
* w
+ x
+ ref_x_offset
])
168 snapshot_different_
= true;
172 if (snapshot_different_
) {
173 std::vector
<unsigned char> png_data
;
174 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap
, false, &png_data
);
175 if (base::CreateTemporaryFile(&snapshot_filename_
)) {
176 base::WriteFile(snapshot_filename_
,
177 reinterpret_cast<char*>(&png_data
[0]), png_data
.size());
182 void PDFBrowserTest::Observe(int type
,
183 const content::NotificationSource
& source
,
184 const content::NotificationDetails
& details
) {
185 DCHECK_EQ(content::NOTIFICATION_LOAD_STOP
, type
);
186 load_stop_notification_count_
++;
189 void PDFBrowserTest::SetUpCommandLine(base::CommandLine
* command_line
) {
190 // Due to the changed architecture of the OOP PDF plugin, these tests don't
191 // pass and need to be reworked. crbug.com/436444.
192 command_line
->AppendSwitch(switches::kDisableOutOfProcessPdf
);
194 #if defined(OS_LINUX)
195 // Calling RenderWidgetHost::CopyFromBackingStore() with the GPU enabled
197 command_line
->AppendSwitch(switches::kDisableGpu
);
200 #if defined(OS_CHROMEOS)
201 // Also need on CrOS in addition to disabling the GPU above.
202 command_line
->AppendSwitch(switches::kUIDisableThreadedCompositing
);