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/location.h"
8 #include "base/path_service.h"
9 #include "base/run_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "content/browser/gpu/compositor_util.h"
13 #include "content/browser/gpu/gpu_data_manager_impl.h"
14 #include "content/browser/renderer_host/dip_util.h"
15 #include "content/browser/renderer_host/render_widget_host_impl.h"
16 #include "content/browser/renderer_host/render_widget_host_view_base.h"
17 #include "content/public/browser/gpu_data_manager.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/content_browser_test.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/shell/browser/shell.h"
28 #include "media/base/video_frame.h"
29 #include "media/blink/skcanvas_video_renderer.h"
30 #include "net/base/filename_util.h"
31 #include "third_party/skia/include/core/SkBitmap.h"
32 #include "third_party/skia/include/core/SkCanvas.h"
33 #include "ui/base/layout.h"
34 #include "ui/base/ui_base_switches.h"
35 #include "ui/gfx/geometry/size_conversions.h"
36 #include "ui/gfx/switches.h"
37 #include "ui/gl/gl_switches.h"
40 #include "base/win/windows_version.h"
41 #include "ui/gfx/win/dpi.h"
47 // Convenience macro: Short-circuit a pass for the tests where platform support
48 // for forced-compositing mode (or disabled-compositing mode) is lacking.
49 #define SET_UP_SURFACE_OR_PASS_TEST(wait_message) \
50 if (!SetUpSourceSurface(wait_message)) { \
52 << ("Blindly passing this test: This platform does not support " \
53 "forced compositing (or forced-disabled compositing) mode."); \
57 // Common base class for browser tests. This is subclassed twice: Once to test
58 // the browser in forced-compositing mode, and once to test with compositing
60 class RenderWidgetHostViewBrowserTest
: public ContentBrowserTest
{
62 RenderWidgetHostViewBrowserTest()
63 : frame_size_(400, 300),
64 callback_invoke_count_(0),
65 frames_captured_(0) {}
67 void SetUpOnMainThread() override
{
68 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA
, &test_dir_
));
71 // Attempts to set up the source surface. Returns false if unsupported on the
73 virtual bool SetUpSourceSurface(const char* wait_message
) = 0;
75 int callback_invoke_count() const {
76 return callback_invoke_count_
;
79 int frames_captured() const {
80 return frames_captured_
;
83 const gfx::Size
& frame_size() const {
87 const base::FilePath
& test_dir() const {
91 RenderViewHost
* GetRenderViewHost() const {
92 RenderViewHost
* const rvh
= shell()->web_contents()->GetRenderViewHost();
97 RenderWidgetHostImpl
* GetRenderWidgetHost() const {
98 RenderWidgetHostImpl
* const rwh
= RenderWidgetHostImpl::From(
99 shell()->web_contents()->GetRenderWidgetHostView()->
100 GetRenderWidgetHost());
105 RenderWidgetHostViewBase
* GetRenderWidgetHostView() const {
106 return static_cast<RenderWidgetHostViewBase
*>(
107 GetRenderViewHost()->GetView());
110 // Callback when using CopyFromBackingStore() API.
111 void FinishCopyFromBackingStore(const base::Closure
& quit_closure
,
112 const SkBitmap
& bitmap
,
113 ReadbackResponse response
) {
114 ++callback_invoke_count_
;
115 if (response
== READBACK_SUCCESS
) {
117 EXPECT_FALSE(bitmap
.empty());
119 if (!quit_closure
.is_null())
123 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API.
124 void FinishCopyFromCompositingSurface(const base::Closure
& quit_closure
,
125 bool frame_captured
) {
126 ++callback_invoke_count_
;
129 if (!quit_closure
.is_null())
133 // Callback when using frame subscriber API.
135 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
136 base::Closure quit_closure
,
137 base::TimeTicks timestamp
,
138 bool frame_captured
) {
139 ++callback_invoke_count_
;
142 if (!quit_closure
.is_null())
143 task_runner
->PostTask(FROM_HERE
, quit_closure
);
146 // Copy one frame using the CopyFromBackingStore API.
147 void RunBasicCopyFromBackingStoreTest() {
148 SET_UP_SURFACE_OR_PASS_TEST(NULL
);
150 // Repeatedly call CopyFromBackingStore() since, on some platforms (e.g.,
151 // Windows), the operation will fail until the first "present" has been
153 int count_attempts
= 0;
156 base::RunLoop run_loop
;
157 GetRenderViewHost()->CopyFromBackingStore(
161 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore
,
162 base::Unretained(this),
163 run_loop
.QuitClosure()),
167 if (frames_captured())
173 EXPECT_EQ(count_attempts
, callback_invoke_count());
174 EXPECT_EQ(1, frames_captured());
178 // Waits until the source is available for copying.
179 void WaitForCopySourceReady() {
180 while (!GetRenderWidgetHostView()->IsSurfaceAvailableForCopy())
184 // Run the current message loop for a short time without unwinding the current
186 static void GiveItSomeTime() {
187 base::RunLoop run_loop
;
188 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
189 FROM_HERE
, run_loop
.QuitClosure(),
190 base::TimeDelta::FromMilliseconds(10));
195 const gfx::Size frame_size_
;
196 base::FilePath test_dir_
;
197 int callback_invoke_count_
;
198 int frames_captured_
;
201 enum CompositingMode
{
203 SOFTWARE_COMPOSITING
,
206 class CompositingRenderWidgetHostViewBrowserTest
207 : public RenderWidgetHostViewBrowserTest
,
208 public testing::WithParamInterface
<CompositingMode
> {
210 explicit CompositingRenderWidgetHostViewBrowserTest()
211 : compositing_mode_(GetParam()) {}
213 void SetUp() override
{
214 if (compositing_mode_
== SOFTWARE_COMPOSITING
)
215 UseSoftwareCompositing();
216 RenderWidgetHostViewBrowserTest::SetUp();
219 virtual GURL
TestUrl() {
220 return net::FilePathToFileURL(
221 test_dir().AppendASCII("rwhv_compositing_animation.html"));
224 bool SetUpSourceSurface(const char* wait_message
) override
{
225 content::DOMMessageQueue message_queue
;
226 NavigateToURL(shell(), TestUrl());
227 if (wait_message
!= NULL
) {
228 std::string
result(wait_message
);
229 if (!message_queue
.WaitForMessage(&result
)) {
230 EXPECT_TRUE(false) << "WaitForMessage " << result
<< " failed.";
235 // A frame might not be available yet. So, wait for it.
236 WaitForCopySourceReady();
241 const CompositingMode compositing_mode_
;
243 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewBrowserTest
);
246 class FakeFrameSubscriber
: public RenderWidgetHostViewFrameSubscriber
{
249 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback
)
250 : callback_(callback
) {
253 bool ShouldCaptureFrame(const gfx::Rect
& damage_rect
,
254 base::TimeTicks present_time
,
255 scoped_refptr
<media::VideoFrame
>* storage
,
256 DeliverFrameCallback
* callback
) override
{
257 // Only allow one frame capture to be made. Otherwise, the compositor could
258 // start multiple captures, unbounded, and eventually its own limiter logic
259 // will begin invoking |callback| with a |false| result. This flakes out
260 // the unit tests, since they receive a "failed" callback before the later
261 // "success" callbacks.
262 if (callback_
.is_null())
264 *storage
= media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100));
265 *callback
= callback_
;
271 DeliverFrameCallback callback_
;
274 // Disable tests for Android and IOS as these platforms have incomplete
276 #if !defined(OS_ANDROID) && !defined(OS_IOS)
278 // The CopyFromBackingStore() API should work on all platforms when compositing
280 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest
,
281 CopyFromBackingStore
) {
282 RunBasicCopyFromBackingStoreTest();
285 // Tests that the callback passed to CopyFromBackingStore is always called,
286 // even when the RenderWidgetHost is deleting in the middle of an async copy.
287 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest
,
288 CopyFromBackingStore_CallbackDespiteDelete
) {
289 SET_UP_SURFACE_OR_PASS_TEST(NULL
);
291 base::RunLoop run_loop
;
292 GetRenderViewHost()->CopyFromBackingStore(
295 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore
,
296 base::Unretained(this),
297 run_loop
.QuitClosure()),
301 EXPECT_EQ(1, callback_invoke_count());
304 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
305 // always called, even when the RenderWidgetHost is deleting in the middle of
307 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest
,
308 CopyFromCompositingSurface_CallbackDespiteDelete
) {
309 SET_UP_SURFACE_OR_PASS_TEST(NULL
);
310 RenderWidgetHostViewBase
* const view
= GetRenderWidgetHostView();
311 if (!view
->CanCopyToVideoFrame()) {
313 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() "
314 "not supported on this platform.");
318 base::RunLoop run_loop
;
319 scoped_refptr
<media::VideoFrame
> dest
=
320 media::VideoFrame::CreateBlackFrame(frame_size());
321 view
->CopyFromCompositingSurfaceToVideoFrame(
322 gfx::Rect(view
->GetViewBounds().size()), dest
, base::Bind(
323 &RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface
,
324 base::Unretained(this), run_loop
.QuitClosure()));
327 EXPECT_EQ(1, callback_invoke_count());
330 // Test basic frame subscription functionality. We subscribe, and then run
331 // until at least one DeliverFrameCallback has been invoked.
332 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest
,
333 FrameSubscriberTest
) {
334 SET_UP_SURFACE_OR_PASS_TEST(NULL
);
335 RenderWidgetHostViewBase
* const view
= GetRenderWidgetHostView();
336 if (!view
->CanSubscribeFrame()) {
337 LOG(WARNING
) << ("Blindly passing this test: Frame subscription not "
338 "supported on this platform.");
342 base::RunLoop run_loop
;
343 scoped_ptr
<RenderWidgetHostViewFrameSubscriber
> subscriber(
344 new FakeFrameSubscriber(base::Bind(
345 &RenderWidgetHostViewBrowserTest::FrameDelivered
,
346 base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
347 run_loop
.QuitClosure())));
348 view
->BeginFrameSubscription(subscriber
.Pass());
350 view
->EndFrameSubscription();
352 EXPECT_LE(1, callback_invoke_count());
353 EXPECT_LE(1, frames_captured());
356 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest
, CopyTwice
) {
357 SET_UP_SURFACE_OR_PASS_TEST(NULL
);
358 RenderWidgetHostViewBase
* const view
= GetRenderWidgetHostView();
359 if (!view
->CanCopyToVideoFrame()) {
360 LOG(WARNING
) << ("Blindly passing this test: "
361 "CopyFromCompositingSurfaceToVideoFrame() not supported "
362 "on this platform.");
366 base::RunLoop run_loop
;
367 scoped_refptr
<media::VideoFrame
> first_output
=
368 media::VideoFrame::CreateBlackFrame(frame_size());
369 ASSERT_TRUE(first_output
.get());
370 scoped_refptr
<media::VideoFrame
> second_output
=
371 media::VideoFrame::CreateBlackFrame(frame_size());
372 ASSERT_TRUE(second_output
.get());
373 base::Closure closure
= base::BarrierClosure(2, run_loop
.QuitClosure());
374 view
->CopyFromCompositingSurfaceToVideoFrame(
375 gfx::Rect(view
->GetViewBounds().size()), first_output
,
376 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered
,
377 base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
378 closure
, base::TimeTicks::Now()));
379 view
->CopyFromCompositingSurfaceToVideoFrame(
380 gfx::Rect(view
->GetViewBounds().size()), second_output
,
381 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered
,
382 base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
383 closure
, base::TimeTicks::Now()));
386 EXPECT_EQ(2, callback_invoke_count());
387 EXPECT_EQ(2, frames_captured());
390 class CompositingRenderWidgetHostViewBrowserTestTabCapture
391 : public CompositingRenderWidgetHostViewBrowserTest
{
393 CompositingRenderWidgetHostViewBrowserTestTabCapture()
394 : readback_response_(READBACK_NO_RESPONSE
),
396 test_url_("data:text/html,<!doctype html>") {}
398 void SetUp() override
{
400 CompositingRenderWidgetHostViewBrowserTest::SetUp();
403 void ReadbackRequestCallbackTest(base::Closure quit_callback
,
404 const SkBitmap
& bitmap
,
405 ReadbackResponse response
) {
406 readback_response_
= response
;
407 if (response
!= READBACK_SUCCESS
) {
412 SkAutoLockPixels
bitmap_lock(bitmap
);
414 // Check that the |bitmap| contains cyan and/or yellow pixels. This is
415 // needed because the compositor will read back "blank" frames until the
416 // first frame from the renderer is composited. See comments in
417 // PerformTestWithLeftRightRects() for more details about eliminating test
419 bool contains_a_test_color
= false;
420 for (int i
= 0; i
< bitmap
.width(); ++i
) {
421 for (int j
= 0; j
< bitmap
.height(); ++j
) {
422 if (!exclude_rect_
.IsEmpty() && exclude_rect_
.Contains(i
, j
))
425 const unsigned high_threshold
= 0xff - allowable_error_
;
426 const unsigned low_threshold
= 0x00 + allowable_error_
;
427 const SkColor color
= bitmap
.getColor(i
, j
);
428 const bool is_cyan
= SkColorGetR(color
) <= low_threshold
&&
429 SkColorGetG(color
) >= high_threshold
&&
430 SkColorGetB(color
) >= high_threshold
;
431 const bool is_yellow
= SkColorGetR(color
) >= high_threshold
&&
432 SkColorGetG(color
) >= high_threshold
&&
433 SkColorGetB(color
) <= low_threshold
;
434 if (is_cyan
|| is_yellow
) {
435 contains_a_test_color
= true;
440 if (!contains_a_test_color
) {
441 readback_response_
= READBACK_NO_TEST_COLORS
;
446 // Compare the readback |bitmap| to the |expected_bitmap|, pixel-by-pixel.
447 const SkBitmap
& expected_bitmap
=
448 expected_copy_from_compositing_surface_bitmap_
;
449 EXPECT_EQ(expected_bitmap
.width(), bitmap
.width());
450 EXPECT_EQ(expected_bitmap
.height(), bitmap
.height());
451 EXPECT_EQ(expected_bitmap
.colorType(), bitmap
.colorType());
452 SkAutoLockPixels
expected_bitmap_lock(expected_bitmap
);
454 for (int i
= 0; i
< bitmap
.width() && fails
< 10; ++i
) {
455 for (int j
= 0; j
< bitmap
.height() && fails
< 10; ++j
) {
456 if (!exclude_rect_
.IsEmpty() && exclude_rect_
.Contains(i
, j
))
459 SkColor expected_color
= expected_bitmap
.getColor(i
, j
);
460 SkColor color
= bitmap
.getColor(i
, j
);
461 int expected_alpha
= SkColorGetA(expected_color
);
462 int alpha
= SkColorGetA(color
);
463 int expected_red
= SkColorGetR(expected_color
);
464 int red
= SkColorGetR(color
);
465 int expected_green
= SkColorGetG(expected_color
);
466 int green
= SkColorGetG(color
);
467 int expected_blue
= SkColorGetB(expected_color
);
468 int blue
= SkColorGetB(color
);
469 EXPECT_NEAR(expected_alpha
, alpha
, allowable_error_
)
470 << "expected_color: " << std::hex
<< expected_color
471 << " color: " << color
472 << " Failed at " << std::dec
<< i
<< ", " << j
473 << " Failure " << ++fails
;
474 EXPECT_NEAR(expected_red
, red
, allowable_error_
)
475 << "expected_color: " << std::hex
<< expected_color
476 << " color: " << color
477 << " Failed at " << std::dec
<< i
<< ", " << j
478 << " Failure " << ++fails
;
479 EXPECT_NEAR(expected_green
, green
, allowable_error_
)
480 << "expected_color: " << std::hex
<< expected_color
481 << " color: " << color
482 << " Failed at " << std::dec
<< i
<< ", " << j
483 << " Failure " << ++fails
;
484 EXPECT_NEAR(expected_blue
, blue
, allowable_error_
)
485 << "expected_color: " << std::hex
<< expected_color
486 << " color: " << color
487 << " Failed at " << std::dec
<< i
<< ", " << j
488 << " Failure " << ++fails
;
491 EXPECT_LT(fails
, 10);
496 void ReadbackRequestCallbackForVideo(
497 scoped_refptr
<media::VideoFrame
> video_frame
,
498 base::Closure quit_callback
,
501 readback_response_
= READBACK_TO_VIDEO_FRAME_FAILED
;
506 media::SkCanvasVideoRenderer video_renderer
;
509 bitmap
.allocN32Pixels(video_frame
->visible_rect().width(),
510 video_frame
->visible_rect().height());
511 // Don't clear the canvas because drawing a video frame by Src mode.
512 SkCanvas
canvas(bitmap
);
513 video_renderer
.Copy(video_frame
, &canvas
, media::Context3D());
515 ReadbackRequestCallbackTest(quit_callback
, bitmap
, READBACK_SUCCESS
);
518 void SetAllowableError(int amount
) { allowable_error_
= amount
; }
519 void SetExcludeRect(gfx::Rect exclude
) { exclude_rect_
= exclude
; }
521 GURL
TestUrl() override
{ return GURL(test_url_
); }
523 void SetTestUrl(std::string url
) { test_url_
= url
; }
525 // Loads a page two boxes side-by-side, each half the width of
526 // |html_rect_size|, and with different background colors. The test then
527 // copies from |copy_rect| region of the page into a bitmap of size
528 // |output_size|, and examines the resulting bitmap/VideoFrame.
529 // Note that |output_size| may not have the same size as |copy_rect| (e.g.
530 // when the output is scaled).
531 void PerformTestWithLeftRightRects(const gfx::Size
& html_rect_size
,
532 const gfx::Rect
& copy_rect
,
533 const gfx::Size
& output_size
,
535 const gfx::Size
box_size(html_rect_size
.width() / 2,
536 html_rect_size
.height());
537 SetTestUrl(base::StringPrintf(
538 "data:text/html,<!doctype html>"
540 " <div class='right'></div>"
543 "body { padding: 0; margin: 0; }"
544 ".left { position: absolute;"
549 ".right { position: absolute;"
557 " domAutomationController.setAutomationId(0);"
558 " domAutomationController.send(\"DONE\");"
566 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\"");
567 if (!ShouldContinueAfterTestURLLoad())
570 RenderWidgetHostViewBase
* rwhv
= GetRenderWidgetHostView();
571 ASSERT_TRUE(!video_frame
|| rwhv
->CanCopyToVideoFrame());
573 SetupLeftRightBitmap(output_size
,
574 &expected_copy_from_compositing_surface_bitmap_
);
576 // The page is loaded in the renderer. Request frames from the renderer
577 // until readback succeeds. When readback succeeds, the resulting
578 // SkBitmap/VideoFrame is examined to ensure it matches the expected result.
579 // This loop is needed because:
580 // 1. Painting/Compositing is not synchronous with the Javascript engine,
581 // and so the "DONE" signal above could be received before the renderer
582 // provides a frame with the expected content. http://crbug.com/405282
583 // 2. Avoiding test flakiness: On some platforms, the readback operation
584 // is allowed to transiently fail. The purpose of these tests is to
585 // confirm correct cropping/scaling behavior; and not that every
586 // readback must succeed. http://crbug.com/444237
587 uint32 last_frame_number
= 0;
589 // Wait for renderer to provide the next frame.
590 while (!GetRenderWidgetHost()->ScheduleComposite())
592 while (rwhv
->RendererFrameNumber() == last_frame_number
)
594 last_frame_number
= rwhv
->RendererFrameNumber();
596 // Request readback. The callbacks will examine the pixels in the
597 // SkBitmap/VideoFrame result if readback was successful.
598 readback_response_
= READBACK_NO_RESPONSE
;
599 base::RunLoop run_loop
;
601 // Allow pixel differences as long as we have the right idea.
602 SetAllowableError(0x10);
603 // Exclude the middle two columns which are blended between the two
606 gfx::Rect(output_size
.width() / 2 - 1, 0, 2, output_size
.height()));
608 scoped_refptr
<media::VideoFrame
> video_frame
=
609 media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12
,
610 output_size
, gfx::Rect(output_size
),
611 output_size
, base::TimeDelta());
613 base::Callback
<void(bool success
)> callback
=
614 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
615 ReadbackRequestCallbackForVideo
,
616 base::Unretained(this),
618 run_loop
.QuitClosure());
619 rwhv
->CopyFromCompositingSurfaceToVideoFrame(
620 copy_rect
, video_frame
, callback
);
622 if (IsDelegatedRendererEnabled()) {
623 if (!content::GpuDataManager::GetInstance()
624 ->CanUseGpuBrowserCompositor()) {
625 // Skia rendering can cause color differences, particularly in the
626 // middle two columns.
627 SetAllowableError(2);
628 SetExcludeRect(gfx::Rect(
629 output_size
.width() / 2 - 1, 0, 2, output_size
.height()));
633 ReadbackRequestCallback callback
=
634 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
635 ReadbackRequestCallbackTest
,
636 base::Unretained(this),
637 run_loop
.QuitClosure());
638 rwhv
->CopyFromCompositingSurface(
639 copy_rect
, output_size
, callback
, kN32_SkColorType
);
643 // If the readback operation did not provide a frame, log the reason
644 // to aid in future debugging. This information will also help determine
645 // whether the implementation is broken, or a test bot is in a bad state.
646 #define CASE_LOG_READBACK_WARNING(enum_value) \
648 LOG(WARNING) << "Readback attempt failed (render frame #" \
649 << last_frame_number << "). Reason: " #enum_value; \
651 switch (readback_response_
) {
652 case READBACK_SUCCESS
:
654 CASE_LOG_READBACK_WARNING(READBACK_FAILED
);
655 CASE_LOG_READBACK_WARNING(READBACK_SURFACE_UNAVAILABLE
);
656 CASE_LOG_READBACK_WARNING(READBACK_BITMAP_ALLOCATION_FAILURE
);
657 CASE_LOG_READBACK_WARNING(READBACK_NO_TEST_COLORS
);
658 CASE_LOG_READBACK_WARNING(READBACK_TO_VIDEO_FRAME_FAILED
);
661 << "Invalid readback response value: " << readback_response_
;
664 } while (readback_response_
!= READBACK_SUCCESS
);
667 // Sets up |bitmap| to have size |copy_size|. It floods the left half with
668 // #0ff and the right half with #ff0.
669 void SetupLeftRightBitmap(const gfx::Size
& copy_size
, SkBitmap
* bitmap
) {
670 bitmap
->allocN32Pixels(copy_size
.width(), copy_size
.height());
671 // Left half is #0ff.
672 bitmap
->eraseARGB(255, 0, 255, 255);
673 // Right half is #ff0.
675 SkAutoLockPixels
lock(*bitmap
);
676 for (int i
= 0; i
< copy_size
.width() / 2; ++i
) {
677 for (int j
= 0; j
< copy_size
.height(); ++j
) {
678 *(bitmap
->getAddr32(copy_size
.width() / 2 + i
, j
)) =
679 SkColorSetARGB(255, 255, 255, 0);
686 // Additional ReadbackResponse enum values only used within this test module,
687 // to distinguish readback exception cases further.
688 enum ExtraReadbackResponsesForTest
{
689 READBACK_NO_RESPONSE
= -1337,
690 READBACK_NO_TEST_COLORS
,
691 READBACK_TO_VIDEO_FRAME_FAILED
,
694 virtual bool ShouldContinueAfterTestURLLoad() {
699 // |readback_response_| is always a content::ReadbackResponse or
700 // ExtraReadbackResponsesForTest enum value.
701 int readback_response_
;
702 SkBitmap expected_copy_from_compositing_surface_bitmap_
;
703 int allowable_error_
;
704 gfx::Rect exclude_rect_
;
705 std::string test_url_
;
708 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
709 CopyFromCompositingSurface_Origin_Unscaled
) {
710 gfx::Rect
copy_rect(400, 300);
711 gfx::Size output_size
= copy_rect
.size();
712 gfx::Size
html_rect_size(400, 300);
713 bool video_frame
= false;
714 PerformTestWithLeftRightRects(html_rect_size
,
720 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
721 CopyFromCompositingSurface_Origin_Scaled
) {
722 gfx::Rect
copy_rect(400, 300);
723 gfx::Size
output_size(200, 100);
724 gfx::Size
html_rect_size(400, 300);
725 bool video_frame
= false;
726 PerformTestWithLeftRightRects(html_rect_size
,
732 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
733 CopyFromCompositingSurface_Cropped_Unscaled
) {
734 // Grab 60x60 pixels from the center of the tab contents.
735 gfx::Rect
copy_rect(400, 300);
736 copy_rect
= gfx::Rect(copy_rect
.CenterPoint() - gfx::Vector2d(30, 30),
738 gfx::Size output_size
= copy_rect
.size();
739 gfx::Size
html_rect_size(400, 300);
740 bool video_frame
= false;
741 PerformTestWithLeftRightRects(html_rect_size
,
747 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
748 CopyFromCompositingSurface_Cropped_Scaled
) {
749 // Grab 60x60 pixels from the center of the tab contents.
750 gfx::Rect
copy_rect(400, 300);
751 copy_rect
= gfx::Rect(copy_rect
.CenterPoint() - gfx::Vector2d(30, 30),
753 gfx::Size
output_size(20, 10);
754 gfx::Size
html_rect_size(400, 300);
755 bool video_frame
= false;
756 PerformTestWithLeftRightRects(html_rect_size
,
762 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
763 CopyFromCompositingSurface_ForVideoFrame
) {
764 // Grab 90x60 pixels from the center of the tab contents.
765 gfx::Rect
copy_rect(400, 300);
766 copy_rect
= gfx::Rect(copy_rect
.CenterPoint() - gfx::Vector2d(45, 30),
768 gfx::Size output_size
= copy_rect
.size();
769 gfx::Size
html_rect_size(400, 300);
770 bool video_frame
= true;
771 PerformTestWithLeftRightRects(html_rect_size
,
777 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture
,
778 CopyFromCompositingSurface_ForVideoFrame_Scaled
) {
779 // Grab 90x60 pixels from the center of the tab contents.
780 gfx::Rect
copy_rect(400, 300);
781 copy_rect
= gfx::Rect(copy_rect
.CenterPoint() - gfx::Vector2d(45, 30),
783 // Scale to 30 x 20 (preserve aspect ratio).
784 gfx::Size
output_size(30, 20);
785 gfx::Size
html_rect_size(400, 300);
786 bool video_frame
= true;
787 PerformTestWithLeftRightRects(html_rect_size
,
793 class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
794 : public CompositingRenderWidgetHostViewBrowserTestTabCapture
{
796 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI() {}
799 void SetUpCommandLine(base::CommandLine
* cmd
) override
{
800 CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd
);
801 cmd
->AppendSwitchASCII(switches::kForceDeviceScaleFactor
,
802 base::StringPrintf("%f", scale()));
805 bool ShouldContinueAfterTestURLLoad() override
{
806 // Short-circuit a pass for platforms where setting up high-DPI fails.
807 const float actual_scale_factor
=
808 GetScaleFactorForView(GetRenderWidgetHostView());
809 if (actual_scale_factor
!= scale()) {
810 LOG(WARNING
) << "Blindly passing this test; unable to force device scale "
811 << "factor: seems to be " << actual_scale_factor
812 << " but expected " << scale();
815 VLOG(1) << ("Successfully forced device scale factor. Moving forward with "
820 static float scale() { return 2.0f
; }
823 DISALLOW_COPY_AND_ASSIGN(
824 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
);
827 // NineImagePainter implementation crashes the process on Windows when this
828 // content_browsertest forces a device scale factor. http://crbug.com/399349
830 #define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
831 #define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
832 #define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
833 #define MAYBE_CopyToVideoFrame_EntireRegion \
834 DISABLED_CopyToVideoFrame_EntireRegion
835 #define MAYBE_CopyToVideoFrame_CenterRegion \
836 DISABLED_CopyToVideoFrame_CenterRegion
837 #define MAYBE_CopyToVideoFrame_ScaledResult \
838 DISABLED_CopyToVideoFrame_ScaledResult
840 #define MAYBE_CopyToBitmap_EntireRegion CopyToBitmap_EntireRegion
841 #define MAYBE_CopyToBitmap_CenterRegion CopyToBitmap_CenterRegion
842 #define MAYBE_CopyToBitmap_ScaledResult CopyToBitmap_ScaledResult
843 #define MAYBE_CopyToVideoFrame_EntireRegion CopyToVideoFrame_EntireRegion
844 #define MAYBE_CopyToVideoFrame_CenterRegion CopyToVideoFrame_CenterRegion
845 #define MAYBE_CopyToVideoFrame_ScaledResult CopyToVideoFrame_ScaledResult
848 IN_PROC_BROWSER_TEST_P(
849 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
850 MAYBE_CopyToBitmap_EntireRegion
) {
851 gfx::Size
html_rect_size(200, 150);
852 gfx::Rect
copy_rect(200, 150);
853 // Scale the output size so that, internally, scaling is not occurring.
854 gfx::Size output_size
=
855 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect
.size(), scale()));
856 bool video_frame
= false;
857 PerformTestWithLeftRightRects(html_rect_size
,
863 IN_PROC_BROWSER_TEST_P(
864 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
865 MAYBE_CopyToBitmap_CenterRegion
) {
866 gfx::Size
html_rect_size(200, 150);
867 // Grab 90x60 pixels from the center of the tab contents.
868 gfx::Rect copy_rect
=
869 gfx::Rect(gfx::Rect(html_rect_size
).CenterPoint() - gfx::Vector2d(45, 30),
871 // Scale the output size so that, internally, scaling is not occurring.
872 gfx::Size output_size
=
873 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect
.size(), scale()));
874 bool video_frame
= false;
875 PerformTestWithLeftRightRects(html_rect_size
,
881 IN_PROC_BROWSER_TEST_P(
882 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
883 MAYBE_CopyToBitmap_ScaledResult
) {
884 gfx::Size
html_rect_size(200, 100);
885 gfx::Rect
copy_rect(200, 100);
886 // Output is being down-scaled since output_size is in phyiscal pixels.
887 gfx::Size
output_size(200, 100);
888 bool video_frame
= false;
889 PerformTestWithLeftRightRects(html_rect_size
,
895 IN_PROC_BROWSER_TEST_P(
896 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
897 MAYBE_CopyToVideoFrame_EntireRegion
) {
898 gfx::Size
html_rect_size(200, 150);
899 gfx::Rect
copy_rect(200, 150);
900 // Scale the output size so that, internally, scaling is not occurring.
901 gfx::Size output_size
=
902 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect
.size(), scale()));
903 bool video_frame
= true;
904 PerformTestWithLeftRightRects(html_rect_size
,
910 IN_PROC_BROWSER_TEST_P(
911 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
912 MAYBE_CopyToVideoFrame_CenterRegion
) {
913 gfx::Size
html_rect_size(200, 150);
914 // Grab 90x60 pixels from the center of the tab contents.
915 gfx::Rect copy_rect
=
916 gfx::Rect(gfx::Rect(html_rect_size
).CenterPoint() - gfx::Vector2d(45, 30),
918 // Scale the output size so that, internally, scaling is not occurring.
919 gfx::Size output_size
=
920 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect
.size(), scale()));
921 bool video_frame
= true;
922 PerformTestWithLeftRightRects(html_rect_size
,
928 IN_PROC_BROWSER_TEST_P(
929 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
930 MAYBE_CopyToVideoFrame_ScaledResult
) {
931 gfx::Size
html_rect_size(200, 100);
932 gfx::Rect
copy_rect(200, 100);
933 // Output is being down-scaled since output_size is in phyiscal pixels.
934 gfx::Size
output_size(200, 100);
935 bool video_frame
= true;
936 PerformTestWithLeftRightRects(html_rect_size
,
942 #if defined(OS_CHROMEOS)
943 // On ChromeOS there is no software compositing.
944 static const auto kTestCompositingModes
= testing::Values(GL_COMPOSITING
);
946 static const auto kTestCompositingModes
=
947 testing::Values(GL_COMPOSITING
, SOFTWARE_COMPOSITING
);
950 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing
,
951 CompositingRenderWidgetHostViewBrowserTest
,
952 kTestCompositingModes
);
953 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing
,
954 CompositingRenderWidgetHostViewBrowserTestTabCapture
,
955 kTestCompositingModes
);
956 INSTANTIATE_TEST_CASE_P(
957 GLAndSoftwareCompositing
,
958 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
,
959 kTestCompositingModes
);
961 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
964 } // namespace content