IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_browsertest.cc
blob22bc6f216f7d8ae5e274b5a5b9f9ea77aa2c99f6
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/command_line.h"
6 #include "base/message_loop/message_loop_proxy.h"
7 #include "base/path_service.h"
8 #include "base/run_loop.h"
9 #include "content/browser/gpu/compositor_util.h"
10 #include "content/browser/gpu/gpu_data_manager_impl.h"
11 #include "content/browser/renderer_host/dip_util.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
14 #include "content/port/browser/render_widget_host_view_port.h"
15 #include "content/public/browser/gpu_data_manager.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/content_paths.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/common/url_constants.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/shell/browser/shell.h"
23 #include "content/test/content_browser_test.h"
24 #include "content/test/content_browser_test_utils.h"
25 #include "media/base/video_frame.h"
26 #include "media/filters/skcanvas_video_renderer.h"
27 #include "net/base/net_util.h"
28 #include "third_party/skia/include/core/SkBitmap.h"
29 #include "third_party/skia/include/core/SkBitmapDevice.h"
30 #include "third_party/skia/include/core/SkCanvas.h"
31 #include "ui/base/ui_base_switches.h"
32 #include "ui/gfx/size_conversions.h"
33 #include "ui/gfx/switches.h"
34 #include "ui/gl/gl_switches.h"
36 #if defined(OS_MACOSX)
37 #include "ui/gl/io_surface_support_mac.h"
38 #endif
40 #if defined(OS_WIN)
41 #include "base/win/windows_version.h"
42 #include "ui/gfx/win/dpi.h"
43 #endif
45 namespace content {
46 namespace {
48 // Convenience macro: Short-circuit a pass for the tests where platform support
49 // for forced-compositing mode (or disabled-compositing mode) is lacking.
50 #define SET_UP_SURFACE_OR_PASS_TEST(wait_message) \
51 if (!SetUpSourceSurface(wait_message)) { \
52 LOG(WARNING) \
53 << ("Blindly passing this test: This platform does not support " \
54 "forced compositing (or forced-disabled compositing) mode."); \
55 return; \
58 // Convenience macro: Short-circuit a pass for platforms where setting up
59 // high-DPI fails.
60 #define PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(factor) \
61 if (ui::GetImageScale( \
62 GetScaleFactorForView(GetRenderWidgetHostViewPort())) != factor) { \
63 LOG(WARNING) << "Blindly passing this test: failed to set up " \
64 "scale factor: " << factor; \
65 return false; \
68 // Common base class for browser tests. This is subclassed twice: Once to test
69 // the browser in forced-compositing mode, and once to test with compositing
70 // mode disabled.
71 class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
72 public:
73 RenderWidgetHostViewBrowserTest()
74 : frame_size_(400, 300),
75 callback_invoke_count_(0),
76 frames_captured_(0) {}
78 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
79 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
80 ContentBrowserTest::SetUpInProcessBrowserTestFixture();
83 // Attempts to set up the source surface. Returns false if unsupported on the
84 // current platform.
85 virtual bool SetUpSourceSurface(const char* wait_message) = 0;
87 int callback_invoke_count() const {
88 return callback_invoke_count_;
91 int frames_captured() const {
92 return frames_captured_;
95 const gfx::Size& frame_size() const {
96 return frame_size_;
99 const base::FilePath& test_dir() const {
100 return test_dir_;
103 RenderViewHost* GetRenderViewHost() const {
104 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
105 CHECK(rvh);
106 return rvh;
109 RenderWidgetHostImpl* GetRenderWidgetHost() const {
110 RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From(
111 shell()->web_contents()->GetRenderWidgetHostView()->
112 GetRenderWidgetHost());
113 CHECK(rwh);
114 return rwh;
117 RenderWidgetHostViewPort* GetRenderWidgetHostViewPort() const {
118 RenderWidgetHostViewPort* const view =
119 RenderWidgetHostViewPort::FromRWHV(GetRenderViewHost()->GetView());
120 CHECK(view);
121 return view;
124 // Callback when using CopyFromBackingStore() API.
125 void FinishCopyFromBackingStore(const base::Closure& quit_closure,
126 bool frame_captured,
127 const SkBitmap& bitmap) {
128 ++callback_invoke_count_;
129 if (frame_captured) {
130 ++frames_captured_;
131 EXPECT_FALSE(bitmap.empty());
133 if (!quit_closure.is_null())
134 quit_closure.Run();
137 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API.
138 void FinishCopyFromCompositingSurface(const base::Closure& quit_closure,
139 bool frame_captured) {
140 ++callback_invoke_count_;
141 if (frame_captured)
142 ++frames_captured_;
143 if (!quit_closure.is_null())
144 quit_closure.Run();
147 // Callback when using frame subscriber API.
148 void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop,
149 base::Closure quit_closure,
150 base::TimeTicks timestamp,
151 bool frame_captured) {
152 ++callback_invoke_count_;
153 if (frame_captured)
154 ++frames_captured_;
155 if (!quit_closure.is_null())
156 loop->PostTask(FROM_HERE, quit_closure);
159 // Copy one frame using the CopyFromBackingStore API.
160 void RunBasicCopyFromBackingStoreTest() {
161 SET_UP_SURFACE_OR_PASS_TEST(NULL);
163 // Repeatedly call CopyFromBackingStore() since, on some platforms (e.g.,
164 // Windows), the operation will fail until the first "present" has been
165 // made.
166 int count_attempts = 0;
167 while (true) {
168 ++count_attempts;
169 base::RunLoop run_loop;
170 GetRenderViewHost()->CopyFromBackingStore(
171 gfx::Rect(),
172 frame_size(),
173 base::Bind(
174 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
175 base::Unretained(this),
176 run_loop.QuitClosure()));
177 run_loop.Run();
179 if (frames_captured())
180 break;
181 else
182 GiveItSomeTime();
185 EXPECT_EQ(count_attempts, callback_invoke_count());
186 EXPECT_EQ(1, frames_captured());
189 protected:
190 // Waits until the source is available for copying.
191 void WaitForCopySourceReady() {
192 while (!GetRenderWidgetHostViewPort()->IsSurfaceAvailableForCopy())
193 GiveItSomeTime();
196 // Run the current message loop for a short time without unwinding the current
197 // call stack.
198 static void GiveItSomeTime() {
199 base::RunLoop run_loop;
200 base::MessageLoop::current()->PostDelayedTask(
201 FROM_HERE,
202 run_loop.QuitClosure(),
203 base::TimeDelta::FromMilliseconds(10));
204 run_loop.Run();
207 private:
208 const gfx::Size frame_size_;
209 base::FilePath test_dir_;
210 int callback_invoke_count_;
211 int frames_captured_;
214 enum CompositingMode {
215 GL_COMPOSITING,
216 SOFTWARE_COMPOSITING,
219 class CompositingRenderWidgetHostViewBrowserTest
220 : public RenderWidgetHostViewBrowserTest,
221 public testing::WithParamInterface<CompositingMode> {
222 public:
223 explicit CompositingRenderWidgetHostViewBrowserTest()
224 : compositing_mode_(GetParam()) {}
226 virtual void SetUp() OVERRIDE {
227 if (compositing_mode_ == SOFTWARE_COMPOSITING) {
228 UseSoftwareCompositing();
229 } else {
230 // We expect real pixel output for these tests.
231 UseRealGLContexts();
233 #if defined(OS_WIN) && !defined(USE_AURA)
234 // On legacy windows, these tests need real GL bindings to pass.
235 UseRealGLBindings();
236 #endif
239 RenderWidgetHostViewBrowserTest::SetUp();
242 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
243 // Note: Not appending kForceCompositingMode switch here, since not all bots
244 // support compositing. Some bots will run with compositing on, and others
245 // won't. Therefore, the call to SetUpSourceSurface() later on will detect
246 // whether compositing mode is actually on or not. If not, the tests will
247 // pass blindly, logging a warning message, since we cannot test what the
248 // platform/implementation does not support.
249 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line);
252 virtual GURL TestUrl() {
253 return net::FilePathToFileURL(
254 test_dir().AppendASCII("rwhv_compositing_animation.html"));
257 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE {
258 if (!IsForceCompositingModeEnabled())
259 return false; // See comment in SetUpCommandLine().
260 #if defined(OS_MACOSX)
261 CHECK(IOSurfaceSupport::Initialize());
262 #endif
264 content::DOMMessageQueue message_queue;
265 NavigateToURL(shell(), TestUrl());
266 if (wait_message != NULL) {
267 std::string result(wait_message);
268 if (!message_queue.WaitForMessage(&result)) {
269 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed.";
270 return false;
274 #if !defined(USE_AURA)
275 if (!GetRenderWidgetHost()->is_accelerated_compositing_active())
276 return false; // Renderer did not turn on accelerated compositing.
277 #endif
279 // Using accelerated compositing, but a compositing surface might not be
280 // available yet. So, wait for it.
281 WaitForCopySourceReady();
282 return true;
285 private:
286 const CompositingMode compositing_mode_;
288 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewBrowserTest);
291 class NonCompositingRenderWidgetHostViewBrowserTest
292 : public RenderWidgetHostViewBrowserTest {
293 public:
294 NonCompositingRenderWidgetHostViewBrowserTest() {}
296 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
297 // Note: Appending the kDisableAcceleratedCompositing switch here, but there
298 // are some builds that only use compositing and will ignore this switch.
299 // Therefore, the call to SetUpSourceSurface() later on will detect whether
300 // compositing mode is actually off. If it's on, the tests will pass
301 // blindly, logging a warning message, since we cannot test what the
302 // platform/implementation does not support.
303 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
304 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line);
307 virtual GURL TestUrl() {
308 return GURL(kAboutBlankURL);
311 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE {
312 if (IsForceCompositingModeEnabled())
313 return false; // See comment in SetUpCommandLine().
315 content::DOMMessageQueue message_queue;
316 NavigateToURL(shell(), TestUrl());
317 if (wait_message != NULL) {
318 std::string result(wait_message);
319 if (!message_queue.WaitForMessage(&result)) {
320 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed.";
321 return false;
325 WaitForCopySourceReady();
326 // Return whether the renderer left accelerated compositing turned off.
327 return !GetRenderWidgetHost()->is_accelerated_compositing_active();
330 private:
331 DISALLOW_COPY_AND_ASSIGN(NonCompositingRenderWidgetHostViewBrowserTest);
334 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
335 public:
336 FakeFrameSubscriber(
337 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback)
338 : callback_(callback) {
341 virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
342 scoped_refptr<media::VideoFrame>* storage,
343 DeliverFrameCallback* callback) OVERRIDE {
344 // Only allow one frame capture to be made. Otherwise, the compositor could
345 // start multiple captures, unbounded, and eventually its own limiter logic
346 // will begin invoking |callback| with a |false| result. This flakes out
347 // the unit tests, since they receive a "failed" callback before the later
348 // "success" callbacks.
349 if (callback_.is_null())
350 return false;
351 *storage = media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100));
352 *callback = callback_;
353 callback_.Reset();
354 return true;
357 private:
358 DeliverFrameCallback callback_;
361 // Disable tests for Android and IOS as these platforms have incomplete
362 // implementation.
363 #if !defined(OS_ANDROID) && !defined(OS_IOS)
365 // The CopyFromBackingStore() API should work on all platforms when compositing
366 // is enabled.
367 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
368 CopyFromBackingStore) {
369 RunBasicCopyFromBackingStoreTest();
372 // The CopyFromBackingStore() API should work on all platforms when compositing
373 // is disabled.
374 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest,
375 CopyFromBackingStore) {
376 RunBasicCopyFromBackingStoreTest();
379 // Tests that the callback passed to CopyFromBackingStore is always called,
380 // even when the RenderWidgetHost is deleting in the middle of an async copy.
381 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
382 CopyFromBackingStore_CallbackDespiteDelete) {
383 SET_UP_SURFACE_OR_PASS_TEST(NULL);
385 base::RunLoop run_loop;
386 GetRenderViewHost()->CopyFromBackingStore(
387 gfx::Rect(),
388 frame_size(),
389 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
390 base::Unretained(this), run_loop.QuitClosure()));
391 // Delete the surface before the callback is run.
392 GetRenderWidgetHostViewPort()->AcceleratedSurfaceRelease();
393 run_loop.Run();
395 EXPECT_EQ(1, callback_invoke_count());
398 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
399 // always called, even when the RenderWidgetHost is deleting in the middle of
400 // an async copy.
402 // Test is flaky on Win Aura. http://crbug.com/276783
403 #if (defined(OS_WIN) && defined(USE_AURA)) || \
404 (defined(OS_CHROMEOS) && !defined(NDEBUG))
405 #define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
406 DISABLED_CopyFromCompositingSurface_CallbackDespiteDelete
407 #else
408 #define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
409 CopyFromCompositingSurface_CallbackDespiteDelete
410 #endif
411 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
412 MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete) {
413 SET_UP_SURFACE_OR_PASS_TEST(NULL);
414 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
415 if (!view->CanCopyToVideoFrame()) {
416 LOG(WARNING) <<
417 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() "
418 "not supported on this platform.");
419 return;
422 base::RunLoop run_loop;
423 scoped_refptr<media::VideoFrame> dest =
424 media::VideoFrame::CreateBlackFrame(frame_size());
425 view->CopyFromCompositingSurfaceToVideoFrame(
426 gfx::Rect(view->GetViewBounds().size()), dest, base::Bind(
427 &RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface,
428 base::Unretained(this), run_loop.QuitClosure()));
429 // Delete the surface before the callback is run.
430 view->AcceleratedSurfaceRelease();
431 run_loop.Run();
433 EXPECT_EQ(1, callback_invoke_count());
436 // With compositing turned off, no platforms should support the
437 // CopyFromCompositingSurfaceToVideoFrame() API.
438 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest,
439 CopyFromCompositingSurfaceToVideoFrameCallbackTest) {
440 SET_UP_SURFACE_OR_PASS_TEST(NULL);
441 EXPECT_FALSE(GetRenderWidgetHostViewPort()->CanCopyToVideoFrame());
444 // Test basic frame subscription functionality. We subscribe, and then run
445 // until at least one DeliverFrameCallback has been invoked.
446 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
447 FrameSubscriberTest) {
448 SET_UP_SURFACE_OR_PASS_TEST(NULL);
449 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
450 if (!view->CanSubscribeFrame()) {
451 LOG(WARNING) << ("Blindly passing this test: Frame subscription not "
452 "supported on this platform.");
453 return;
456 base::RunLoop run_loop;
457 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
458 new FakeFrameSubscriber(
459 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
460 base::Unretained(this),
461 base::MessageLoopProxy::current(),
462 run_loop.QuitClosure())));
463 view->BeginFrameSubscription(subscriber.Pass());
464 run_loop.Run();
465 view->EndFrameSubscription();
467 EXPECT_LE(1, callback_invoke_count());
468 EXPECT_LE(1, frames_captured());
471 // Test that we can copy twice from an accelerated composited page.
472 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) {
473 SET_UP_SURFACE_OR_PASS_TEST(NULL);
474 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
475 if (!view->CanCopyToVideoFrame()) {
476 LOG(WARNING) << ("Blindly passing this test: "
477 "CopyFromCompositingSurfaceToVideoFrame() not supported "
478 "on this platform.");
479 return;
482 base::RunLoop run_loop;
483 scoped_refptr<media::VideoFrame> first_output =
484 media::VideoFrame::CreateBlackFrame(frame_size());
485 ASSERT_TRUE(first_output.get());
486 scoped_refptr<media::VideoFrame> second_output =
487 media::VideoFrame::CreateBlackFrame(frame_size());
488 ASSERT_TRUE(second_output.get());
489 view->CopyFromCompositingSurfaceToVideoFrame(
490 gfx::Rect(view->GetViewBounds().size()),
491 first_output,
492 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
493 base::Unretained(this),
494 base::MessageLoopProxy::current(),
495 base::Closure(),
496 base::TimeTicks::Now()));
497 view->CopyFromCompositingSurfaceToVideoFrame(
498 gfx::Rect(view->GetViewBounds().size()),
499 second_output,
500 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
501 base::Unretained(this),
502 base::MessageLoopProxy::current(),
503 run_loop.QuitClosure(),
504 base::TimeTicks::Now()));
505 run_loop.Run();
507 EXPECT_EQ(2, callback_invoke_count());
508 EXPECT_EQ(2, frames_captured());
511 class CompositingRenderWidgetHostViewBrowserTestTabCapture
512 : public CompositingRenderWidgetHostViewBrowserTest {
513 public:
514 CompositingRenderWidgetHostViewBrowserTestTabCapture()
515 : expected_copy_from_compositing_surface_result_(false),
516 allowable_error_(0),
517 test_url_("data:text/html,<!doctype html>") {}
519 void CopyFromCompositingSurfaceCallback(base::Closure quit_callback,
520 bool result,
521 const SkBitmap& bitmap) {
522 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
523 if (!result) {
524 quit_callback.Run();
525 return;
528 const SkBitmap& expected_bitmap =
529 expected_copy_from_compositing_surface_bitmap_;
530 EXPECT_EQ(expected_bitmap.width(), bitmap.width());
531 EXPECT_EQ(expected_bitmap.height(), bitmap.height());
532 EXPECT_EQ(expected_bitmap.config(), bitmap.config());
533 SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
534 SkAutoLockPixels bitmap_lock(bitmap);
535 int fails = 0;
536 for (int i = 0; i < bitmap.width() && fails < 10; ++i) {
537 for (int j = 0; j < bitmap.height() && fails < 10; ++j) {
538 if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j))
539 continue;
541 SkColor expected_color = expected_bitmap.getColor(i, j);
542 SkColor color = bitmap.getColor(i, j);
543 int expected_alpha = SkColorGetA(expected_color);
544 int alpha = SkColorGetA(color);
545 int expected_red = SkColorGetR(expected_color);
546 int red = SkColorGetR(color);
547 int expected_green = SkColorGetG(expected_color);
548 int green = SkColorGetG(color);
549 int expected_blue = SkColorGetB(expected_color);
550 int blue = SkColorGetB(color);
551 EXPECT_NEAR(expected_alpha, alpha, allowable_error_)
552 << "expected_color: " << std::hex << expected_color
553 << " color: " << color
554 << " Failed at " << std::dec << i << ", " << j
555 << " Failure " << ++fails;
556 EXPECT_NEAR(expected_red, red, allowable_error_)
557 << "expected_color: " << std::hex << expected_color
558 << " color: " << color
559 << " Failed at " << std::dec << i << ", " << j
560 << " Failure " << ++fails;
561 EXPECT_NEAR(expected_green, green, allowable_error_)
562 << "expected_color: " << std::hex << expected_color
563 << " color: " << color
564 << " Failed at " << std::dec << i << ", " << j
565 << " Failure " << ++fails;
566 EXPECT_NEAR(expected_blue, blue, allowable_error_)
567 << "expected_color: " << std::hex << expected_color
568 << " color: " << color
569 << " Failed at " << std::dec << i << ", " << j
570 << " Failure " << ++fails;
573 EXPECT_LT(fails, 10);
575 quit_callback.Run();
578 void CopyFromCompositingSurfaceCallbackForVideo(
579 scoped_refptr<media::VideoFrame> video_frame,
580 base::Closure quit_callback,
581 bool result) {
582 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
583 if (!result) {
584 quit_callback.Run();
585 return;
588 media::SkCanvasVideoRenderer video_renderer;
590 SkBitmap bitmap;
591 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
592 video_frame->visible_rect().width(),
593 video_frame->visible_rect().height(),
594 0, kOpaque_SkAlphaType);
595 bitmap.allocPixels();
597 SkBitmapDevice device(bitmap);
598 SkCanvas canvas(&device);
600 video_renderer.Paint(video_frame.get(),
601 &canvas,
602 video_frame->visible_rect(),
603 0xff);
605 CopyFromCompositingSurfaceCallback(quit_callback,
606 result,
607 bitmap);
610 void SetExpectedCopyFromCompositingSurfaceResult(bool result,
611 const SkBitmap& bitmap) {
612 expected_copy_from_compositing_surface_result_ = result;
613 expected_copy_from_compositing_surface_bitmap_ = bitmap;
616 void SetAllowableError(int amount) { allowable_error_ = amount; }
617 void SetExcludeRect(gfx::Rect exclude) { exclude_rect_ = exclude; }
619 virtual GURL TestUrl() OVERRIDE {
620 return GURL(test_url_);
623 void SetTestUrl(std::string url) { test_url_ = url; }
625 // Loads a page two boxes side-by-side, each half the width of
626 // |html_rect_size|, and with different background colors. The test then
627 // copies from |copy_rect| region of the page into a bitmap of size
628 // |output_size|, and compares that with a bitmap of size
629 // |expected_bitmap_size|.
630 // Note that |output_size| may not have the same size as |copy_rect| (e.g.
631 // when the output is scaled). Also note that |expected_bitmap_size| may not
632 // be the same as |output_size| (e.g. when the device scale factor is not 1).
633 void PerformTestWithLeftRightRects(const gfx::Size& html_rect_size,
634 const gfx::Rect& copy_rect,
635 const gfx::Size& output_size,
636 const gfx::Size& expected_bitmap_size,
637 bool video_frame) {
638 const gfx::Size box_size(html_rect_size.width() / 2,
639 html_rect_size.height());
640 SetTestUrl(base::StringPrintf(
641 "data:text/html,<!doctype html>"
642 "<div class='left'>"
643 " <div class='right'></div>"
644 "</div>"
645 "<style>"
646 "body { padding: 0; margin: 0; }"
647 ".left { position: absolute;"
648 " background: #0ff;"
649 " width: %dpx;"
650 " height: %dpx;"
652 ".right { position: absolute;"
653 " left: %dpx;"
654 " background: #ff0;"
655 " width: %dpx;"
656 " height: %dpx;"
658 "</style>"
659 "<script>"
660 " domAutomationController.setAutomationId(0);"
661 " domAutomationController.send(\"DONE\");"
662 "</script>",
663 box_size.width(),
664 box_size.height(),
665 box_size.width(),
666 box_size.width(),
667 box_size.height()));
669 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\"");
670 if (!ShouldContinueAfterTestURLLoad())
671 return;
673 RenderWidgetHostViewPort* rwhvp = GetRenderWidgetHostViewPort();
674 if (video_frame && !rwhvp->CanCopyToVideoFrame()) {
675 // This should only happen on Mac when using the software compositor.
676 // Otherwise, raise an error. This can be removed when Mac is moved to a
677 // browser compositor.
678 // http://crbug.com/314190
679 #if defined(OS_MACOSX)
680 if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) {
681 LOG(WARNING) << ("Blindly passing this test because copying to "
682 "video frames is not supported on this platform.");
683 return;
685 #endif
686 NOTREACHED();
689 // The page is loaded in the renderer, wait for a new frame to arrive.
690 uint32 frame = rwhvp->RendererFrameNumber();
691 while (!GetRenderWidgetHost()->ScheduleComposite())
692 GiveItSomeTime();
693 while (rwhvp->RendererFrameNumber() == frame)
694 GiveItSomeTime();
696 SkBitmap expected_bitmap;
697 SetupLeftRightBitmap(expected_bitmap_size, &expected_bitmap);
698 SetExpectedCopyFromCompositingSurfaceResult(true, expected_bitmap);
700 base::RunLoop run_loop;
701 if (video_frame) {
702 // Allow pixel differences as long as we have the right idea.
703 SetAllowableError(0x10);
704 // Exclude the middle two columns which are blended between the two sides.
705 SetExcludeRect(
706 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
708 scoped_refptr<media::VideoFrame> video_frame =
709 media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
710 expected_bitmap_size,
711 gfx::Rect(expected_bitmap_size),
712 expected_bitmap_size,
713 base::TimeDelta());
715 base::Callback<void(bool success)> callback =
716 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
717 CopyFromCompositingSurfaceCallbackForVideo,
718 base::Unretained(this),
719 video_frame,
720 run_loop.QuitClosure());
721 rwhvp->CopyFromCompositingSurfaceToVideoFrame(copy_rect,
722 video_frame,
723 callback);
724 } else {
725 #if defined(USE_AURA)
726 if (!content::GpuDataManager::GetInstance()
727 ->CanUseGpuBrowserCompositor()) {
728 // Skia rendering can cause color differences, particularly in the
729 // middle two columns.
730 SetAllowableError(2);
731 SetExcludeRect(
732 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
734 #endif
736 base::Callback<void(bool, const SkBitmap&)> callback =
737 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
738 CopyFromCompositingSurfaceCallback,
739 base::Unretained(this),
740 run_loop.QuitClosure());
741 rwhvp->CopyFromCompositingSurface(copy_rect, output_size, callback);
743 run_loop.Run();
746 // Sets up |bitmap| to have size |copy_size|. It floods the left half with
747 // #0ff and the right half with #ff0.
748 void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) {
749 bitmap->setConfig(
750 SkBitmap::kARGB_8888_Config, copy_size.width(), copy_size.height());
751 bitmap->allocPixels();
752 // Left half is #0ff.
753 bitmap->eraseARGB(255, 0, 255, 255);
754 // Right half is #ff0.
756 SkAutoLockPixels lock(*bitmap);
757 for (int i = 0; i < copy_size.width() / 2; ++i) {
758 for (int j = 0; j < copy_size.height(); ++j) {
759 *(bitmap->getAddr32(copy_size.width() / 2 + i, j)) =
760 SkColorSetARGB(255, 255, 255, 0);
766 protected:
767 virtual bool ShouldContinueAfterTestURLLoad() {
768 return true;
771 private:
772 bool expected_copy_from_compositing_surface_result_;
773 SkBitmap expected_copy_from_compositing_surface_bitmap_;
774 int allowable_error_;
775 gfx::Rect exclude_rect_;
776 std::string test_url_;
779 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
780 CopyFromCompositingSurface_Origin_Unscaled) {
781 gfx::Rect copy_rect(400, 300);
782 gfx::Size output_size = copy_rect.size();
783 gfx::Size expected_bitmap_size = output_size;
784 gfx::Size html_rect_size(400, 300);
785 bool video_frame = false;
786 PerformTestWithLeftRightRects(html_rect_size,
787 copy_rect,
788 output_size,
789 expected_bitmap_size,
790 video_frame);
793 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
794 CopyFromCompositingSurface_Origin_Scaled) {
795 gfx::Rect copy_rect(400, 300);
796 gfx::Size output_size(200, 100);
797 gfx::Size expected_bitmap_size = output_size;
798 gfx::Size html_rect_size(400, 300);
799 bool video_frame = false;
800 PerformTestWithLeftRightRects(html_rect_size,
801 copy_rect,
802 output_size,
803 expected_bitmap_size,
804 video_frame);
807 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
808 CopyFromCompositingSurface_Cropped_Unscaled) {
809 // Grab 60x60 pixels from the center of the tab contents.
810 gfx::Rect copy_rect(400, 300);
811 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
812 gfx::Size(60, 60));
813 gfx::Size output_size = copy_rect.size();
814 gfx::Size expected_bitmap_size = output_size;
815 gfx::Size html_rect_size(400, 300);
816 bool video_frame = false;
817 PerformTestWithLeftRightRects(html_rect_size,
818 copy_rect,
819 output_size,
820 expected_bitmap_size,
821 video_frame);
824 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
825 CopyFromCompositingSurface_Cropped_Scaled) {
826 // Grab 60x60 pixels from the center of the tab contents.
827 gfx::Rect copy_rect(400, 300);
828 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
829 gfx::Size(60, 60));
830 gfx::Size output_size(20, 10);
831 gfx::Size expected_bitmap_size = output_size;
832 gfx::Size html_rect_size(400, 300);
833 bool video_frame = false;
834 PerformTestWithLeftRightRects(html_rect_size,
835 copy_rect,
836 output_size,
837 expected_bitmap_size,
838 video_frame);
841 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
842 CopyFromCompositingSurface_ForVideoFrame) {
843 // Grab 90x60 pixels from the center of the tab contents.
844 gfx::Rect copy_rect(400, 300);
845 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
846 gfx::Size(90, 60));
847 gfx::Size output_size = copy_rect.size();
848 gfx::Size expected_bitmap_size = output_size;
849 gfx::Size html_rect_size(400, 300);
850 bool video_frame = true;
851 PerformTestWithLeftRightRects(html_rect_size,
852 copy_rect,
853 output_size,
854 expected_bitmap_size,
855 video_frame);
858 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
859 CopyFromCompositingSurface_ForVideoFrame_Scaled) {
860 // Grab 90x60 pixels from the center of the tab contents.
861 gfx::Rect copy_rect(400, 300);
862 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
863 gfx::Size(90, 60));
864 // Scale to 30 x 20 (preserve aspect ratio).
865 gfx::Size output_size(30, 20);
866 gfx::Size expected_bitmap_size = output_size;
867 gfx::Size html_rect_size(400, 300);
868 bool video_frame = true;
869 PerformTestWithLeftRightRects(html_rect_size,
870 copy_rect,
871 output_size,
872 expected_bitmap_size,
873 video_frame);
876 class CompositingRenderWidgetHostViewTabCaptureHighDPI
877 : public CompositingRenderWidgetHostViewBrowserTestTabCapture {
878 public:
879 CompositingRenderWidgetHostViewTabCaptureHighDPI() : kScale(2.f) {}
881 virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
882 CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd);
883 cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
884 base::StringPrintf("%f", scale()));
885 #if defined(OS_WIN)
886 cmd->AppendSwitchASCII(switches::kHighDPISupport, "1");
887 gfx::EnableHighDPISupport();
888 #endif
891 float scale() const { return kScale; }
893 private:
894 virtual bool ShouldContinueAfterTestURLLoad() OVERRIDE {
895 PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(scale());
896 return true;
899 const float kScale;
901 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewTabCaptureHighDPI);
904 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
905 CopyFromCompositingSurface) {
906 gfx::Rect copy_rect(200, 150);
907 gfx::Size output_size = copy_rect.size();
908 gfx::Size expected_bitmap_size =
909 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
910 gfx::Size html_rect_size(200, 150);
911 bool video_frame = false;
912 PerformTestWithLeftRightRects(html_rect_size,
913 copy_rect,
914 output_size,
915 expected_bitmap_size,
916 video_frame);
919 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
920 CopyFromCompositingSurfaceVideoFrame) {
921 gfx::Size html_rect_size(200, 150);
922 // Grab 90x60 pixels from the center of the tab contents.
923 gfx::Rect copy_rect =
924 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
925 gfx::Size(90, 60));
926 gfx::Size output_size = copy_rect.size();
927 gfx::Size expected_bitmap_size =
928 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
929 bool video_frame = true;
930 PerformTestWithLeftRightRects(html_rect_size,
931 copy_rect,
932 output_size,
933 expected_bitmap_size,
934 video_frame);
937 #if !defined(USE_AURA) && !defined(OS_MACOSX)
938 // TODO(danakj): Remove this case when GTK linux is no more and move the
939 // values inline to testing::Values() below.
940 static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING};
941 #else
942 static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING,
943 SOFTWARE_COMPOSITING};
944 #endif
946 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
947 CompositingRenderWidgetHostViewBrowserTest,
948 testing::ValuesIn(kAllCompositingModes));
949 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
950 CompositingRenderWidgetHostViewBrowserTestTabCapture,
951 testing::ValuesIn(kAllCompositingModes));
952 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
953 CompositingRenderWidgetHostViewTabCaptureHighDPI,
954 testing::ValuesIn(kAllCompositingModes));
956 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
958 } // namespace
959 } // namespace content