Ensure that extension resources are loaded with the correct scaling applied on Windows.
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_browsertest.cc
blob65f65369091ca168d2798f909036e6e032572355
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/public/test/content_browser_test.h"
23 #include "content/public/test/content_browser_test_utils.h"
24 #include "content/shell/browser/shell.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/SkCanvas.h"
30 #include "ui/base/ui_base_switches.h"
31 #include "ui/gfx/size_conversions.h"
32 #include "ui/gfx/switches.h"
33 #include "ui/gl/gl_switches.h"
35 #if defined(OS_MACOSX)
36 #include "ui/gl/io_surface_support_mac.h"
37 #endif
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 // Convenience macro: Short-circuit a pass for platforms where setting up
58 // high-DPI fails.
59 #define PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(factor) \
60 if (ui::GetScaleForScaleFactor( \
61 GetScaleFactorForView(GetRenderWidgetHostViewPort())) != factor) { \
62 LOG(WARNING) << "Blindly passing this test: failed to set up " \
63 "scale factor: " << factor; \
64 return false; \
67 // Common base class for browser tests. This is subclassed twice: Once to test
68 // the browser in forced-compositing mode, and once to test with compositing
69 // mode disabled.
70 class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
71 public:
72 RenderWidgetHostViewBrowserTest()
73 : frame_size_(400, 300),
74 callback_invoke_count_(0),
75 frames_captured_(0) {}
77 virtual void SetUpOnMainThread() OVERRIDE {
78 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
81 // Attempts to set up the source surface. Returns false if unsupported on the
82 // current platform.
83 virtual bool SetUpSourceSurface(const char* wait_message) = 0;
85 int callback_invoke_count() const {
86 return callback_invoke_count_;
89 int frames_captured() const {
90 return frames_captured_;
93 const gfx::Size& frame_size() const {
94 return frame_size_;
97 const base::FilePath& test_dir() const {
98 return test_dir_;
101 RenderViewHost* GetRenderViewHost() const {
102 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
103 CHECK(rvh);
104 return rvh;
107 RenderWidgetHostImpl* GetRenderWidgetHost() const {
108 RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From(
109 shell()->web_contents()->GetRenderWidgetHostView()->
110 GetRenderWidgetHost());
111 CHECK(rwh);
112 return rwh;
115 RenderWidgetHostViewPort* GetRenderWidgetHostViewPort() const {
116 RenderWidgetHostViewPort* const view =
117 RenderWidgetHostViewPort::FromRWHV(GetRenderViewHost()->GetView());
118 CHECK(view);
119 return view;
122 // Callback when using CopyFromBackingStore() API.
123 void FinishCopyFromBackingStore(const base::Closure& quit_closure,
124 bool frame_captured,
125 const SkBitmap& bitmap) {
126 ++callback_invoke_count_;
127 if (frame_captured) {
128 ++frames_captured_;
129 EXPECT_FALSE(bitmap.empty());
131 if (!quit_closure.is_null())
132 quit_closure.Run();
135 // Callback when using CopyFromCompositingSurfaceToVideoFrame() API.
136 void FinishCopyFromCompositingSurface(const base::Closure& quit_closure,
137 bool frame_captured) {
138 ++callback_invoke_count_;
139 if (frame_captured)
140 ++frames_captured_;
141 if (!quit_closure.is_null())
142 quit_closure.Run();
145 // Callback when using frame subscriber API.
146 void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop,
147 base::Closure quit_closure,
148 base::TimeTicks timestamp,
149 bool frame_captured) {
150 ++callback_invoke_count_;
151 if (frame_captured)
152 ++frames_captured_;
153 if (!quit_closure.is_null())
154 loop->PostTask(FROM_HERE, quit_closure);
157 // Copy one frame using the CopyFromBackingStore API.
158 void RunBasicCopyFromBackingStoreTest() {
159 SET_UP_SURFACE_OR_PASS_TEST(NULL);
161 // Repeatedly call CopyFromBackingStore() since, on some platforms (e.g.,
162 // Windows), the operation will fail until the first "present" has been
163 // made.
164 int count_attempts = 0;
165 while (true) {
166 ++count_attempts;
167 base::RunLoop run_loop;
168 GetRenderViewHost()->CopyFromBackingStore(
169 gfx::Rect(),
170 frame_size(),
171 base::Bind(
172 &RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
173 base::Unretained(this),
174 run_loop.QuitClosure()),
175 SkBitmap::kARGB_8888_Config);
176 run_loop.Run();
178 if (frames_captured())
179 break;
180 else
181 GiveItSomeTime();
184 EXPECT_EQ(count_attempts, callback_invoke_count());
185 EXPECT_EQ(1, frames_captured());
188 protected:
189 // Waits until the source is available for copying.
190 void WaitForCopySourceReady() {
191 while (!GetRenderWidgetHostViewPort()->IsSurfaceAvailableForCopy())
192 GiveItSomeTime();
195 // Run the current message loop for a short time without unwinding the current
196 // call stack.
197 static void GiveItSomeTime() {
198 base::RunLoop run_loop;
199 base::MessageLoop::current()->PostDelayedTask(
200 FROM_HERE,
201 run_loop.QuitClosure(),
202 base::TimeDelta::FromMilliseconds(10));
203 run_loop.Run();
206 private:
207 const gfx::Size frame_size_;
208 base::FilePath test_dir_;
209 int callback_invoke_count_;
210 int frames_captured_;
213 enum CompositingMode {
214 GL_COMPOSITING,
215 SOFTWARE_COMPOSITING,
218 class CompositingRenderWidgetHostViewBrowserTest
219 : public RenderWidgetHostViewBrowserTest,
220 public testing::WithParamInterface<CompositingMode> {
221 public:
222 explicit CompositingRenderWidgetHostViewBrowserTest()
223 : compositing_mode_(GetParam()) {}
225 virtual void SetUp() OVERRIDE {
226 if (compositing_mode_ == SOFTWARE_COMPOSITING)
227 UseSoftwareCompositing();
228 RenderWidgetHostViewBrowserTest::SetUp();
231 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
232 // Note: Not appending kForceCompositingMode switch here, since not all bots
233 // support compositing. Some bots will run with compositing on, and others
234 // won't. Therefore, the call to SetUpSourceSurface() later on will detect
235 // whether compositing mode is actually on or not. If not, the tests will
236 // pass blindly, logging a warning message, since we cannot test what the
237 // platform/implementation does not support.
238 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line);
241 virtual GURL TestUrl() {
242 return net::FilePathToFileURL(
243 test_dir().AppendASCII("rwhv_compositing_animation.html"));
246 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE {
247 if (!IsForceCompositingModeEnabled())
248 return false; // See comment in SetUpCommandLine().
249 #if defined(OS_MACOSX)
250 CHECK(IOSurfaceSupport::Initialize());
251 #endif
253 content::DOMMessageQueue message_queue;
254 NavigateToURL(shell(), TestUrl());
255 if (wait_message != NULL) {
256 std::string result(wait_message);
257 if (!message_queue.WaitForMessage(&result)) {
258 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed.";
259 return false;
263 #if !defined(USE_AURA)
264 if (!GetRenderWidgetHost()->is_accelerated_compositing_active())
265 return false; // Renderer did not turn on accelerated compositing.
266 #endif
268 // Using accelerated compositing, but a compositing surface might not be
269 // available yet. So, wait for it.
270 WaitForCopySourceReady();
271 return true;
274 private:
275 const CompositingMode compositing_mode_;
277 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewBrowserTest);
280 class NonCompositingRenderWidgetHostViewBrowserTest
281 : public RenderWidgetHostViewBrowserTest {
282 public:
283 NonCompositingRenderWidgetHostViewBrowserTest() {}
285 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
286 // Note: Appending the kDisableAcceleratedCompositing switch here, but there
287 // are some builds that only use compositing and will ignore this switch.
288 // Therefore, the call to SetUpSourceSurface() later on will detect whether
289 // compositing mode is actually off. If it's on, the tests will pass
290 // blindly, logging a warning message, since we cannot test what the
291 // platform/implementation does not support.
292 command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
293 RenderWidgetHostViewBrowserTest::SetUpCommandLine(command_line);
296 virtual GURL TestUrl() {
297 return GURL(kAboutBlankURL);
300 virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE {
301 if (IsForceCompositingModeEnabled())
302 return false; // See comment in SetUpCommandLine().
304 content::DOMMessageQueue message_queue;
305 NavigateToURL(shell(), TestUrl());
306 if (wait_message != NULL) {
307 std::string result(wait_message);
308 if (!message_queue.WaitForMessage(&result)) {
309 EXPECT_TRUE(false) << "WaitForMessage " << result << " failed.";
310 return false;
314 WaitForCopySourceReady();
315 // Return whether the renderer left accelerated compositing turned off.
316 return !GetRenderWidgetHost()->is_accelerated_compositing_active();
319 private:
320 DISALLOW_COPY_AND_ASSIGN(NonCompositingRenderWidgetHostViewBrowserTest);
323 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
324 public:
325 FakeFrameSubscriber(
326 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback)
327 : callback_(callback) {
330 virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
331 scoped_refptr<media::VideoFrame>* storage,
332 DeliverFrameCallback* callback) OVERRIDE {
333 // Only allow one frame capture to be made. Otherwise, the compositor could
334 // start multiple captures, unbounded, and eventually its own limiter logic
335 // will begin invoking |callback| with a |false| result. This flakes out
336 // the unit tests, since they receive a "failed" callback before the later
337 // "success" callbacks.
338 if (callback_.is_null())
339 return false;
340 *storage = media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100));
341 *callback = callback_;
342 callback_.Reset();
343 return true;
346 private:
347 DeliverFrameCallback callback_;
350 // Disable tests for Android and IOS as these platforms have incomplete
351 // implementation.
352 #if !defined(OS_ANDROID) && !defined(OS_IOS)
354 // The CopyFromBackingStore() API should work on all platforms when compositing
355 // is enabled.
356 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
357 CopyFromBackingStore) {
358 RunBasicCopyFromBackingStoreTest();
361 // The CopyFromBackingStore() API should work on all platforms when compositing
362 // is disabled.
363 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest,
364 CopyFromBackingStore) {
365 RunBasicCopyFromBackingStoreTest();
368 // Tests that the callback passed to CopyFromBackingStore is always called,
369 // even when the RenderWidgetHost is deleting in the middle of an async copy.
370 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
371 CopyFromBackingStore_CallbackDespiteDelete) {
372 SET_UP_SURFACE_OR_PASS_TEST(NULL);
374 base::RunLoop run_loop;
375 GetRenderViewHost()->CopyFromBackingStore(
376 gfx::Rect(),
377 frame_size(),
378 base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
379 base::Unretained(this),
380 run_loop.QuitClosure()),
381 SkBitmap::kARGB_8888_Config);
382 // Delete the surface before the callback is run.
383 GetRenderWidgetHostViewPort()->AcceleratedSurfaceRelease();
384 run_loop.Run();
386 EXPECT_EQ(1, callback_invoke_count());
389 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
390 // always called, even when the RenderWidgetHost is deleting in the middle of
391 // an async copy.
393 // Test is flaky on Win. http://crbug.com/276783
394 #if defined(OS_WIN) || (defined(OS_CHROMEOS) && !defined(NDEBUG))
395 #define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
396 DISABLED_CopyFromCompositingSurface_CallbackDespiteDelete
397 #else
398 #define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
399 CopyFromCompositingSurface_CallbackDespiteDelete
400 #endif
401 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
402 MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete) {
403 SET_UP_SURFACE_OR_PASS_TEST(NULL);
404 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
405 if (!view->CanCopyToVideoFrame()) {
406 LOG(WARNING) <<
407 ("Blindly passing this test: CopyFromCompositingSurfaceToVideoFrame() "
408 "not supported on this platform.");
409 return;
412 base::RunLoop run_loop;
413 scoped_refptr<media::VideoFrame> dest =
414 media::VideoFrame::CreateBlackFrame(frame_size());
415 view->CopyFromCompositingSurfaceToVideoFrame(
416 gfx::Rect(view->GetViewBounds().size()), dest, base::Bind(
417 &RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface,
418 base::Unretained(this), run_loop.QuitClosure()));
419 // Delete the surface before the callback is run.
420 view->AcceleratedSurfaceRelease();
421 run_loop.Run();
423 EXPECT_EQ(1, callback_invoke_count());
426 // With compositing turned off, no platforms should support the
427 // CopyFromCompositingSurfaceToVideoFrame() API.
428 IN_PROC_BROWSER_TEST_F(NonCompositingRenderWidgetHostViewBrowserTest,
429 CopyFromCompositingSurfaceToVideoFrameCallbackTest) {
430 SET_UP_SURFACE_OR_PASS_TEST(NULL);
431 EXPECT_FALSE(GetRenderWidgetHostViewPort()->CanCopyToVideoFrame());
434 // Test basic frame subscription functionality. We subscribe, and then run
435 // until at least one DeliverFrameCallback has been invoked.
436 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
437 FrameSubscriberTest) {
438 SET_UP_SURFACE_OR_PASS_TEST(NULL);
439 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
440 if (!view->CanSubscribeFrame()) {
441 LOG(WARNING) << ("Blindly passing this test: Frame subscription not "
442 "supported on this platform.");
443 return;
446 base::RunLoop run_loop;
447 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
448 new FakeFrameSubscriber(
449 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
450 base::Unretained(this),
451 base::MessageLoopProxy::current(),
452 run_loop.QuitClosure())));
453 view->BeginFrameSubscription(subscriber.Pass());
454 run_loop.Run();
455 view->EndFrameSubscription();
457 EXPECT_LE(1, callback_invoke_count());
458 EXPECT_LE(1, frames_captured());
461 // Test that we can copy twice from an accelerated composited page.
462 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest, CopyTwice) {
463 SET_UP_SURFACE_OR_PASS_TEST(NULL);
464 RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
465 if (!view->CanCopyToVideoFrame()) {
466 LOG(WARNING) << ("Blindly passing this test: "
467 "CopyFromCompositingSurfaceToVideoFrame() not supported "
468 "on this platform.");
469 return;
472 base::RunLoop run_loop;
473 scoped_refptr<media::VideoFrame> first_output =
474 media::VideoFrame::CreateBlackFrame(frame_size());
475 ASSERT_TRUE(first_output.get());
476 scoped_refptr<media::VideoFrame> second_output =
477 media::VideoFrame::CreateBlackFrame(frame_size());
478 ASSERT_TRUE(second_output.get());
479 view->CopyFromCompositingSurfaceToVideoFrame(
480 gfx::Rect(view->GetViewBounds().size()),
481 first_output,
482 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
483 base::Unretained(this),
484 base::MessageLoopProxy::current(),
485 base::Closure(),
486 base::TimeTicks::Now()));
487 view->CopyFromCompositingSurfaceToVideoFrame(
488 gfx::Rect(view->GetViewBounds().size()),
489 second_output,
490 base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
491 base::Unretained(this),
492 base::MessageLoopProxy::current(),
493 run_loop.QuitClosure(),
494 base::TimeTicks::Now()));
495 run_loop.Run();
497 EXPECT_EQ(2, callback_invoke_count());
498 EXPECT_EQ(2, frames_captured());
501 class CompositingRenderWidgetHostViewBrowserTestTabCapture
502 : public CompositingRenderWidgetHostViewBrowserTest {
503 public:
504 CompositingRenderWidgetHostViewBrowserTestTabCapture()
505 : expected_copy_from_compositing_surface_result_(false),
506 allowable_error_(0),
507 test_url_("data:text/html,<!doctype html>") {}
509 virtual void SetUp() OVERRIDE {
510 EnablePixelOutput();
511 CompositingRenderWidgetHostViewBrowserTest::SetUp();
514 void CopyFromCompositingSurfaceCallback(base::Closure quit_callback,
515 bool result,
516 const SkBitmap& bitmap) {
517 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
518 if (!result) {
519 quit_callback.Run();
520 return;
523 const SkBitmap& expected_bitmap =
524 expected_copy_from_compositing_surface_bitmap_;
525 EXPECT_EQ(expected_bitmap.width(), bitmap.width());
526 EXPECT_EQ(expected_bitmap.height(), bitmap.height());
527 EXPECT_EQ(expected_bitmap.config(), bitmap.config());
528 SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
529 SkAutoLockPixels bitmap_lock(bitmap);
530 int fails = 0;
531 for (int i = 0; i < bitmap.width() && fails < 10; ++i) {
532 for (int j = 0; j < bitmap.height() && fails < 10; ++j) {
533 if (!exclude_rect_.IsEmpty() && exclude_rect_.Contains(i, j))
534 continue;
536 SkColor expected_color = expected_bitmap.getColor(i, j);
537 SkColor color = bitmap.getColor(i, j);
538 int expected_alpha = SkColorGetA(expected_color);
539 int alpha = SkColorGetA(color);
540 int expected_red = SkColorGetR(expected_color);
541 int red = SkColorGetR(color);
542 int expected_green = SkColorGetG(expected_color);
543 int green = SkColorGetG(color);
544 int expected_blue = SkColorGetB(expected_color);
545 int blue = SkColorGetB(color);
546 EXPECT_NEAR(expected_alpha, alpha, allowable_error_)
547 << "expected_color: " << std::hex << expected_color
548 << " color: " << color
549 << " Failed at " << std::dec << i << ", " << j
550 << " Failure " << ++fails;
551 EXPECT_NEAR(expected_red, red, 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_green, green, 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_blue, blue, allowable_error_)
562 << "expected_color: " << std::hex << expected_color
563 << " color: " << color
564 << " Failed at " << std::dec << i << ", " << j
565 << " Failure " << ++fails;
568 EXPECT_LT(fails, 10);
570 quit_callback.Run();
573 void CopyFromCompositingSurfaceCallbackForVideo(
574 scoped_refptr<media::VideoFrame> video_frame,
575 base::Closure quit_callback,
576 bool result) {
577 EXPECT_EQ(expected_copy_from_compositing_surface_result_, result);
578 if (!result) {
579 quit_callback.Run();
580 return;
583 media::SkCanvasVideoRenderer video_renderer;
585 SkBitmap bitmap;
586 bitmap.allocPixels(SkImageInfo::Make(video_frame->visible_rect().width(),
587 video_frame->visible_rect().height(),
588 kPMColor_SkColorType,
589 kOpaque_SkAlphaType));
590 bitmap.allocPixels();
591 SkCanvas canvas(bitmap);
593 video_renderer.Paint(video_frame.get(),
594 &canvas,
595 video_frame->visible_rect(),
596 0xff);
598 CopyFromCompositingSurfaceCallback(quit_callback,
599 result,
600 bitmap);
603 void SetExpectedCopyFromCompositingSurfaceResult(bool result,
604 const SkBitmap& bitmap) {
605 expected_copy_from_compositing_surface_result_ = result;
606 expected_copy_from_compositing_surface_bitmap_ = bitmap;
609 void SetAllowableError(int amount) { allowable_error_ = amount; }
610 void SetExcludeRect(gfx::Rect exclude) { exclude_rect_ = exclude; }
612 virtual GURL TestUrl() OVERRIDE {
613 return GURL(test_url_);
616 void SetTestUrl(std::string url) { test_url_ = url; }
618 // Loads a page two boxes side-by-side, each half the width of
619 // |html_rect_size|, and with different background colors. The test then
620 // copies from |copy_rect| region of the page into a bitmap of size
621 // |output_size|, and compares that with a bitmap of size
622 // |expected_bitmap_size|.
623 // Note that |output_size| may not have the same size as |copy_rect| (e.g.
624 // when the output is scaled). Also note that |expected_bitmap_size| may not
625 // be the same as |output_size| (e.g. when the device scale factor is not 1).
626 void PerformTestWithLeftRightRects(const gfx::Size& html_rect_size,
627 const gfx::Rect& copy_rect,
628 const gfx::Size& output_size,
629 const gfx::Size& expected_bitmap_size,
630 bool video_frame) {
631 const gfx::Size box_size(html_rect_size.width() / 2,
632 html_rect_size.height());
633 SetTestUrl(base::StringPrintf(
634 "data:text/html,<!doctype html>"
635 "<div class='left'>"
636 " <div class='right'></div>"
637 "</div>"
638 "<style>"
639 "body { padding: 0; margin: 0; }"
640 ".left { position: absolute;"
641 " background: #0ff;"
642 " width: %dpx;"
643 " height: %dpx;"
645 ".right { position: absolute;"
646 " left: %dpx;"
647 " background: #ff0;"
648 " width: %dpx;"
649 " height: %dpx;"
651 "</style>"
652 "<script>"
653 " domAutomationController.setAutomationId(0);"
654 " domAutomationController.send(\"DONE\");"
655 "</script>",
656 box_size.width(),
657 box_size.height(),
658 box_size.width(),
659 box_size.width(),
660 box_size.height()));
662 SET_UP_SURFACE_OR_PASS_TEST("\"DONE\"");
663 if (!ShouldContinueAfterTestURLLoad())
664 return;
666 RenderWidgetHostViewPort* rwhvp = GetRenderWidgetHostViewPort();
667 if (video_frame && !rwhvp->CanCopyToVideoFrame()) {
668 // This should only happen on Mac when using the software compositor.
669 // Otherwise, raise an error. This can be removed when Mac is moved to a
670 // browser compositor.
671 // http://crbug.com/314190
672 #if defined(OS_MACOSX)
673 if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) {
674 LOG(WARNING) << ("Blindly passing this test because copying to "
675 "video frames is not supported on this platform.");
676 return;
678 #endif
679 NOTREACHED();
682 // The page is loaded in the renderer, wait for a new frame to arrive.
683 uint32 frame = rwhvp->RendererFrameNumber();
684 while (!GetRenderWidgetHost()->ScheduleComposite())
685 GiveItSomeTime();
686 while (rwhvp->RendererFrameNumber() == frame)
687 GiveItSomeTime();
689 SkBitmap expected_bitmap;
690 SetupLeftRightBitmap(expected_bitmap_size, &expected_bitmap);
691 SetExpectedCopyFromCompositingSurfaceResult(true, expected_bitmap);
693 base::RunLoop run_loop;
694 if (video_frame) {
695 // Allow pixel differences as long as we have the right idea.
696 SetAllowableError(0x10);
697 // Exclude the middle two columns which are blended between the two sides.
698 SetExcludeRect(
699 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
701 scoped_refptr<media::VideoFrame> video_frame =
702 media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
703 expected_bitmap_size,
704 gfx::Rect(expected_bitmap_size),
705 expected_bitmap_size,
706 base::TimeDelta());
708 base::Callback<void(bool success)> callback =
709 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
710 CopyFromCompositingSurfaceCallbackForVideo,
711 base::Unretained(this),
712 video_frame,
713 run_loop.QuitClosure());
714 rwhvp->CopyFromCompositingSurfaceToVideoFrame(copy_rect,
715 video_frame,
716 callback);
717 } else {
718 #if defined(USE_AURA)
719 if (!content::GpuDataManager::GetInstance()
720 ->CanUseGpuBrowserCompositor()) {
721 // Skia rendering can cause color differences, particularly in the
722 // middle two columns.
723 SetAllowableError(2);
724 SetExcludeRect(
725 gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
727 #endif
729 base::Callback<void(bool, const SkBitmap&)> callback =
730 base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
731 CopyFromCompositingSurfaceCallback,
732 base::Unretained(this),
733 run_loop.QuitClosure());
734 rwhvp->CopyFromCompositingSurface(copy_rect,
735 output_size,
736 callback,
737 SkBitmap::kARGB_8888_Config);
739 run_loop.Run();
742 // Sets up |bitmap| to have size |copy_size|. It floods the left half with
743 // #0ff and the right half with #ff0.
744 void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) {
745 bitmap->setConfig(
746 SkBitmap::kARGB_8888_Config, copy_size.width(), copy_size.height());
747 bitmap->allocPixels();
748 // Left half is #0ff.
749 bitmap->eraseARGB(255, 0, 255, 255);
750 // Right half is #ff0.
752 SkAutoLockPixels lock(*bitmap);
753 for (int i = 0; i < copy_size.width() / 2; ++i) {
754 for (int j = 0; j < copy_size.height(); ++j) {
755 *(bitmap->getAddr32(copy_size.width() / 2 + i, j)) =
756 SkColorSetARGB(255, 255, 255, 0);
762 protected:
763 virtual bool ShouldContinueAfterTestURLLoad() {
764 return true;
767 private:
768 bool expected_copy_from_compositing_surface_result_;
769 SkBitmap expected_copy_from_compositing_surface_bitmap_;
770 int allowable_error_;
771 gfx::Rect exclude_rect_;
772 std::string test_url_;
775 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
776 CopyFromCompositingSurface_Origin_Unscaled) {
777 gfx::Rect copy_rect(400, 300);
778 gfx::Size output_size = copy_rect.size();
779 gfx::Size expected_bitmap_size = output_size;
780 gfx::Size html_rect_size(400, 300);
781 bool video_frame = false;
782 PerformTestWithLeftRightRects(html_rect_size,
783 copy_rect,
784 output_size,
785 expected_bitmap_size,
786 video_frame);
789 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
790 CopyFromCompositingSurface_Origin_Scaled) {
791 gfx::Rect copy_rect(400, 300);
792 gfx::Size output_size(200, 100);
793 gfx::Size expected_bitmap_size = output_size;
794 gfx::Size html_rect_size(400, 300);
795 bool video_frame = false;
796 PerformTestWithLeftRightRects(html_rect_size,
797 copy_rect,
798 output_size,
799 expected_bitmap_size,
800 video_frame);
803 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
804 CopyFromCompositingSurface_Cropped_Unscaled) {
805 // Grab 60x60 pixels from the center of the tab contents.
806 gfx::Rect copy_rect(400, 300);
807 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
808 gfx::Size(60, 60));
809 gfx::Size output_size = copy_rect.size();
810 gfx::Size expected_bitmap_size = output_size;
811 gfx::Size html_rect_size(400, 300);
812 bool video_frame = false;
813 PerformTestWithLeftRightRects(html_rect_size,
814 copy_rect,
815 output_size,
816 expected_bitmap_size,
817 video_frame);
820 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
821 CopyFromCompositingSurface_Cropped_Scaled) {
822 // Grab 60x60 pixels from the center of the tab contents.
823 gfx::Rect copy_rect(400, 300);
824 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
825 gfx::Size(60, 60));
826 gfx::Size output_size(20, 10);
827 gfx::Size expected_bitmap_size = output_size;
828 gfx::Size html_rect_size(400, 300);
829 bool video_frame = false;
830 PerformTestWithLeftRightRects(html_rect_size,
831 copy_rect,
832 output_size,
833 expected_bitmap_size,
834 video_frame);
837 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
838 CopyFromCompositingSurface_ForVideoFrame) {
839 // Grab 90x60 pixels from the center of the tab contents.
840 gfx::Rect copy_rect(400, 300);
841 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
842 gfx::Size(90, 60));
843 gfx::Size output_size = copy_rect.size();
844 gfx::Size expected_bitmap_size = output_size;
845 gfx::Size html_rect_size(400, 300);
846 bool video_frame = true;
847 PerformTestWithLeftRightRects(html_rect_size,
848 copy_rect,
849 output_size,
850 expected_bitmap_size,
851 video_frame);
854 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
855 CopyFromCompositingSurface_ForVideoFrame_Scaled) {
856 // Grab 90x60 pixels from the center of the tab contents.
857 gfx::Rect copy_rect(400, 300);
858 copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
859 gfx::Size(90, 60));
860 // Scale to 30 x 20 (preserve aspect ratio).
861 gfx::Size output_size(30, 20);
862 gfx::Size expected_bitmap_size = output_size;
863 gfx::Size html_rect_size(400, 300);
864 bool video_frame = true;
865 PerformTestWithLeftRightRects(html_rect_size,
866 copy_rect,
867 output_size,
868 expected_bitmap_size,
869 video_frame);
872 class CompositingRenderWidgetHostViewTabCaptureHighDPI
873 : public CompositingRenderWidgetHostViewBrowserTestTabCapture {
874 public:
875 CompositingRenderWidgetHostViewTabCaptureHighDPI() : kScale(2.f) {}
877 virtual void SetUpOnMainThread() OVERRIDE {
878 CommandLine* cmd = CommandLine::ForCurrentProcess();
879 cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
880 base::StringPrintf("%f", scale()));
881 #if defined(OS_WIN)
882 gfx::ForceHighDPISupportForTesting(scale());
883 gfx::EnableHighDPISupport();
884 #endif
887 float scale() const { return kScale; }
889 private:
890 virtual bool ShouldContinueAfterTestURLLoad() OVERRIDE {
891 PASS_TEST_IF_SCALE_FACTOR_NOT_SUPPORTED(scale());
892 return true;
895 const float kScale;
897 DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewTabCaptureHighDPI);
900 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
901 CopyFromCompositingSurface) {
902 gfx::Rect copy_rect(200, 150);
903 gfx::Size output_size = copy_rect.size();
904 gfx::Size expected_bitmap_size =
905 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
906 gfx::Size html_rect_size(200, 150);
907 bool video_frame = false;
908 PerformTestWithLeftRightRects(html_rect_size,
909 copy_rect,
910 output_size,
911 expected_bitmap_size,
912 video_frame);
915 IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
916 CopyFromCompositingSurfaceVideoFrame) {
917 gfx::Size html_rect_size(200, 150);
918 // Grab 90x60 pixels from the center of the tab contents.
919 gfx::Rect copy_rect =
920 gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
921 gfx::Size(90, 60));
922 gfx::Size output_size = copy_rect.size();
923 gfx::Size expected_bitmap_size =
924 gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
925 bool video_frame = true;
926 PerformTestWithLeftRightRects(html_rect_size,
927 copy_rect,
928 output_size,
929 expected_bitmap_size,
930 video_frame);
933 #if !defined(USE_AURA) && !defined(OS_MACOSX)
934 // TODO(danakj): Remove this case when GTK linux is no more and move the
935 // values inline to testing::Values() below.
936 static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING};
937 #else
938 static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING,
939 SOFTWARE_COMPOSITING};
940 #endif
942 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
943 CompositingRenderWidgetHostViewBrowserTest,
944 testing::ValuesIn(kAllCompositingModes));
945 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
946 CompositingRenderWidgetHostViewBrowserTestTabCapture,
947 testing::ValuesIn(kAllCompositingModes));
948 INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
949 CompositingRenderWidgetHostViewTabCaptureHighDPI,
950 testing::ValuesIn(kAllCompositingModes));
952 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
954 } // namespace
955 } // namespace content