Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_browsertest.cc
blobbf7e250a2e0dc4e36f08a2bd07b015f962add62f
1 // Copyright (c) 2013 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 "base/barrier_closure.h"
6 #include "base/command_line.h"
7 #include "base/message_loop/message_loop_proxy.h"
8 #include "base/path_service.h"
9 #include "base/run_loop.h"
10 #include "content/browser/gpu/compositor_util.h"
11 #include "content/browser/gpu/gpu_data_manager_impl.h"
12 #include "content/browser/renderer_host/dip_util.h"
13 #include "content/browser/renderer_host/render_widget_host_impl.h"
14 #include "content/browser/renderer_host/render_widget_host_view_base.h"
15 #include "content/public/browser/gpu_data_manager.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/content_paths.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/content_browser_test.h"
24 #include "content/public/test/content_browser_test_utils.h"
25 #include "content/shell/browser/shell.h"
26 #include "media/base/video_frame.h"
27 #include "media/blink/skcanvas_video_renderer.h"
28 #include "net/base/filename_util.h"
29 #include "third_party/skia/include/core/SkBitmap.h"
30 #include "third_party/skia/include/core/SkCanvas.h"
31 #include "ui/base/layout.h"
32 #include "ui/base/ui_base_switches.h"
33 #include "ui/gfx/geometry/size_conversions.h"
34 #include "ui/gfx/switches.h"
35 #include "ui/gl/gl_switches.h"
37 #if defined(OS_WIN)
38 #include "base/win/windows_version.h"
39 #include "ui/gfx/win/dpi.h"
40 #endif
42 namespace content {
43 namespace {
45 // Convenience macro: Short-circuit a pass for the tests where platform support
46 // for forced-compositing mode (or disabled-compositing mode) is lacking.
47 #define SET_UP_SURFACE_OR_PASS_TEST(wait_message) \
48 if (!SetUpSourceSurface(wait_message)) { \
49 LOG(WARNING) \
50 << ("Blindly passing this test: This platform does not support " \
51 "forced compositing (or forced-disabled compositing) mode."); \
52 return; \
55 // Common base class for browser tests. This is subclassed twice: Once to test
56 // the browser in forced-compositing mode, and once to test with compositing
57 // mode disabled.
58 class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
59 public:
60 RenderWidgetHostViewBrowserTest()
61 : frame_size_(400, 300),
62 callback_invoke_count_(0),
63 frames_captured_(0) {}
65 void SetUpOnMainThread() override {
66 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
69 // Attempts to set up the source surface. Returns false if unsupported on the
70 // current platform.
71 virtual bool SetUpSourceSurface(const char* wait_message) = 0;
73 int callback_invoke_count() const {
74 return callback_invoke_count_;
77 int frames_captured() const {
78 return frames_captured_;
81 const gfx::Size& frame_size() const {
82 return frame_size_;
85 const base::FilePath& test_dir() const {
86 return test_dir_;
89 RenderViewHost* GetRenderViewHost() const {
90 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
91 CHECK(rvh);
92 return rvh;
95 RenderWidgetHostImpl* GetRenderWidgetHost() const {
96 RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From(
97 shell()->web_contents()->GetRenderWidgetHostView()->
98 GetRenderWidgetHost());
99 CHECK(rwh);
100 return rwh;
103 RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
104 return static_cast<RenderWidgetHostViewBase*>(
105 GetRenderViewHost()->GetView());
108 // Callback when using CopyFromBackingStore() API.
109 void FinishCopyFromBackingStore(const base::Closure& quit_closure,
110 const SkBitmap& bitmap,
111 ReadbackResponse response) {
112 ++callback_invoke_count_;
113 if (response == READBACK_SUCCESS) {
114 ++frames_captured_;
115 EXPECT_FALSE(bitmap.empty());
117 if (!quit_closure.is_null())
118 quit_closure.Run();
121 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API.
122 void FinishCopyFromCompositingSurface(const base::Closure& quit_closure,
123 bool frame_captured) {
124 ++callback_invoke_count_;
125 if (frame_captured)
126 ++frames_captured_;
127 if (!quit_closure.is_null())
128 quit_closure.Run();
131 // Callback when using frame subscriber API.
132 void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop,
133 base::Closure quit_closure,
134 base::TimeTicks timestamp,
135 bool frame_captured) {
136 ++callback_invoke_count_;
137 if (frame_captured)
138 ++frames_captured_;
139 if (!quit_closure.is_null())
140 loop->PostTask(FROM_HERE, quit_closure);
143 // Copy one frame using the CopyFromBackingStore API.
144 void RunBasicCopyFromBackingStoreTest() {
145 SET_UP_SURFACE_OR_PASS_TEST(NULL);
147 // Repeatedly call CopyFromBackingStore() since, on some platforms (e.g.,
148 // Windows), the operation will fail until the first "present" has been
149 // made.
150 int count_attempts = 0;
151 while (true) {
152 ++count_attempts;
153 base::RunLoop run_loop;
154 GetRenderViewHost()->CopyFromBackingStore(
155 gfx::Rect(),
156 frame_size(),
157 base::Bind(
158 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
159 base::Unretained(this),
160 run_loop.QuitClosure()),
161 kN32_SkColorType);
162 run_loop.Run();
164 if (frames_captured())
165 break;
166 else
167 GiveItSomeTime();
170 EXPECT_EQ(count_attempts, callback_invoke_count());
171 EXPECT_EQ(1, frames_captured());
174 protected:
175 // Waits until the source is available for copying.
176 void WaitForCopySourceReady() {
177 while (!GetRenderWidgetHostView()->IsSurfaceAvailableForCopy())
178 GiveItSomeTime();
181 // Run the current message loop for a short time without unwinding the current
182 // call stack.
183 static void GiveItSomeTime() {
184 base::RunLoop run_loop;
185 base::MessageLoop::current()->PostDelayedTask(
186 FROM_HERE,
187 run_loop.QuitClosure(),
188 base::TimeDelta::FromMilliseconds(10));
189 run_loop.Run();
192 private:
193 const gfx::Size frame_size_;
194 base::FilePath test_dir_;
195 int callback_invoke_count_;
196 int frames_captured_;
199 enum CompositingMode {
200 GL_COMPOSITING,
201 SOFTWARE_COMPOSITING,
204 class CompositingRenderWidgetHostViewBrowserTest
205 : public RenderWidgetHostViewBrowserTest,
206 public testing::WithParamInterface<CompositingMode> {
207 public:
208 explicit CompositingRenderWidgetHostViewBrowserTest()
209 : compositing_mode_(GetParam()) {}
211 void SetUp() override {
212 if (compositing_mode_ == SOFTWARE_COMPOSITING)
213 UseSoftwareCompositing();
214 RenderWidgetHostViewBrowserTest::SetUp();
217 virtual GURL TestUrl() {
218 return net::FilePathToFileURL(
219 test_dir().AppendASCII("rwhv_compositing_animation.html"));
222 bool SetUpSourceSurface(const char* wait_message) override {
223 content::DOMMessageQueue message_queue;
224 NavigateToURL(shell(), TestUrl());
225 if (wait_message != NULL) {
226 std::string result(wait_message);
227 if (!message_queue.WaitForMessage(&result)) {
228 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed.";
229 return false;
233 // A frame might not be available yet. So, wait for it.
234 WaitForCopySourceReady();
235 return true;
238 private:
239 const CompositingMode compositing_mode_;
241 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewBrowserTest);
244 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
245 public:
246 FakeFrameSubscriber(
247 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback)
248 : callback_(callback) {
251 bool ShouldCaptureFrame(const gfx::Rect& damage_rect,
252 base::TimeTicks present_time,
253 scoped_refptr<media::VideoFrame>* storage,
254 DeliverFrameCallback* callback) override {
255 // Only allow one frame capture to be made. Otherwise, the compositor could
256 // start multiple captures, unbounded, and eventually its own limiter logic
257 // will begin invoking |callback| with a |false| result. This flakes out
258 // the unit tests, since they receive a "failed" callback before the later
259 // "success" callbacks.
260 if (callback_.is_null())
261 return false;
262 *storage = media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100));
263 *callback = callback_;
264 callback_.Reset();
265 return true;
268 private:
269 DeliverFrameCallback callback_;
272 // Disable tests for Android and IOS as these platforms have incomplete
273 // implementation.
274 #if !defined(OS_ANDROID) && !defined(OS_IOS)
276 // The CopyFromBackingStore() API should work on all platforms when compositing
277 // is enabled.
278 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
279 CopyFromBackingStore) {
280 RunBasicCopyFromBackingStoreTest();
283 // Tests that the callback passed to CopyFromBackingStore is always called,
284 // even when the RenderWidgetHost is deleting in the middle of an async copy.
285 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
286 CopyFromBackingStore_CallbackDespiteDelete) {
287 SET_UP_SURFACE_OR_PASS_TEST(NULL);
289 base::RunLoop run_loop;
290 GetRenderViewHost()->CopyFromBackingStore(
291 gfx::Rect(),
292 frame_size(),
293 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
294 base::Unretained(this),
295 run_loop.QuitClosure()),
296 kN32_SkColorType);
297 run_loop.Run();
299 EXPECT_EQ(1, callback_invoke_count());
302 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
303 // always called, even when the RenderWidgetHost is deleting in the middle of
304 // an async copy.
305 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
306 CopyFromCompositingSurface_CallbackDespiteDelete) {
307 SET_UP_SURFACE_OR_PASS_TEST(NULL);
308 RenderWidgetHostViewBase* const view = GetRenderWidgetHostView();
309 if (!view->CanCopyToVideoFrame()) {
310 LOG(WARNING) <<
311 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() "
312 "not supported on this platform.");
313 return;
316 base::RunLoop run_loop;
317 scoped_refptr<media::VideoFrame> dest =
318 media::VideoFrame::CreateBlackFrame(frame_size());
319 view->CopyFromCompositingSurfaceToVideoFrame(
320 gfx::Rect(view->GetViewBounds().size()), dest, base::Bind(
321 &RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface,
322 base::Unretained(this), run_loop.QuitClosure()));
323 run_loop.Run();
325 EXPECT_EQ(1, callback_invoke_count());
328 // Test basic frame subscription functionality. We subscribe, and then run
329 // until at least one DeliverFrameCallback has been invoked.
330 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
331 FrameSubscriberTest) {
332 SET_UP_SURFACE_OR_PASS_TEST(NULL);
333 RenderWidgetHostViewBase* const view = GetRenderWidgetHostView();
334 if (!view->CanSubscribeFrame()) {
335 LOG(WARNING) << ("Blindly passing this test: Frame subscription not "
336 "supported on this platform.");
337 return;
340 base::RunLoop run_loop;
341 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
342 new FakeFrameSubscriber(
343 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
344 base::Unretained(this),
345 base::MessageLoopProxy::current(),
346 run_loop.QuitClosure())));
347 view->BeginFrameSubscription(subscriber.Pass());
348 run_loop.Run();
349 view->EndFrameSubscription();
351 EXPECT_LE(1, callback_invoke_count());
352 EXPECT_LE(1, frames_captured());
355 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) {
356 SET_UP_SURFACE_OR_PASS_TEST(NULL);
357 RenderWidgetHostViewBase* const view = GetRenderWidgetHostView();
358 if (!view->CanCopyToVideoFrame()) {
359 LOG(WARNING) << ("Blindly passing this test: "
360 "CopyFromCompositingSurfaceToVideoFrame() not supported "
361 "on this platform.");
362 return;
365 base::RunLoop run_loop;
366 scoped_refptr<media::VideoFrame> first_output =
367 media::VideoFrame::CreateBlackFrame(frame_size());
368 ASSERT_TRUE(first_output.get());
369 scoped_refptr<media::VideoFrame> second_output =
370 media::VideoFrame::CreateBlackFrame(frame_size());
371 ASSERT_TRUE(second_output.get());
372 base::Closure closure = base::BarrierClosure(2, run_loop.QuitClosure());
373 view->CopyFromCompositingSurfaceToVideoFrame(
374 gfx::Rect(view->GetViewBounds().size()), first_output,
375 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
376 base::Unretained(this), base::MessageLoopProxy::current(),
377 closure, base::TimeTicks::Now()));
378 view->CopyFromCompositingSurfaceToVideoFrame(
379 gfx::Rect(view->GetViewBounds().size()), second_output,
380 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
381 base::Unretained(this), base::MessageLoopProxy::current(),
382 closure, base::TimeTicks::Now()));
383 run_loop.Run();
385 EXPECT_EQ(2, callback_invoke_count());
386 EXPECT_EQ(2, frames_captured());
389 class CompositingRenderWidgetHostViewBrowserTestTabCapture
390 : public CompositingRenderWidgetHostViewBrowserTest {
391 public:
392 CompositingRenderWidgetHostViewBrowserTestTabCapture()
393 : readback_response_(READBACK_NO_RESPONSE),
394 allowable_error_(0),
395 test_url_("data:text/html,<!doctype html>") {}
397 void SetUp() override {
398 EnablePixelOutput();
399 CompositingRenderWidgetHostViewBrowserTest::SetUp();
402 void ReadbackRequestCallbackTest(base::Closure quit_callback,
403 const SkBitmap& bitmap,
404 ReadbackResponse response) {
405 readback_response_ = response;
406 if (response != READBACK_SUCCESS) {
407 quit_callback.Run();
408 return;
411 SkAutoLockPixels bitmap_lock(bitmap);
413 // Check that the |bitmap| contains cyan and/or yellow pixels. This is
414 // needed because the compositor will read back "blank" frames until the
415 // first frame from the renderer is composited. See comments in
416 // PerformTestWithLeftRightRects() for more details about eliminating test
417 // flakiness.
418 bool contains_a_test_color = false;
419 for (int i = 0; i < bitmap.width(); ++i) {
420 for (int j = 0; j < bitmap.height(); ++j) {
421 if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j))
422 continue;
424 const unsigned high_threshold = 0xff - allowable_error_;
425 const unsigned low_threshold = 0x00 + allowable_error_;
426 const SkColor color = bitmap.getColor(i, j);
427 const bool is_cyan = SkColorGetR(color) <= low_threshold &&
428 SkColorGetG(color) >= high_threshold &&
429 SkColorGetB(color) >= high_threshold;
430 const bool is_yellow = SkColorGetR(color) >= high_threshold &&
431 SkColorGetG(color) >= high_threshold &&
432 SkColorGetB(color) <= low_threshold;
433 if (is_cyan || is_yellow) {
434 contains_a_test_color = true;
435 break;
439 if (!contains_a_test_color) {
440 readback_response_ = READBACK_NO_TEST_COLORS;
441 quit_callback.Run();
442 return;
445 // Compare the readback |bitmap| to the |expected_bitmap|, pixel-by-pixel.
446 const SkBitmap& expected_bitmap =
447 expected_copy_from_compositing_surface_bitmap_;
448 EXPECT_EQ(expected_bitmap.width(), bitmap.width());
449 EXPECT_EQ(expected_bitmap.height(), bitmap.height());
450 EXPECT_EQ(expected_bitmap.colorType(), bitmap.colorType());
451 SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
452 int fails = 0;
453 for (int i = 0; i < bitmap.width() && fails < 10; ++i) {
454 for (int j = 0; j < bitmap.height() && fails < 10; ++j) {
455 if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j))
456 continue;
458 SkColor expected_color = expected_bitmap.getColor(i, j);
459 SkColor color = bitmap.getColor(i, j);
460 int expected_alpha = SkColorGetA(expected_color);
461 int alpha = SkColorGetA(color);
462 int expected_red = SkColorGetR(expected_color);
463 int red = SkColorGetR(color);
464 int expected_green = SkColorGetG(expected_color);
465 int green = SkColorGetG(color);
466 int expected_blue = SkColorGetB(expected_color);
467 int blue = SkColorGetB(color);
468 EXPECT_NEAR(expected_alpha, alpha, allowable_error_)
469 << "expected_color: " << std::hex << expected_color
470 << " color: " << color
471 << " Failed at " << std::dec << i << ", " << j
472 << " Failure " << ++fails;
473 EXPECT_NEAR(expected_red, red, allowable_error_)
474 << "expected_color: " << std::hex << expected_color
475 << " color: " << color
476 << " Failed at " << std::dec << i << ", " << j
477 << " Failure " << ++fails;
478 EXPECT_NEAR(expected_green, green, allowable_error_)
479 << "expected_color: " << std::hex << expected_color
480 << " color: " << color
481 << " Failed at " << std::dec << i << ", " << j
482 << " Failure " << ++fails;
483 EXPECT_NEAR(expected_blue, blue, allowable_error_)
484 << "expected_color: " << std::hex << expected_color
485 << " color: " << color
486 << " Failed at " << std::dec << i << ", " << j
487 << " Failure " << ++fails;
490 EXPECT_LT(fails, 10);
492 quit_callback.Run();
495 void ReadbackRequestCallbackForVideo(
496 scoped_refptr<media::VideoFrame> video_frame,
497 base::Closure quit_callback,
498 bool result) {
499 if (!result) {
500 readback_response_ = READBACK_TO_VIDEO_FRAME_FAILED;
501 quit_callback.Run();
502 return;
505 media::SkCanvasVideoRenderer video_renderer;
507 SkBitmap bitmap;
508 bitmap.allocN32Pixels(video_frame->visible_rect().width(),
509 video_frame->visible_rect().height());
510 // Don't clear the canvas because drawing a video frame by Src mode.
511 SkCanvas canvas(bitmap);
512 video_renderer.Copy(video_frame, &canvas, media::Context3D());
514 ReadbackRequestCallbackTest(quit_callback, bitmap, READBACK_SUCCESS);
517 void SetAllowableError(int amount) { allowable_error_ = amount; }
518 void SetExcludeRect(gfx::Rect exclude) { exclude_rect_ = exclude; }
520 GURL TestUrl() override { return GURL(test_url_); }
522 void SetTestUrl(std::string url) { test_url_ = url; }
524 // Loads a page two boxes side-by-side, each half the width of
525 // |html_rect_size|, and with different background colors. The test then
526 // copies from |copy_rect| region of the page into a bitmap of size
527 // |output_size|, and examines the resulting bitmap/VideoFrame.
528 // Note that |output_size| may not have the same size as |copy_rect| (e.g.
529 // when the output is scaled).
530 void PerformTestWithLeftRightRects(const gfx::Size& html_rect_size,
531 const gfx::Rect& copy_rect,
532 const gfx::Size& output_size,
533 bool video_frame) {
534 const gfx::Size box_size(html_rect_size.width() / 2,
535 html_rect_size.height());
536 SetTestUrl(base::StringPrintf(
537 "data:text/html,<!doctype html>"
538 "<div class='left'>"
539 " <div class='right'></div>"
540 "</div>"
541 "<style>"
542 "body { padding: 0; margin: 0; }"
543 ".left { position: absolute;"
544 " background: #0ff;"
545 " width: %dpx;"
546 " height: %dpx;"
548 ".right { position: absolute;"
549 " left: %dpx;"
550 " background: #ff0;"
551 " width: %dpx;"
552 " height: %dpx;"
554 "</style>"
555 "<script>"
556 " domAutomationController.setAutomationId(0);"
557 " domAutomationController.send(\"DONE\");"
558 "</script>",
559 box_size.width(),
560 box_size.height(),
561 box_size.width(),
562 box_size.width(),
563 box_size.height()));
565 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\"");
566 if (!ShouldContinueAfterTestURLLoad())
567 return;
569 RenderWidgetHostViewBase* rwhv = GetRenderWidgetHostView();
570 ASSERT_TRUE(!video_frame || rwhv->CanCopyToVideoFrame());
572 SetupLeftRightBitmap(output_size,
573 &expected_copy_from_compositing_surface_bitmap_);
575 // The page is loaded in the renderer. Request frames from the renderer
576 // until readback succeeds. When readback succeeds, the resulting
577 // SkBitmap/VideoFrame is examined to ensure it matches the expected result.
578 // This loop is needed because:
579 // 1. Painting/Compositing is not synchronous with the Javascript engine,
580 // and so the "DONE" signal above could be received before the renderer
581 // provides a frame with the expected content. http://crbug.com/405282
582 // 2. Avoiding test flakiness: On some platforms, the readback operation
583 // is allowed to transiently fail. The purpose of these tests is to
584 // confirm correct cropping/scaling behavior; and not that every
585 // readback must succeed. http://crbug.com/444237
586 uint32 last_frame_number = 0;
587 do {
588 // Wait for renderer to provide the next frame.
589 while (!GetRenderWidgetHost()->ScheduleComposite())
590 GiveItSomeTime();
591 while (rwhv->RendererFrameNumber() == last_frame_number)
592 GiveItSomeTime();
593 last_frame_number = rwhv->RendererFrameNumber();
595 // Request readback. The callbacks will examine the pixels in the
596 // SkBitmap/VideoFrame result if readback was successful.
597 readback_response_ = READBACK_NO_RESPONSE;
598 base::RunLoop run_loop;
599 if (video_frame) {
600 // Allow pixel differences as long as we have the right idea.
601 SetAllowableError(0x10);
602 // Exclude the middle two columns which are blended between the two
603 // sides.
604 SetExcludeRect(
605 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
607 scoped_refptr<media::VideoFrame> video_frame =
608 media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
609 output_size,
610 gfx::Rect(output_size),
611 output_size,
612 base::TimeDelta());
614 base::Callback<void(bool success)> callback =
615 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
616 ReadbackRequestCallbackForVideo,
617 base::Unretained(this),
618 video_frame,
619 run_loop.QuitClosure());
620 rwhv->CopyFromCompositingSurfaceToVideoFrame(
621 copy_rect, video_frame, callback);
622 } else {
623 if (IsDelegatedRendererEnabled()) {
624 if (!content::GpuDataManager::GetInstance()
625 ->CanUseGpuBrowserCompositor()) {
626 // Skia rendering can cause color differences, particularly in the
627 // middle two columns.
628 SetAllowableError(2);
629 SetExcludeRect(gfx::Rect(
630 output_size.width() / 2 - 1, 0, 2, output_size.height()));
634 ReadbackRequestCallback callback =
635 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
636 ReadbackRequestCallbackTest,
637 base::Unretained(this),
638 run_loop.QuitClosure());
639 rwhv->CopyFromCompositingSurface(
640 copy_rect, output_size, callback, kN32_SkColorType);
642 run_loop.Run();
644 // If the readback operation did not provide a frame, log the reason
645 // to aid in future debugging. This information will also help determine
646 // whether the implementation is broken, or a test bot is in a bad state.
647 #define CASE_LOG_READBACK_WARNING(enum_value) \
648 case enum_value: \
649 LOG(WARNING) << "Readback attempt failed (render frame #" \
650 << last_frame_number << "). Reason: " #enum_value; \
651 break
652 switch (readback_response_) {
653 case READBACK_SUCCESS:
654 break;
655 CASE_LOG_READBACK_WARNING(READBACK_FAILED);
656 CASE_LOG_READBACK_WARNING(READBACK_FORMAT_NOT_SUPPORTED);
657 CASE_LOG_READBACK_WARNING(READBACK_NOT_SUPPORTED);
658 CASE_LOG_READBACK_WARNING(READBACK_SURFACE_UNAVAILABLE);
659 CASE_LOG_READBACK_WARNING(READBACK_MEMORY_ALLOCATION_FAILURE);
660 CASE_LOG_READBACK_WARNING(READBACK_NO_TEST_COLORS);
661 CASE_LOG_READBACK_WARNING(READBACK_TO_VIDEO_FRAME_FAILED);
662 default:
663 LOG(ERROR)
664 << "Invalid readback response value: " << readback_response_;
665 NOTREACHED();
667 } while (readback_response_ != READBACK_SUCCESS);
670 // Sets up |bitmap| to have size |copy_size|. It floods the left half with
671 // #0ff and the right half with #ff0.
672 void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) {
673 bitmap->allocN32Pixels(copy_size.width(), copy_size.height());
674 // Left half is #0ff.
675 bitmap->eraseARGB(255, 0, 255, 255);
676 // Right half is #ff0.
678 SkAutoLockPixels lock(*bitmap);
679 for (int i = 0; i < copy_size.width() / 2; ++i) {
680 for (int j = 0; j < copy_size.height(); ++j) {
681 *(bitmap->getAddr32(copy_size.width() / 2 + i, j)) =
682 SkColorSetARGB(255, 255, 255, 0);
688 protected:
689 // Additional ReadbackResponse enum values only used within this test module,
690 // to distinguish readback exception cases further.
691 enum ExtraReadbackResponsesForTest {
692 READBACK_NO_RESPONSE = -1337,
693 READBACK_NO_TEST_COLORS,
694 READBACK_TO_VIDEO_FRAME_FAILED,
697 virtual bool ShouldContinueAfterTestURLLoad() {
698 return true;
701 private:
702 // |readback_response_| is always a content::ReadbackResponse or
703 // ExtraReadbackResponsesForTest enum value.
704 int readback_response_;
705 SkBitmap expected_copy_from_compositing_surface_bitmap_;
706 int allowable_error_;
707 gfx::Rect exclude_rect_;
708 std::string test_url_;
711 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
712 CopyFromCompositingSurface_Origin_Unscaled) {
713 gfx::Rect copy_rect(400, 300);
714 gfx::Size output_size = copy_rect.size();
715 gfx::Size html_rect_size(400, 300);
716 bool video_frame = false;
717 PerformTestWithLeftRightRects(html_rect_size,
718 copy_rect,
719 output_size,
720 video_frame);
723 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
724 CopyFromCompositingSurface_Origin_Scaled) {
725 gfx::Rect copy_rect(400, 300);
726 gfx::Size output_size(200, 100);
727 gfx::Size html_rect_size(400, 300);
728 bool video_frame = false;
729 PerformTestWithLeftRightRects(html_rect_size,
730 copy_rect,
731 output_size,
732 video_frame);
735 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
736 CopyFromCompositingSurface_Cropped_Unscaled) {
737 // Grab 60x60 pixels from the center of the tab contents.
738 gfx::Rect copy_rect(400, 300);
739 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
740 gfx::Size(60, 60));
741 gfx::Size output_size = copy_rect.size();
742 gfx::Size html_rect_size(400, 300);
743 bool video_frame = false;
744 PerformTestWithLeftRightRects(html_rect_size,
745 copy_rect,
746 output_size,
747 video_frame);
750 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
751 CopyFromCompositingSurface_Cropped_Scaled) {
752 // Grab 60x60 pixels from the center of the tab contents.
753 gfx::Rect copy_rect(400, 300);
754 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
755 gfx::Size(60, 60));
756 gfx::Size output_size(20, 10);
757 gfx::Size html_rect_size(400, 300);
758 bool video_frame = false;
759 PerformTestWithLeftRightRects(html_rect_size,
760 copy_rect,
761 output_size,
762 video_frame);
765 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
766 CopyFromCompositingSurface_ForVideoFrame) {
767 // Grab 90x60 pixels from the center of the tab contents.
768 gfx::Rect copy_rect(400, 300);
769 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
770 gfx::Size(90, 60));
771 gfx::Size output_size = copy_rect.size();
772 gfx::Size html_rect_size(400, 300);
773 bool video_frame = true;
774 PerformTestWithLeftRightRects(html_rect_size,
775 copy_rect,
776 output_size,
777 video_frame);
780 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
781 CopyFromCompositingSurface_ForVideoFrame_Scaled) {
782 // Grab 90x60 pixels from the center of the tab contents.
783 gfx::Rect copy_rect(400, 300);
784 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
785 gfx::Size(90, 60));
786 // Scale to 30 x 20 (preserve aspect ratio).
787 gfx::Size output_size(30, 20);
788 gfx::Size html_rect_size(400, 300);
789 bool video_frame = true;
790 PerformTestWithLeftRightRects(html_rect_size,
791 copy_rect,
792 output_size,
793 video_frame);
796 class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
797 : public CompositingRenderWidgetHostViewBrowserTestTabCapture {
798 public:
799 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI() {}
801 protected:
802 void SetUpCommandLine(base::CommandLine* cmd) override {
803 CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd);
804 cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
805 base::StringPrintf("%f", scale()));
808 bool ShouldContinueAfterTestURLLoad() override {
809 // Short-circuit a pass for platforms where setting up high-DPI fails.
810 const float actual_scale_factor =
811 GetScaleFactorForView(GetRenderWidgetHostView());
812 if (actual_scale_factor != scale()) {
813 LOG(WARNING) << "Blindly passing this test; unable to force device scale "
814 << "factor: seems to be " << actual_scale_factor
815 << " but expected " << scale();
816 return false;
818 VLOG(1) << ("Successfully forced device scale factor. Moving forward with "
819 "this test! :-)");
820 return true;
823 static float scale() { return 2.0f; }
825 private:
826 DISALLOW_COPY_AND_ASSIGN(
827 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI);
830 // NineImagePainter implementation crashes the process on Windows when this
831 // content_browsertest forces a device scale factor. http://crbug.com/399349
832 #if defined(OS_WIN)
833 #define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
834 #define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
835 #define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
836 #define MAYBE_CopyToVideoFrame_EntireRegion \
837 DISABLED_CopyToVideoFrame_EntireRegion
838 #define MAYBE_CopyToVideoFrame_CenterRegion \
839 DISABLED_CopyToVideoFrame_CenterRegion
840 #define MAYBE_CopyToVideoFrame_ScaledResult \
841 DISABLED_CopyToVideoFrame_ScaledResult
842 #else
843 #define MAYBE_CopyToBitmap_EntireRegion CopyToBitmap_EntireRegion
844 #define MAYBE_CopyToBitmap_CenterRegion CopyToBitmap_CenterRegion
845 #define MAYBE_CopyToBitmap_ScaledResult CopyToBitmap_ScaledResult
846 #define MAYBE_CopyToVideoFrame_EntireRegion CopyToVideoFrame_EntireRegion
847 #define MAYBE_CopyToVideoFrame_CenterRegion CopyToVideoFrame_CenterRegion
848 #define MAYBE_CopyToVideoFrame_ScaledResult CopyToVideoFrame_ScaledResult
849 #endif
851 IN_PROC_BROWSER_TEST_P(
852 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
853 MAYBE_CopyToBitmap_EntireRegion) {
854 gfx::Size html_rect_size(200, 150);
855 gfx::Rect copy_rect(200, 150);
856 // Scale the output size so that, internally, scaling is not occurring.
857 gfx::Size output_size =
858 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
859 bool video_frame = false;
860 PerformTestWithLeftRightRects(html_rect_size,
861 copy_rect,
862 output_size,
863 video_frame);
866 IN_PROC_BROWSER_TEST_P(
867 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
868 MAYBE_CopyToBitmap_CenterRegion) {
869 gfx::Size html_rect_size(200, 150);
870 // Grab 90x60 pixels from the center of the tab contents.
871 gfx::Rect copy_rect =
872 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
873 gfx::Size(90, 60));
874 // Scale the output size so that, internally, scaling is not occurring.
875 gfx::Size output_size =
876 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
877 bool video_frame = false;
878 PerformTestWithLeftRightRects(html_rect_size,
879 copy_rect,
880 output_size,
881 video_frame);
884 IN_PROC_BROWSER_TEST_P(
885 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
886 MAYBE_CopyToBitmap_ScaledResult) {
887 gfx::Size html_rect_size(200, 100);
888 gfx::Rect copy_rect(200, 100);
889 // Output is being down-scaled since output_size is in phyiscal pixels.
890 gfx::Size output_size(200, 100);
891 bool video_frame = false;
892 PerformTestWithLeftRightRects(html_rect_size,
893 copy_rect,
894 output_size,
895 video_frame);
898 IN_PROC_BROWSER_TEST_P(
899 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
900 MAYBE_CopyToVideoFrame_EntireRegion) {
901 gfx::Size html_rect_size(200, 150);
902 gfx::Rect copy_rect(200, 150);
903 // Scale the output size so that, internally, scaling is not occurring.
904 gfx::Size output_size =
905 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
906 bool video_frame = true;
907 PerformTestWithLeftRightRects(html_rect_size,
908 copy_rect,
909 output_size,
910 video_frame);
913 IN_PROC_BROWSER_TEST_P(
914 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
915 MAYBE_CopyToVideoFrame_CenterRegion) {
916 gfx::Size html_rect_size(200, 150);
917 // Grab 90x60 pixels from the center of the tab contents.
918 gfx::Rect copy_rect =
919 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
920 gfx::Size(90, 60));
921 // Scale the output size so that, internally, scaling is not occurring.
922 gfx::Size output_size =
923 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
924 bool video_frame = true;
925 PerformTestWithLeftRightRects(html_rect_size,
926 copy_rect,
927 output_size,
928 video_frame);
931 IN_PROC_BROWSER_TEST_P(
932 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
933 MAYBE_CopyToVideoFrame_ScaledResult) {
934 gfx::Size html_rect_size(200, 100);
935 gfx::Rect copy_rect(200, 100);
936 // Output is being down-scaled since output_size is in phyiscal pixels.
937 gfx::Size output_size(200, 100);
938 bool video_frame = true;
939 PerformTestWithLeftRightRects(html_rect_size,
940 copy_rect,
941 output_size,
942 video_frame);
945 #if defined(OS_CHROMEOS)
946 // On ChromeOS there is no software compositing.
947 static const auto kTestCompositingModes = testing::Values(GL_COMPOSITING);
948 #else
949 static const auto kTestCompositingModes =
950 testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING);
951 #endif
953 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
954 CompositingRenderWidgetHostViewBrowserTest,
955 kTestCompositingModes);
956 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
957 CompositingRenderWidgetHostViewBrowserTestTabCapture,
958 kTestCompositingModes);
959 INSTANTIATE_TEST_CASE_P(
960 GLAndSoftwareCompositing,
961 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
962 kTestCompositingModes);
964 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
966 } // namespace
967 } // namespace content