DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_browsertest.cc
blob464b9157e3c350a5b64fbfef8e301114afadf149
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"
39 #if defined(OS_WIN)
40 #include "base/win/windows_version.h"
41 #include "ui/gfx/win/dpi.h"
42 #endif
44 namespace content {
45 namespace {
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)) { \
51 LOG(WARNING) \
52 << ("Blindly passing this test: This platform does not support " \
53 "forced compositing (or forced-disabled compositing) mode."); \
54 return; \
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
59 // mode disabled.
60 class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
61 public:
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
72 // current platform.
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 {
84 return frame_size_;
87 const base::FilePath& test_dir() const {
88 return test_dir_;
91 RenderViewHost* GetRenderViewHost() const {
92 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
93 CHECK(rvh);
94 return rvh;
97 RenderWidgetHostImpl* GetRenderWidgetHost() const {
98 RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From(
99 shell()->web_contents()->GetRenderWidgetHostView()->
100 GetRenderWidgetHost());
101 CHECK(rwh);
102 return rwh;
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) {
116 ++frames_captured_;
117 EXPECT_FALSE(bitmap.empty());
119 if (!quit_closure.is_null())
120 quit_closure.Run();
123 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API.
124 void FinishCopyFromCompositingSurface(const base::Closure& quit_closure,
125 bool frame_captured) {
126 ++callback_invoke_count_;
127 if (frame_captured)
128 ++frames_captured_;
129 if (!quit_closure.is_null())
130 quit_closure.Run();
133 // Callback when using frame subscriber API.
134 void FrameDelivered(
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_;
140 if (frame_captured)
141 ++frames_captured_;
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
152 // made.
153 int count_attempts = 0;
154 while (true) {
155 ++count_attempts;
156 base::RunLoop run_loop;
157 GetRenderViewHost()->CopyFromBackingStore(
158 gfx::Rect(),
159 frame_size(),
160 base::Bind(
161 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
162 base::Unretained(this),
163 run_loop.QuitClosure()),
164 kN32_SkColorType);
165 run_loop.Run();
167 if (frames_captured())
168 break;
169 else
170 GiveItSomeTime();
173 EXPECT_EQ(count_attempts, callback_invoke_count());
174 EXPECT_EQ(1, frames_captured());
177 protected:
178 // Waits until the source is available for copying.
179 void WaitForCopySourceReady() {
180 while (!GetRenderWidgetHostView()->IsSurfaceAvailableForCopy())
181 GiveItSomeTime();
184 // Run the current message loop for a short time without unwinding the current
185 // call stack.
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));
191 run_loop.Run();
194 private:
195 const gfx::Size frame_size_;
196 base::FilePath test_dir_;
197 int callback_invoke_count_;
198 int frames_captured_;
201 enum CompositingMode {
202 GL_COMPOSITING,
203 SOFTWARE_COMPOSITING,
206 class CompositingRenderWidgetHostViewBrowserTest
207 : public RenderWidgetHostViewBrowserTest,
208 public testing::WithParamInterface<CompositingMode> {
209 public:
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.";
231 return false;
235 // A frame might not be available yet. So, wait for it.
236 WaitForCopySourceReady();
237 return true;
240 private:
241 const CompositingMode compositing_mode_;
243 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewBrowserTest);
246 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
247 public:
248 FakeFrameSubscriber(
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())
263 return false;
264 *storage = media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100));
265 *callback = callback_;
266 callback_.Reset();
267 return true;
270 private:
271 DeliverFrameCallback callback_;
274 // Disable tests for Android and IOS as these platforms have incomplete
275 // implementation.
276 #if !defined(OS_ANDROID) && !defined(OS_IOS)
278 // The CopyFromBackingStore() API should work on all platforms when compositing
279 // is enabled.
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(
293 gfx::Rect(),
294 frame_size(),
295 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
296 base::Unretained(this),
297 run_loop.QuitClosure()),
298 kN32_SkColorType);
299 run_loop.Run();
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
306 // an async copy.
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()) {
312 LOG(WARNING) <<
313 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() "
314 "not supported on this platform.");
315 return;
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()));
325 run_loop.Run();
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.");
339 return;
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());
349 run_loop.Run();
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.");
363 return;
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()));
384 run_loop.Run();
386 EXPECT_EQ(2, callback_invoke_count());
387 EXPECT_EQ(2, frames_captured());
390 class CompositingRenderWidgetHostViewBrowserTestTabCapture
391 : public CompositingRenderWidgetHostViewBrowserTest {
392 public:
393 CompositingRenderWidgetHostViewBrowserTestTabCapture()
394 : readback_response_(READBACK_NO_RESPONSE),
395 allowable_error_(0),
396 test_url_("data:text/html,<!doctype html>") {}
398 void SetUp() override {
399 EnablePixelOutput();
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) {
408 quit_callback.Run();
409 return;
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
418 // flakiness.
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))
423 continue;
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;
436 break;
440 if (!contains_a_test_color) {
441 readback_response_ = READBACK_NO_TEST_COLORS;
442 quit_callback.Run();
443 return;
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);
453 int fails = 0;
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))
457 continue;
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);
493 quit_callback.Run();
496 void ReadbackRequestCallbackForVideo(
497 scoped_refptr<media::VideoFrame> video_frame,
498 base::Closure quit_callback,
499 bool result) {
500 if (!result) {
501 readback_response_ = READBACK_TO_VIDEO_FRAME_FAILED;
502 quit_callback.Run();
503 return;
506 media::SkCanvasVideoRenderer video_renderer;
508 SkBitmap bitmap;
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,
534 bool video_frame) {
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>"
539 "<div class='left'>"
540 " <div class='right'></div>"
541 "</div>"
542 "<style>"
543 "body { padding: 0; margin: 0; }"
544 ".left { position: absolute;"
545 " background: #0ff;"
546 " width: %dpx;"
547 " height: %dpx;"
549 ".right { position: absolute;"
550 " left: %dpx;"
551 " background: #ff0;"
552 " width: %dpx;"
553 " height: %dpx;"
555 "</style>"
556 "<script>"
557 " domAutomationController.setAutomationId(0);"
558 " domAutomationController.send(\"DONE\");"
559 "</script>",
560 box_size.width(),
561 box_size.height(),
562 box_size.width(),
563 box_size.width(),
564 box_size.height()));
566 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\"");
567 if (!ShouldContinueAfterTestURLLoad())
568 return;
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;
588 do {
589 // Wait for renderer to provide the next frame.
590 while (!GetRenderWidgetHost()->ScheduleComposite())
591 GiveItSomeTime();
592 while (rwhv->RendererFrameNumber() == last_frame_number)
593 GiveItSomeTime();
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;
600 if (video_frame) {
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
604 // sides.
605 SetExcludeRect(
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::VideoFrame::YV12,
610 output_size,
611 gfx::Rect(output_size),
612 output_size,
613 base::TimeDelta());
615 base::Callback<void(bool success)> callback =
616 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
617 ReadbackRequestCallbackForVideo,
618 base::Unretained(this),
619 video_frame,
620 run_loop.QuitClosure());
621 rwhv->CopyFromCompositingSurfaceToVideoFrame(
622 copy_rect, video_frame, callback);
623 } else {
624 if (IsDelegatedRendererEnabled()) {
625 if (!content::GpuDataManager::GetInstance()
626 ->CanUseGpuBrowserCompositor()) {
627 // Skia rendering can cause color differences, particularly in the
628 // middle two columns.
629 SetAllowableError(2);
630 SetExcludeRect(gfx::Rect(
631 output_size.width() / 2 - 1, 0, 2, output_size.height()));
635 ReadbackRequestCallback callback =
636 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
637 ReadbackRequestCallbackTest,
638 base::Unretained(this),
639 run_loop.QuitClosure());
640 rwhv->CopyFromCompositingSurface(
641 copy_rect, output_size, callback, kN32_SkColorType);
643 run_loop.Run();
645 // If the readback operation did not provide a frame, log the reason
646 // to aid in future debugging. This information will also help determine
647 // whether the implementation is broken, or a test bot is in a bad state.
648 #define CASE_LOG_READBACK_WARNING(enum_value) \
649 case enum_value: \
650 LOG(WARNING) << "Readback attempt failed (render frame #" \
651 << last_frame_number << "). Reason: " #enum_value; \
652 break
653 switch (readback_response_) {
654 case READBACK_SUCCESS:
655 break;
656 CASE_LOG_READBACK_WARNING(READBACK_FAILED);
657 CASE_LOG_READBACK_WARNING(READBACK_SURFACE_UNAVAILABLE);
658 CASE_LOG_READBACK_WARNING(READBACK_BITMAP_ALLOCATION_FAILURE);
659 CASE_LOG_READBACK_WARNING(READBACK_NO_TEST_COLORS);
660 CASE_LOG_READBACK_WARNING(READBACK_TO_VIDEO_FRAME_FAILED);
661 default:
662 LOG(ERROR)
663 << "Invalid readback response value: " << readback_response_;
664 NOTREACHED();
666 } while (readback_response_ != READBACK_SUCCESS);
669 // Sets up |bitmap| to have size |copy_size|. It floods the left half with
670 // #0ff and the right half with #ff0.
671 void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) {
672 bitmap->allocN32Pixels(copy_size.width(), copy_size.height());
673 // Left half is #0ff.
674 bitmap->eraseARGB(255, 0, 255, 255);
675 // Right half is #ff0.
677 SkAutoLockPixels lock(*bitmap);
678 for (int i = 0; i < copy_size.width() / 2; ++i) {
679 for (int j = 0; j < copy_size.height(); ++j) {
680 *(bitmap->getAddr32(copy_size.width() / 2 + i, j)) =
681 SkColorSetARGB(255, 255, 255, 0);
687 protected:
688 // Additional ReadbackResponse enum values only used within this test module,
689 // to distinguish readback exception cases further.
690 enum ExtraReadbackResponsesForTest {
691 READBACK_NO_RESPONSE = -1337,
692 READBACK_NO_TEST_COLORS,
693 READBACK_TO_VIDEO_FRAME_FAILED,
696 virtual bool ShouldContinueAfterTestURLLoad() {
697 return true;
700 private:
701 // |readback_response_| is always a content::ReadbackResponse or
702 // ExtraReadbackResponsesForTest enum value.
703 int readback_response_;
704 SkBitmap expected_copy_from_compositing_surface_bitmap_;
705 int allowable_error_;
706 gfx::Rect exclude_rect_;
707 std::string test_url_;
710 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
711 CopyFromCompositingSurface_Origin_Unscaled) {
712 gfx::Rect copy_rect(400, 300);
713 gfx::Size output_size = copy_rect.size();
714 gfx::Size html_rect_size(400, 300);
715 bool video_frame = false;
716 PerformTestWithLeftRightRects(html_rect_size,
717 copy_rect,
718 output_size,
719 video_frame);
722 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
723 CopyFromCompositingSurface_Origin_Scaled) {
724 gfx::Rect copy_rect(400, 300);
725 gfx::Size output_size(200, 100);
726 gfx::Size html_rect_size(400, 300);
727 bool video_frame = false;
728 PerformTestWithLeftRightRects(html_rect_size,
729 copy_rect,
730 output_size,
731 video_frame);
734 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
735 CopyFromCompositingSurface_Cropped_Unscaled) {
736 // Grab 60x60 pixels from the center of the tab contents.
737 gfx::Rect copy_rect(400, 300);
738 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
739 gfx::Size(60, 60));
740 gfx::Size output_size = copy_rect.size();
741 gfx::Size html_rect_size(400, 300);
742 bool video_frame = false;
743 PerformTestWithLeftRightRects(html_rect_size,
744 copy_rect,
745 output_size,
746 video_frame);
749 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
750 CopyFromCompositingSurface_Cropped_Scaled) {
751 // Grab 60x60 pixels from the center of the tab contents.
752 gfx::Rect copy_rect(400, 300);
753 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
754 gfx::Size(60, 60));
755 gfx::Size output_size(20, 10);
756 gfx::Size html_rect_size(400, 300);
757 bool video_frame = false;
758 PerformTestWithLeftRightRects(html_rect_size,
759 copy_rect,
760 output_size,
761 video_frame);
764 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
765 CopyFromCompositingSurface_ForVideoFrame) {
766 // Grab 90x60 pixels from the center of the tab contents.
767 gfx::Rect copy_rect(400, 300);
768 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
769 gfx::Size(90, 60));
770 gfx::Size output_size = copy_rect.size();
771 gfx::Size html_rect_size(400, 300);
772 bool video_frame = true;
773 PerformTestWithLeftRightRects(html_rect_size,
774 copy_rect,
775 output_size,
776 video_frame);
779 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
780 CopyFromCompositingSurface_ForVideoFrame_Scaled) {
781 // Grab 90x60 pixels from the center of the tab contents.
782 gfx::Rect copy_rect(400, 300);
783 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
784 gfx::Size(90, 60));
785 // Scale to 30 x 20 (preserve aspect ratio).
786 gfx::Size output_size(30, 20);
787 gfx::Size html_rect_size(400, 300);
788 bool video_frame = true;
789 PerformTestWithLeftRightRects(html_rect_size,
790 copy_rect,
791 output_size,
792 video_frame);
795 class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
796 : public CompositingRenderWidgetHostViewBrowserTestTabCapture {
797 public:
798 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI() {}
800 protected:
801 void SetUpCommandLine(base::CommandLine* cmd) override {
802 CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd);
803 cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
804 base::StringPrintf("%f", scale()));
807 bool ShouldContinueAfterTestURLLoad() override {
808 // Short-circuit a pass for platforms where setting up high-DPI fails.
809 const float actual_scale_factor =
810 GetScaleFactorForView(GetRenderWidgetHostView());
811 if (actual_scale_factor != scale()) {
812 LOG(WARNING) << "Blindly passing this test; unable to force device scale "
813 << "factor: seems to be " << actual_scale_factor
814 << " but expected " << scale();
815 return false;
817 VLOG(1) << ("Successfully forced device scale factor. Moving forward with "
818 "this test! :-)");
819 return true;
822 static float scale() { return 2.0f; }
824 private:
825 DISALLOW_COPY_AND_ASSIGN(
826 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI);
829 // NineImagePainter implementation crashes the process on Windows when this
830 // content_browsertest forces a device scale factor. http://crbug.com/399349
831 #if defined(OS_WIN)
832 #define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
833 #define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
834 #define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
835 #define MAYBE_CopyToVideoFrame_EntireRegion \
836 DISABLED_CopyToVideoFrame_EntireRegion
837 #define MAYBE_CopyToVideoFrame_CenterRegion \
838 DISABLED_CopyToVideoFrame_CenterRegion
839 #define MAYBE_CopyToVideoFrame_ScaledResult \
840 DISABLED_CopyToVideoFrame_ScaledResult
841 #else
842 #define MAYBE_CopyToBitmap_EntireRegion CopyToBitmap_EntireRegion
843 #define MAYBE_CopyToBitmap_CenterRegion CopyToBitmap_CenterRegion
844 #define MAYBE_CopyToBitmap_ScaledResult CopyToBitmap_ScaledResult
845 #define MAYBE_CopyToVideoFrame_EntireRegion CopyToVideoFrame_EntireRegion
846 #define MAYBE_CopyToVideoFrame_CenterRegion CopyToVideoFrame_CenterRegion
847 #define MAYBE_CopyToVideoFrame_ScaledResult CopyToVideoFrame_ScaledResult
848 #endif
850 IN_PROC_BROWSER_TEST_P(
851 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
852 MAYBE_CopyToBitmap_EntireRegion) {
853 gfx::Size html_rect_size(200, 150);
854 gfx::Rect copy_rect(200, 150);
855 // Scale the output size so that, internally, scaling is not occurring.
856 gfx::Size output_size =
857 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
858 bool video_frame = false;
859 PerformTestWithLeftRightRects(html_rect_size,
860 copy_rect,
861 output_size,
862 video_frame);
865 IN_PROC_BROWSER_TEST_P(
866 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
867 MAYBE_CopyToBitmap_CenterRegion) {
868 gfx::Size html_rect_size(200, 150);
869 // Grab 90x60 pixels from the center of the tab contents.
870 gfx::Rect copy_rect =
871 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
872 gfx::Size(90, 60));
873 // Scale the output size so that, internally, scaling is not occurring.
874 gfx::Size output_size =
875 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
876 bool video_frame = false;
877 PerformTestWithLeftRightRects(html_rect_size,
878 copy_rect,
879 output_size,
880 video_frame);
883 IN_PROC_BROWSER_TEST_P(
884 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
885 MAYBE_CopyToBitmap_ScaledResult) {
886 gfx::Size html_rect_size(200, 100);
887 gfx::Rect copy_rect(200, 100);
888 // Output is being down-scaled since output_size is in phyiscal pixels.
889 gfx::Size output_size(200, 100);
890 bool video_frame = false;
891 PerformTestWithLeftRightRects(html_rect_size,
892 copy_rect,
893 output_size,
894 video_frame);
897 IN_PROC_BROWSER_TEST_P(
898 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
899 MAYBE_CopyToVideoFrame_EntireRegion) {
900 gfx::Size html_rect_size(200, 150);
901 gfx::Rect copy_rect(200, 150);
902 // Scale the output size so that, internally, scaling is not occurring.
903 gfx::Size output_size =
904 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
905 bool video_frame = true;
906 PerformTestWithLeftRightRects(html_rect_size,
907 copy_rect,
908 output_size,
909 video_frame);
912 IN_PROC_BROWSER_TEST_P(
913 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
914 MAYBE_CopyToVideoFrame_CenterRegion) {
915 gfx::Size html_rect_size(200, 150);
916 // Grab 90x60 pixels from the center of the tab contents.
917 gfx::Rect copy_rect =
918 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
919 gfx::Size(90, 60));
920 // Scale the output size so that, internally, scaling is not occurring.
921 gfx::Size output_size =
922 gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
923 bool video_frame = true;
924 PerformTestWithLeftRightRects(html_rect_size,
925 copy_rect,
926 output_size,
927 video_frame);
930 IN_PROC_BROWSER_TEST_P(
931 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
932 MAYBE_CopyToVideoFrame_ScaledResult) {
933 gfx::Size html_rect_size(200, 100);
934 gfx::Rect copy_rect(200, 100);
935 // Output is being down-scaled since output_size is in phyiscal pixels.
936 gfx::Size output_size(200, 100);
937 bool video_frame = true;
938 PerformTestWithLeftRightRects(html_rect_size,
939 copy_rect,
940 output_size,
941 video_frame);
944 #if defined(OS_CHROMEOS)
945 // On ChromeOS there is no software compositing.
946 static const auto kTestCompositingModes = testing::Values(GL_COMPOSITING);
947 #else
948 static const auto kTestCompositingModes =
949 testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING);
950 #endif
952 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
953 CompositingRenderWidgetHostViewBrowserTest,
954 kTestCompositingModes);
955 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
956 CompositingRenderWidgetHostViewBrowserTestTabCapture,
957 kTestCompositingModes);
958 INSTANTIATE_TEST_CASE_P(
959 GLAndSoftwareCompositing,
960 CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
961 kTestCompositingModes);
963 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
965 } // namespace
966 } // namespace content